Bug 1949027 - remove support for legacy CRLite filter format. r=keeler
Differential Revision: https://phabricator.services.mozilla.com/D238680
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -751,7 +751,6 @@ dependencies = [
|
|||||||
"nserror",
|
"nserror",
|
||||||
"nsstring",
|
"nsstring",
|
||||||
"rkv",
|
"rkv",
|
||||||
"rust_cascade",
|
|
||||||
"sha2",
|
"sha2",
|
||||||
"static_prefs",
|
"static_prefs",
|
||||||
"storage_variant",
|
"storage_variant",
|
||||||
|
|||||||
@@ -702,34 +702,7 @@ Result BuildCRLiteTimestampArray(
|
|||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result NSSCertDBTrustDomain::CheckCRLiteStash(
|
|
||||||
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
|
|
||||||
const nsTArray<uint8_t>& serialNumberBytes) {
|
|
||||||
// This information is deterministic and has already been validated by our
|
|
||||||
// infrastructure (it comes from signed CRLs), so if the stash says a
|
|
||||||
// certificate is revoked, it is.
|
|
||||||
bool isRevokedByStash = false;
|
|
||||||
nsresult rv = mCertStorage->IsCertRevokedByStash(
|
|
||||||
issuerSubjectPublicKeyInfoBytes, serialNumberBytes, &isRevokedByStash);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
|
||||||
("NSSCertDBTrustDomain::CheckCRLiteStash: IsCertRevokedByStash "
|
|
||||||
"failed"));
|
|
||||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
|
||||||
}
|
|
||||||
if (isRevokedByStash) {
|
|
||||||
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
|
||||||
("NSSCertDBTrustDomain::CheckCRLiteStash: IsCertRevokedByStash "
|
|
||||||
"returned true"));
|
|
||||||
mozilla::glean::cert_verifier::crlite_status.Get("revoked_in_stash"_ns)
|
|
||||||
.Add(1);
|
|
||||||
return Result::ERROR_REVOKED_CERTIFICATE;
|
|
||||||
}
|
|
||||||
return Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result NSSCertDBTrustDomain::CheckCRLite(
|
Result NSSCertDBTrustDomain::CheckCRLite(
|
||||||
const nsTArray<uint8_t>& issuerBytes,
|
|
||||||
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
|
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
|
||||||
const nsTArray<uint8_t>& serialNumberBytes,
|
const nsTArray<uint8_t>& serialNumberBytes,
|
||||||
const nsTArray<RefPtr<nsICRLiteTimestamp>>& timestamps,
|
const nsTArray<RefPtr<nsICRLiteTimestamp>>& timestamps,
|
||||||
@@ -737,8 +710,8 @@ Result NSSCertDBTrustDomain::CheckCRLite(
|
|||||||
filterCoversCertificate = false;
|
filterCoversCertificate = false;
|
||||||
int16_t crliteRevocationState;
|
int16_t crliteRevocationState;
|
||||||
nsresult rv = mCertStorage->GetCRLiteRevocationState(
|
nsresult rv = mCertStorage->GetCRLiteRevocationState(
|
||||||
issuerBytes, issuerSubjectPublicKeyInfoBytes, serialNumberBytes,
|
issuerSubjectPublicKeyInfoBytes, serialNumberBytes, timestamps,
|
||||||
timestamps, &crliteRevocationState);
|
&crliteRevocationState);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
||||||
("NSSCertDBTrustDomain::CheckCRLite: CRLite call failed"));
|
("NSSCertDBTrustDomain::CheckCRLite: CRLite call failed"));
|
||||||
@@ -885,29 +858,17 @@ Result NSSCertDBTrustDomain::CheckRevocationByCRLite(
|
|||||||
nsTArray<uint8_t> serialNumberBytes;
|
nsTArray<uint8_t> serialNumberBytes;
|
||||||
serialNumberBytes.AppendElements(certID.serialNumber.UnsafeGetData(),
|
serialNumberBytes.AppendElements(certID.serialNumber.UnsafeGetData(),
|
||||||
certID.serialNumber.GetLength());
|
certID.serialNumber.GetLength());
|
||||||
// The CRLite stash is essentially a subset of a collection of CRLs, so if
|
|
||||||
// it says a certificate is revoked, it is.
|
|
||||||
Result rv =
|
|
||||||
CheckCRLiteStash(issuerSubjectPublicKeyInfoBytes, serialNumberBytes);
|
|
||||||
if (rv != Success) {
|
|
||||||
crliteCoversCertificate = (rv == Result::ERROR_REVOKED_CERTIFICATE);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsTArray<uint8_t> issuerBytes;
|
|
||||||
issuerBytes.AppendElements(certID.issuer.UnsafeGetData(),
|
|
||||||
certID.issuer.GetLength());
|
|
||||||
|
|
||||||
nsTArray<RefPtr<nsICRLiteTimestamp>> timestamps;
|
nsTArray<RefPtr<nsICRLiteTimestamp>> timestamps;
|
||||||
rv = BuildCRLiteTimestampArray(sctExtension, timestamps);
|
Result rv = BuildCRLiteTimestampArray(sctExtension, timestamps);
|
||||||
if (rv != Success) {
|
if (rv != Success) {
|
||||||
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
|
||||||
("decoding SCT extension failed - CRLite will be not be "
|
("decoding SCT extension failed - CRLite will be not be "
|
||||||
"consulted"));
|
"consulted"));
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
return CheckCRLite(issuerBytes, issuerSubjectPublicKeyInfoBytes,
|
return CheckCRLite(issuerSubjectPublicKeyInfoBytes, serialNumberBytes,
|
||||||
serialNumberBytes, timestamps, crliteCoversCertificate);
|
timestamps, crliteCoversCertificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result NSSCertDBTrustDomain::CheckRevocationByOCSP(
|
Result NSSCertDBTrustDomain::CheckRevocationByOCSP(
|
||||||
|
|||||||
@@ -248,11 +248,7 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain {
|
|||||||
IssuerSources GetIssuerSources() { return mIssuerSources; }
|
IssuerSources GetIssuerSources() { return mIssuerSources; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result CheckCRLiteStash(
|
|
||||||
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
|
|
||||||
const nsTArray<uint8_t>& serialNumberBytes);
|
|
||||||
Result CheckCRLite(
|
Result CheckCRLite(
|
||||||
const nsTArray<uint8_t>& issuerBytes,
|
|
||||||
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
|
const nsTArray<uint8_t>& issuerSubjectPublicKeyInfoBytes,
|
||||||
const nsTArray<uint8_t>& serialNumberBytes,
|
const nsTArray<uint8_t>& serialNumberBytes,
|
||||||
const nsTArray<RefPtr<nsICRLiteTimestamp>>& crliteTimestamps,
|
const nsTArray<RefPtr<nsICRLiteTimestamp>>& crliteTimestamps,
|
||||||
|
|||||||
@@ -57,17 +57,6 @@ function bytesToString(bytes) {
|
|||||||
return String.fromCharCode.apply(null, bytes);
|
return String.fromCharCode.apply(null, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
class CRLiteCoverage {
|
|
||||||
constructor(b64LogID, minTimestamp, maxTimestamp) {
|
|
||||||
this.b64LogID = b64LogID;
|
|
||||||
this.minTimestamp = minTimestamp;
|
|
||||||
this.maxTimestamp = maxTimestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CRLiteCoverage.prototype.QueryInterface = ChromeUtils.generateQI([
|
|
||||||
"nsICRLiteCoverage",
|
|
||||||
]);
|
|
||||||
|
|
||||||
class CertInfo {
|
class CertInfo {
|
||||||
constructor(cert, subject) {
|
constructor(cert, subject) {
|
||||||
this.cert = cert;
|
this.cert = cert;
|
||||||
@@ -124,9 +113,9 @@ function hasPriorData(dataType) {
|
|||||||
Ci.nsICertStorage
|
Ci.nsICertStorage
|
||||||
);
|
);
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
certStorage.hasPriorData(dataType, (rv, hasPriorData) => {
|
certStorage.hasPriorData(dataType, (rv, out) => {
|
||||||
if (rv == Cr.NS_OK) {
|
if (rv == Cr.NS_OK) {
|
||||||
resolve(hasPriorData);
|
resolve(out);
|
||||||
} else {
|
} else {
|
||||||
// If calling hasPriorData failed, assume we need to reload everything
|
// If calling hasPriorData failed, assume we need to reload everything
|
||||||
// (even though it's unlikely doing so will succeed).
|
// (even though it's unlikely doing so will succeed).
|
||||||
@@ -570,10 +559,10 @@ class CRLiteFilters {
|
|||||||
toReset.map(r => ({ ...r, loaded_into_cert_storage: false }))
|
toReset.map(r => ({ ...r, loaded_into_cert_storage: false }))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let hasPriorStash = await hasPriorData(
|
let hasPriorDelta = await hasPriorData(
|
||||||
Ci.nsICertStorage.DATA_TYPE_CRLITE_FILTER_INCREMENTAL
|
Ci.nsICertStorage.DATA_TYPE_CRLITE_FILTER_INCREMENTAL
|
||||||
);
|
);
|
||||||
if (!hasPriorStash) {
|
if (!hasPriorDelta) {
|
||||||
let current = await this.getFilteredRecords();
|
let current = await this.getFilteredRecords();
|
||||||
let toReset = current.filter(
|
let toReset = current.filter(
|
||||||
record => record.incremental && record.loaded_into_cert_storage
|
record => record.incremental && record.loaded_into_cert_storage
|
||||||
@@ -651,56 +640,14 @@ class CRLiteFilters {
|
|||||||
}
|
}
|
||||||
let filter = fullFiltersDownloaded[0];
|
let filter = fullFiltersDownloaded[0];
|
||||||
|
|
||||||
let coverage = [];
|
|
||||||
if (filter.coverage) {
|
|
||||||
for (let entry of filter.coverage) {
|
|
||||||
coverage.push(
|
|
||||||
new CRLiteCoverage(
|
|
||||||
entry.logID,
|
|
||||||
entry.minTimestamp,
|
|
||||||
entry.maxTimestamp
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let enrollment = filter.enrolledIssuers ? filter.enrolledIssuers : [];
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
certList.setFullCRLiteFilter(filter.bytes, enrollment, coverage, rv => {
|
certList.setFullCRLiteFilter(filter.bytes, rv => {
|
||||||
lazy.log.debug(`setFullCRLiteFilter: ${rv}`);
|
lazy.log.debug(`setFullCRLiteFilter: ${rv}`);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let stashes = filtersDownloaded.filter(
|
let deltas = filtersDownloaded.filter(filter => filter.incremental);
|
||||||
filter =>
|
|
||||||
filter.incremental && filter.attachment.filename.endsWith("stash")
|
|
||||||
);
|
|
||||||
let totalLength = stashes.reduce(
|
|
||||||
(sum, filter) => sum + filter.bytes.length,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
let concatenatedStashes = new Uint8Array(totalLength);
|
|
||||||
let offset = 0;
|
|
||||||
for (let filter of stashes) {
|
|
||||||
concatenatedStashes.set(filter.bytes, offset);
|
|
||||||
offset += filter.bytes.length;
|
|
||||||
}
|
|
||||||
if (concatenatedStashes.length) {
|
|
||||||
lazy.log.debug(
|
|
||||||
`adding concatenated incremental updates of total length ${concatenatedStashes.length}`
|
|
||||||
);
|
|
||||||
await new Promise(resolve => {
|
|
||||||
certList.addCRLiteStash(concatenatedStashes, rv => {
|
|
||||||
lazy.log.debug(`addCRLiteStash: ${rv}`);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let deltas = filtersDownloaded.filter(
|
|
||||||
filter =>
|
|
||||||
filter.incremental && filter.attachment.filename.endsWith("delta")
|
|
||||||
);
|
|
||||||
for (let filter of deltas) {
|
for (let filter of deltas) {
|
||||||
lazy.log.debug(`adding delta update of size ${filter.bytes.length}`);
|
lazy.log.debug(`adding delta update of size ${filter.bytes.length}`);
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ moz_task = { path = "../../../../xpcom/rust/moz_task" }
|
|||||||
nserror = { path = "../../../../xpcom/rust/nserror" }
|
nserror = { path = "../../../../xpcom/rust/nserror" }
|
||||||
nsstring = { path = "../../../../xpcom/rust/nsstring" }
|
nsstring = { path = "../../../../xpcom/rust/nsstring" }
|
||||||
rkv = { version = "0.19", default-features = false }
|
rkv = { version = "0.19", default-features = false }
|
||||||
rust_cascade = "1.4.0"
|
|
||||||
sha2 = "0.10.2"
|
sha2 = "0.10.2"
|
||||||
static_prefs = { path = "../../../../modules/libpref/init/static_prefs" }
|
static_prefs = { path = "../../../../modules/libpref/init/static_prefs" }
|
||||||
storage_variant = { path = "../../../../storage/variant" }
|
storage_variant = { path = "../../../../storage/variant" }
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ extern crate moz_task;
|
|||||||
extern crate nserror;
|
extern crate nserror;
|
||||||
extern crate nsstring;
|
extern crate nsstring;
|
||||||
extern crate rkv;
|
extern crate rkv;
|
||||||
extern crate rust_cascade;
|
|
||||||
extern crate sha2;
|
extern crate sha2;
|
||||||
extern crate thin_vec;
|
extern crate thin_vec;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
@@ -29,7 +28,7 @@ extern crate wr_malloc_size_of;
|
|||||||
use wr_malloc_size_of as malloc_size_of;
|
use wr_malloc_size_of as malloc_size_of;
|
||||||
|
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
use byteorder::{LittleEndian, NetworkEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use clubcard::{ApproximateSizeOf, Queryable};
|
use clubcard::{ApproximateSizeOf, Queryable};
|
||||||
use clubcard_crlite::{CRLiteClubcard, CRLiteKey, CRLiteQuery, CRLiteStatus};
|
use clubcard_crlite::{CRLiteClubcard, CRLiteKey, CRLiteQuery, CRLiteStatus};
|
||||||
use crossbeam_utils::atomic::AtomicCell;
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
@@ -42,14 +41,12 @@ use nserror::{
|
|||||||
use nsstring::{nsACString, nsCStr, nsCString, nsString};
|
use nsstring::{nsACString, nsCStr, nsCString, nsString};
|
||||||
use rkv::backend::{BackendEnvironmentBuilder, SafeMode, SafeModeDatabase, SafeModeEnvironment};
|
use rkv::backend::{BackendEnvironmentBuilder, SafeMode, SafeModeDatabase, SafeModeEnvironment};
|
||||||
use rkv::{StoreError, StoreOptions, Value};
|
use rkv::{StoreError, StoreOptions, Value};
|
||||||
use rust_cascade::Cascade;
|
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ffi::{CString, OsString};
|
use std::ffi::{CString, OsString};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::fs::{create_dir_all, remove_file, File, OpenOptions};
|
use std::fs::{create_dir_all, remove_file, File};
|
||||||
use std::io::{BufRead, BufReader, Read, Write};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str;
|
use std::str;
|
||||||
@@ -58,8 +55,8 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
|||||||
use storage_variant::VariantType;
|
use storage_variant::VariantType;
|
||||||
use thin_vec::ThinVec;
|
use thin_vec::ThinVec;
|
||||||
use xpcom::interfaces::{
|
use xpcom::interfaces::{
|
||||||
nsICRLiteCoverage, nsICRLiteTimestamp, nsICertInfo, nsICertStorage, nsICertStorageCallback,
|
nsICRLiteTimestamp, nsICertInfo, nsICertStorage, nsICertStorageCallback, nsIFile,
|
||||||
nsIFile, nsIHandleReportCallback, nsIIssuerAndSerialRevocationState, nsIMemoryReporter,
|
nsIHandleReportCallback, nsIIssuerAndSerialRevocationState, nsIMemoryReporter,
|
||||||
nsIMemoryReporterManager, nsIProperties, nsIRevocationState, nsISerialEventTarget,
|
nsIMemoryReporterManager, nsIProperties, nsIRevocationState, nsISerialEventTarget,
|
||||||
nsISubjectAndPubKeyRevocationState, nsISupports,
|
nsISubjectAndPubKeyRevocationState, nsISupports,
|
||||||
};
|
};
|
||||||
@@ -73,12 +70,6 @@ const PREFIX_DATA_TYPE: &str = "datatype";
|
|||||||
|
|
||||||
const LAST_CRLITE_UPDATE_KEY: &str = "last_crlite_update";
|
const LAST_CRLITE_UPDATE_KEY: &str = "last_crlite_update";
|
||||||
|
|
||||||
const COVERAGE_SERIALIZATION_VERSION: u8 = 1;
|
|
||||||
const COVERAGE_V1_ENTRY_BYTES: usize = 48;
|
|
||||||
|
|
||||||
const ENROLLMENT_SERIALIZATION_VERSION: u8 = 1;
|
|
||||||
const ENROLLMENT_V1_ENTRY_BYTES: usize = 32;
|
|
||||||
|
|
||||||
type Rkv = rkv::Rkv<SafeModeEnvironment>;
|
type Rkv = rkv::Rkv<SafeModeEnvironment>;
|
||||||
type SingleStore = rkv::SingleStore<SafeModeDatabase>;
|
type SingleStore = rkv::SingleStore<SafeModeDatabase>;
|
||||||
|
|
||||||
@@ -133,134 +124,7 @@ impl MallocSizeOf for EnvAndStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CascadeWithMetadata {
|
|
||||||
cascade: Cascade,
|
|
||||||
/// Maps an RFC 6962 LogID to a pair of 64 bit unix timestamps
|
|
||||||
coverage: HashMap<Vec<u8>, (u64, u64)>,
|
|
||||||
/// Set of `SHA256(subject || spki)` values for enrolled issuers
|
|
||||||
enrollment: HashSet<Vec<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CascadeWithMetadata {
|
|
||||||
fn new(
|
|
||||||
cascade: Cascade,
|
|
||||||
coverage_path: &PathBuf,
|
|
||||||
enrollment_path: &PathBuf,
|
|
||||||
) -> Result<Self, SecurityStateError> {
|
|
||||||
if !coverage_path.exists() {
|
|
||||||
return Err(SecurityStateError::from("missing coverage file"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !enrollment_path.exists() {
|
|
||||||
return Err(SecurityStateError::from("missing enrollment file"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize the coverage metadata.
|
|
||||||
// The format is described in `set_full_crlite_filter`.
|
|
||||||
let coverage_file = File::open(coverage_path)?;
|
|
||||||
let coverage_file_len = coverage_file.metadata()?.len() as usize;
|
|
||||||
let mut coverage_reader = BufReader::new(coverage_file);
|
|
||||||
match coverage_reader.read_u8() {
|
|
||||||
Ok(COVERAGE_SERIALIZATION_VERSION) => (),
|
|
||||||
_ => return Err(SecurityStateError::from("unknown CRLite coverage version")),
|
|
||||||
}
|
|
||||||
if (coverage_file_len - 1) % COVERAGE_V1_ENTRY_BYTES != 0 {
|
|
||||||
return Err(SecurityStateError::from("truncated CRLite coverage file"));
|
|
||||||
}
|
|
||||||
let coverage_count = (coverage_file_len - 1) / COVERAGE_V1_ENTRY_BYTES;
|
|
||||||
let mut coverage = HashMap::new();
|
|
||||||
for _ in 0..coverage_count {
|
|
||||||
let mut coverage_entry = [0u8; COVERAGE_V1_ENTRY_BYTES];
|
|
||||||
match coverage_reader.read_exact(&mut coverage_entry) {
|
|
||||||
Ok(()) => (),
|
|
||||||
_ => return Err(SecurityStateError::from("truncated CRLite coverage file")),
|
|
||||||
};
|
|
||||||
let log_id = &coverage_entry[0..32];
|
|
||||||
let min_timestamp: u64;
|
|
||||||
let max_timestamp: u64;
|
|
||||||
match (&coverage_entry[32..40]).read_u64::<LittleEndian>() {
|
|
||||||
Ok(value) => min_timestamp = value,
|
|
||||||
_ => return Err(SecurityStateError::from("truncated CRLite coverage file")),
|
|
||||||
}
|
|
||||||
match (&coverage_entry[40..48]).read_u64::<LittleEndian>() {
|
|
||||||
Ok(value) => max_timestamp = value,
|
|
||||||
_ => return Err(SecurityStateError::from("truncated CRLite coverage file")),
|
|
||||||
}
|
|
||||||
coverage.insert(log_id.to_vec(), (min_timestamp, max_timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize the enrollment metadata.
|
|
||||||
// The format is described in `set_full_crlite_filter`.
|
|
||||||
let enrollment_file = File::open(enrollment_path)?;
|
|
||||||
let enrollment_file_len = enrollment_file.metadata()?.len() as usize;
|
|
||||||
let mut enrollment_reader = BufReader::new(enrollment_file);
|
|
||||||
match enrollment_reader.read_u8() {
|
|
||||||
Ok(ENROLLMENT_SERIALIZATION_VERSION) => (),
|
|
||||||
_ => {
|
|
||||||
return Err(SecurityStateError::from(
|
|
||||||
"unknown CRLite enrollment version",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (enrollment_file_len - 1) % ENROLLMENT_V1_ENTRY_BYTES != 0 {
|
|
||||||
return Err(SecurityStateError::from("truncated CRLite enrollment file"));
|
|
||||||
}
|
|
||||||
let enrollment_count = (enrollment_file_len - 1) / ENROLLMENT_V1_ENTRY_BYTES;
|
|
||||||
let mut enrollment = HashSet::new();
|
|
||||||
for _ in 0..enrollment_count {
|
|
||||||
let mut enrollment_entry = [0u8; ENROLLMENT_V1_ENTRY_BYTES];
|
|
||||||
match enrollment_reader.read_exact(&mut enrollment_entry) {
|
|
||||||
Ok(()) => (),
|
|
||||||
_ => return Err(SecurityStateError::from("truncated CRLite enrollment file")),
|
|
||||||
};
|
|
||||||
let issuer_id = &enrollment_entry[..];
|
|
||||||
enrollment.insert(issuer_id.to_vec());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
cascade,
|
|
||||||
coverage,
|
|
||||||
enrollment,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn filter_covers_some_timestamp(&self, timestamps: &[CRLiteTimestamp]) -> bool {
|
|
||||||
let mut covered_timestamp_count = 0;
|
|
||||||
for entry in timestamps {
|
|
||||||
if let Some(&(low, high)) = self.coverage.get(entry.log_id.as_ref()) {
|
|
||||||
if low <= entry.timestamp && entry.timestamp <= high {
|
|
||||||
covered_timestamp_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
covered_timestamp_count
|
|
||||||
>= static_prefs::pref!("security.pki.crlite_timestamps_for_coverage")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn issuer_is_enrolled(&self, subject: &[u8], pub_key: &[u8]) -> bool {
|
|
||||||
let mut digest = Sha256::default();
|
|
||||||
digest.update(subject);
|
|
||||||
digest.update(pub_key);
|
|
||||||
let issuer_id = digest.finalize();
|
|
||||||
self.enrollment.contains(issuer_id.as_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has(&self, crlite_key: &[u8]) -> bool {
|
|
||||||
self.cascade.has(crlite_key.to_vec())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MallocSizeOf for CascadeWithMetadata {
|
|
||||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
|
||||||
self.cascade.approximate_size_of()
|
|
||||||
+ self.coverage.size_of(ops)
|
|
||||||
+ self.enrollment.size_of(ops)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Filter {
|
enum Filter {
|
||||||
Cascade(CascadeWithMetadata),
|
|
||||||
Clubcard(CRLiteClubcard),
|
Clubcard(CRLiteClubcard),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,47 +142,13 @@ impl Filter {
|
|||||||
|
|
||||||
if let Ok(clubcard) = CRLiteClubcard::from_bytes(&filter_bytes) {
|
if let Ok(clubcard) = CRLiteClubcard::from_bytes(&filter_bytes) {
|
||||||
Ok(Some(Filter::Clubcard(clubcard)))
|
Ok(Some(Filter::Clubcard(clubcard)))
|
||||||
} else if let Ok(maybe_cascade) = Cascade::from_bytes(filter_bytes) {
|
|
||||||
let Some(cascade) = maybe_cascade else {
|
|
||||||
return Err(SecurityStateError::from("expecting non-empty filter"));
|
|
||||||
};
|
|
||||||
let coverage_path = store_path.join("crlite.coverage");
|
|
||||||
let enrollment_path = store_path.join("crlite.enrollment");
|
|
||||||
if !coverage_path.exists() || !enrollment_path.exists() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let cascade_with_metadata =
|
|
||||||
CascadeWithMetadata::new(cascade, &coverage_path, &enrollment_path)?;
|
|
||||||
Ok(Some(Filter::Cascade(cascade_with_metadata)))
|
|
||||||
} else {
|
} else {
|
||||||
Err(SecurityStateError::from("invalid CRLite filter"))
|
Err(SecurityStateError::from("invalid CRLite filter"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has(
|
fn has(&self, clubcard_crlite_key: &CRLiteKey, timestamps: &[CRLiteTimestamp]) -> i16 {
|
||||||
&self,
|
|
||||||
issuer_dn: &[u8],
|
|
||||||
issuer_spki: &[u8],
|
|
||||||
issuer_spki_hash: &[u8],
|
|
||||||
serial: &[u8],
|
|
||||||
clubcard_crlite_key: &CRLiteKey,
|
|
||||||
timestamps: &[CRLiteTimestamp],
|
|
||||||
) -> i16 {
|
|
||||||
match self {
|
match self {
|
||||||
Filter::Cascade(cascade) => {
|
|
||||||
let mut crlite_key = Vec::with_capacity(issuer_spki_hash.len() + serial.len());
|
|
||||||
crlite_key.extend_from_slice(issuer_spki_hash);
|
|
||||||
crlite_key.extend_from_slice(serial);
|
|
||||||
if !cascade.issuer_is_enrolled(issuer_dn, issuer_spki) {
|
|
||||||
nsICertStorage::STATE_NOT_ENROLLED
|
|
||||||
} else if !cascade.filter_covers_some_timestamp(timestamps) {
|
|
||||||
nsICertStorage::STATE_NOT_COVERED
|
|
||||||
} else if cascade.has(&crlite_key) {
|
|
||||||
nsICertStorage::STATE_ENFORCE
|
|
||||||
} else {
|
|
||||||
nsICertStorage::STATE_UNSET
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Filter::Clubcard(clubcard) => {
|
Filter::Clubcard(clubcard) => {
|
||||||
let timestamp_iter = timestamps
|
let timestamp_iter = timestamps
|
||||||
.iter()
|
.iter()
|
||||||
@@ -354,9 +184,8 @@ impl Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MallocSizeOf for Filter {
|
impl MallocSizeOf for Filter {
|
||||||
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
|
fn size_of(&self, _: &mut MallocSizeOfOps) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Filter::Cascade(cascade) => cascade.size_of(ops),
|
|
||||||
Filter::Clubcard(clubcard) => clubcard.approximate_size_of(),
|
Filter::Clubcard(clubcard) => clubcard.approximate_size_of(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,8 +196,6 @@ struct SecurityState {
|
|||||||
profile_path: PathBuf,
|
profile_path: PathBuf,
|
||||||
env_and_store: Option<EnvAndStore>,
|
env_and_store: Option<EnvAndStore>,
|
||||||
crlite_filters: Vec<Filter>,
|
crlite_filters: Vec<Filter>,
|
||||||
/// Maps issuer spki hashes to sets of serial numbers.
|
|
||||||
crlite_stash: Option<HashMap<Vec<u8>, HashSet<Vec<u8>>>>,
|
|
||||||
/// Tracks the number of asynchronous operations which have been dispatched but not completed.
|
/// Tracks the number of asynchronous operations which have been dispatched but not completed.
|
||||||
remaining_ops: i32,
|
remaining_ops: i32,
|
||||||
}
|
}
|
||||||
@@ -381,7 +208,6 @@ impl SecurityState {
|
|||||||
profile_path,
|
profile_path,
|
||||||
env_and_store: None,
|
env_and_store: None,
|
||||||
crlite_filters: vec![],
|
crlite_filters: vec![],
|
||||||
crlite_stash: None,
|
|
||||||
remaining_ops: 0,
|
remaining_ops: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -515,7 +341,7 @@ impl SecurityState {
|
|||||||
return Ok(!self.crlite_filters.is_empty());
|
return Ok(!self.crlite_filters.is_empty());
|
||||||
}
|
}
|
||||||
if data_type == nsICertStorage::DATA_TYPE_CRLITE_FILTER_INCREMENTAL {
|
if data_type == nsICertStorage::DATA_TYPE_CRLITE_FILTER_INCREMENTAL {
|
||||||
return Ok(self.crlite_stash.is_some() || self.crlite_filters.len() > 1);
|
return Ok(self.crlite_filters.len() > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let env_and_store = match self.env_and_store.as_ref() {
|
let env_and_store = match self.env_and_store.as_ref() {
|
||||||
@@ -652,19 +478,15 @@ impl SecurityState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_full_crlite_filter(
|
pub fn set_full_crlite_filter(&mut self, filter: Vec<u8>) -> Result<(), SecurityStateError> {
|
||||||
&mut self,
|
|
||||||
filter: Vec<u8>,
|
|
||||||
enrolled_issuers: Vec<nsCString>,
|
|
||||||
coverage_entries: &[(nsCString, u64, u64)],
|
|
||||||
) -> Result<(), SecurityStateError> {
|
|
||||||
let store_path = get_store_path(&self.profile_path)?;
|
let store_path = get_store_path(&self.profile_path)?;
|
||||||
|
|
||||||
// Drop any existing crlite filter and clear the accumulated stash.
|
// Drop any existing crlite filters
|
||||||
self.crlite_filters.clear();
|
self.crlite_filters.clear();
|
||||||
self.crlite_stash = None;
|
|
||||||
|
|
||||||
// Delete the backing data for any stash or delta files.
|
// Delete the backing data for the previous collection of filters. We may be migrating
|
||||||
|
// from a bloom filter cascade, so check for and delete "coverage", "enrollment", and
|
||||||
|
// "stash" files in addition to "delta" and "filter" files.
|
||||||
for entry in std::fs::read_dir(&store_path)? {
|
for entry in std::fs::read_dir(&store_path)? {
|
||||||
let Ok(entry) = entry else {
|
let Ok(entry) = entry else {
|
||||||
continue;
|
continue;
|
||||||
@@ -674,7 +496,12 @@ impl SecurityState {
|
|||||||
.extension()
|
.extension()
|
||||||
.map(|os_str| os_str.to_str())
|
.map(|os_str| os_str.to_str())
|
||||||
.flatten();
|
.flatten();
|
||||||
if extension == Some("stash") || extension == Some("delta") {
|
if extension == Some("coverage")
|
||||||
|
|| extension == Some("delta")
|
||||||
|
|| extension == Some("enrollment")
|
||||||
|
|| extension == Some("filter")
|
||||||
|
|| extension == Some("stash")
|
||||||
|
{
|
||||||
let _ = std::fs::remove_file(entry_path);
|
let _ = std::fs::remove_file(entry_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -682,46 +509,6 @@ impl SecurityState {
|
|||||||
// Write the new full filter.
|
// Write the new full filter.
|
||||||
std::fs::write(store_path.join("crlite.filter"), &filter)?;
|
std::fs::write(store_path.join("crlite.filter"), &filter)?;
|
||||||
|
|
||||||
// Serialize the coverage metadata as a 1 byte version number followed by any number of 48
|
|
||||||
// byte entries. Each entry is a 32 byte (opaque) log id, followed by two 8 byte
|
|
||||||
// timestamps. Each timestamp is an 8 byte unsigned integer in little endian.
|
|
||||||
let mut coverage_bytes =
|
|
||||||
Vec::with_capacity(size_of::<u8>() + coverage_entries.len() * COVERAGE_V1_ENTRY_BYTES);
|
|
||||||
coverage_bytes.push(COVERAGE_SERIALIZATION_VERSION);
|
|
||||||
for (b64_log_id, min_t, max_t) in coverage_entries {
|
|
||||||
let log_id = match BASE64_STANDARD.decode(&b64_log_id) {
|
|
||||||
Ok(log_id) if log_id.len() == 32 => log_id,
|
|
||||||
_ => {
|
|
||||||
warn!("malformed log ID - skipping: {}", b64_log_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
coverage_bytes.extend_from_slice(&log_id);
|
|
||||||
coverage_bytes.extend_from_slice(&min_t.to_le_bytes());
|
|
||||||
coverage_bytes.extend_from_slice(&max_t.to_le_bytes());
|
|
||||||
}
|
|
||||||
// Write the coverage file for the new filter
|
|
||||||
std::fs::write(store_path.join("crlite.coverage"), &coverage_bytes)?;
|
|
||||||
|
|
||||||
// Serialize the enrollment list as a 1 byte version number followed by:
|
|
||||||
// Version 1: any number of 32 byte values of the form `SHA256(subject || spki)`.
|
|
||||||
let mut enrollment_bytes = Vec::with_capacity(
|
|
||||||
size_of::<u8>() + enrolled_issuers.len() * ENROLLMENT_V1_ENTRY_BYTES,
|
|
||||||
);
|
|
||||||
enrollment_bytes.push(ENROLLMENT_SERIALIZATION_VERSION);
|
|
||||||
for b64_issuer_id in enrolled_issuers {
|
|
||||||
let issuer_id = match BASE64_STANDARD.decode(&b64_issuer_id) {
|
|
||||||
Ok(issuer_id) if issuer_id.len() == 32 => issuer_id,
|
|
||||||
_ => {
|
|
||||||
warn!("malformed issuer ID - skipping: {}", b64_issuer_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
enrollment_bytes.extend_from_slice(&issuer_id);
|
|
||||||
}
|
|
||||||
// Write the enrollment file for the new filter
|
|
||||||
std::fs::write(store_path.join("crlite.enrollment"), &enrollment_bytes)?;
|
|
||||||
|
|
||||||
self.note_crlite_update_time()?;
|
self.note_crlite_update_time()?;
|
||||||
self.load_crlite_filter()?;
|
self.load_crlite_filter()?;
|
||||||
self.note_memory_usage();
|
self.note_memory_usage();
|
||||||
@@ -743,19 +530,6 @@ impl SecurityState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_crlite_stash(&mut self, stash: Vec<u8>) -> Result<(), SecurityStateError> {
|
|
||||||
// Append the update to the previously-seen stashes.
|
|
||||||
let mut path = get_store_path(&self.profile_path)?;
|
|
||||||
path.push("crlite.stash");
|
|
||||||
let mut stash_file = OpenOptions::new().append(true).create(true).open(path)?;
|
|
||||||
stash_file.write_all(&stash)?;
|
|
||||||
let crlite_stash = self.crlite_stash.get_or_insert(HashMap::new());
|
|
||||||
load_crlite_stash_from_reader_into_map(&mut stash.as_slice(), crlite_stash)?;
|
|
||||||
self.note_crlite_update_time()?;
|
|
||||||
self.note_memory_usage();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_crlite_delta(
|
pub fn add_crlite_delta(
|
||||||
&mut self,
|
&mut self,
|
||||||
delta: Vec<u8>,
|
delta: Vec<u8>,
|
||||||
@@ -772,28 +546,8 @@ impl SecurityState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_cert_revoked_by_stash(
|
|
||||||
&self,
|
|
||||||
issuer_spki: &[u8],
|
|
||||||
serial: &[u8],
|
|
||||||
) -> Result<bool, SecurityStateError> {
|
|
||||||
let crlite_stash = match self.crlite_stash.as_ref() {
|
|
||||||
Some(crlite_stash) => crlite_stash,
|
|
||||||
None => return Ok(false),
|
|
||||||
};
|
|
||||||
let mut digest = Sha256::default();
|
|
||||||
digest.update(issuer_spki);
|
|
||||||
let lookup_key = digest.finalize().to_vec();
|
|
||||||
let serials = match crlite_stash.get(&lookup_key) {
|
|
||||||
Some(serials) => serials,
|
|
||||||
None => return Ok(false),
|
|
||||||
};
|
|
||||||
Ok(serials.contains(&serial.to_vec()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_crlite_revocation_state(
|
pub fn get_crlite_revocation_state(
|
||||||
&self,
|
&self,
|
||||||
issuer: &[u8],
|
|
||||||
issuer_spki: &[u8],
|
issuer_spki: &[u8],
|
||||||
serial_number: &[u8],
|
serial_number: &[u8],
|
||||||
timestamps: &[CRLiteTimestamp],
|
timestamps: &[CRLiteTimestamp],
|
||||||
@@ -812,14 +566,7 @@ impl SecurityState {
|
|||||||
let issuer_spki_hash = Sha256::digest(issuer_spki);
|
let issuer_spki_hash = Sha256::digest(issuer_spki);
|
||||||
let clubcard_crlite_key = CRLiteKey::new(issuer_spki_hash.as_ref(), serial_number);
|
let clubcard_crlite_key = CRLiteKey::new(issuer_spki_hash.as_ref(), serial_number);
|
||||||
for filter in &self.crlite_filters {
|
for filter in &self.crlite_filters {
|
||||||
match filter.has(
|
match filter.has(&clubcard_crlite_key, timestamps) {
|
||||||
issuer,
|
|
||||||
issuer_spki,
|
|
||||||
issuer_spki_hash.as_ref(),
|
|
||||||
serial_number,
|
|
||||||
&clubcard_crlite_key,
|
|
||||||
timestamps,
|
|
||||||
) {
|
|
||||||
nsICertStorage::STATE_ENFORCE => return nsICertStorage::STATE_ENFORCE,
|
nsICertStorage::STATE_ENFORCE => return nsICertStorage::STATE_ENFORCE,
|
||||||
nsICertStorage::STATE_UNSET => maybe_good = true,
|
nsICertStorage::STATE_UNSET => maybe_good = true,
|
||||||
nsICertStorage::STATE_NOT_ENROLLED => covered = true,
|
nsICertStorage::STATE_NOT_ENROLLED => covered = true,
|
||||||
@@ -1015,7 +762,6 @@ impl MallocSizeOf for SecurityState {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|filter| filter.size_of(ops))
|
.map(|filter| filter.size_of(ops))
|
||||||
.sum::<usize>()
|
.sum::<usize>()
|
||||||
+ self.crlite_stash.size_of(ops)
|
|
||||||
+ self.remaining_ops.size_of(ops)
|
+ self.remaining_ops.size_of(ops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1302,71 +1048,26 @@ fn remove_db(path: &Path) -> Result<(), SecurityStateError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to read stash information from the given reader and insert the results into the
|
// This is a helper struct that implements the task that asynchronously reads CRLite deltas on
|
||||||
// given stash map.
|
// a background thread.
|
||||||
fn load_crlite_stash_from_reader_into_map(
|
struct BackgroundReadDeltasTask {
|
||||||
reader: &mut dyn Read,
|
|
||||||
dest: &mut HashMap<Vec<u8>, HashSet<Vec<u8>>>,
|
|
||||||
) -> Result<(), SecurityStateError> {
|
|
||||||
// The basic unit of the stash file is an issuer subject public key info
|
|
||||||
// hash (sha-256) followed by a number of serial numbers corresponding
|
|
||||||
// to revoked certificates issued by that issuer. More specifically,
|
|
||||||
// each unit consists of:
|
|
||||||
// 4 bytes little-endian: the number of serial numbers following the issuer spki hash
|
|
||||||
// 1 byte: the length of the issuer spki hash
|
|
||||||
// issuer spki hash length bytes: the issuer spki hash
|
|
||||||
// as many times as the indicated serial numbers:
|
|
||||||
// 1 byte: the length of the serial number
|
|
||||||
// serial number length bytes: the serial number
|
|
||||||
// The stash file consists of any number of these units concatenated
|
|
||||||
// together.
|
|
||||||
loop {
|
|
||||||
let num_serials = match reader.read_u32::<LittleEndian>() {
|
|
||||||
Ok(num_serials) => num_serials,
|
|
||||||
Err(_) => break, // end of input, presumably
|
|
||||||
};
|
|
||||||
let issuer_spki_hash_len = reader.read_u8().map_err(|e| {
|
|
||||||
SecurityStateError::from(format!("error reading stash issuer_spki_hash_len: {}", e))
|
|
||||||
})?;
|
|
||||||
let mut issuer_spki_hash = vec![0; issuer_spki_hash_len.into()];
|
|
||||||
reader.read_exact(&mut issuer_spki_hash).map_err(|e| {
|
|
||||||
SecurityStateError::from(format!("error reading stash issuer_spki_hash: {}", e))
|
|
||||||
})?;
|
|
||||||
let serials = dest.entry(issuer_spki_hash).or_insert(HashSet::new());
|
|
||||||
for _ in 0..num_serials {
|
|
||||||
let serial_len = reader.read_u8().map_err(|e| {
|
|
||||||
SecurityStateError::from(format!("error reading stash serial_len: {}", e))
|
|
||||||
})?;
|
|
||||||
let mut serial = vec![0; serial_len.into()];
|
|
||||||
reader.read_exact(&mut serial).map_err(|e| {
|
|
||||||
SecurityStateError::from(format!("error reading stash serial: {}", e))
|
|
||||||
})?;
|
|
||||||
let _ = serials.insert(serial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a helper struct that implements the task that asynchronously reads the CRLite stash on a
|
|
||||||
// background thread.
|
|
||||||
struct BackgroundReadStashTask {
|
|
||||||
profile_path: PathBuf,
|
profile_path: PathBuf,
|
||||||
security_state: Arc<RwLock<SecurityState>>,
|
security_state: Arc<RwLock<SecurityState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BackgroundReadStashTask {
|
impl BackgroundReadDeltasTask {
|
||||||
fn new(
|
fn new(
|
||||||
profile_path: PathBuf,
|
profile_path: PathBuf,
|
||||||
security_state: &Arc<RwLock<SecurityState>>,
|
security_state: &Arc<RwLock<SecurityState>>,
|
||||||
) -> BackgroundReadStashTask {
|
) -> BackgroundReadDeltasTask {
|
||||||
BackgroundReadStashTask {
|
BackgroundReadDeltasTask {
|
||||||
profile_path,
|
profile_path,
|
||||||
security_state: Arc::clone(security_state),
|
security_state: Arc::clone(security_state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Task for BackgroundReadStashTask {
|
impl Task for BackgroundReadDeltasTask {
|
||||||
fn run(&self) {
|
fn run(&self) {
|
||||||
let Ok(store_path) = get_store_path(&self.profile_path) else {
|
let Ok(store_path) = get_store_path(&self.profile_path) else {
|
||||||
error!("error getting security_state path");
|
error!("error getting security_state path");
|
||||||
@@ -1390,23 +1091,6 @@ impl Task for BackgroundReadStashTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut maybe_crlite_stash = None;
|
|
||||||
let stash_path = store_path.join("crlite.stash");
|
|
||||||
// Before we've downloaded any stashes, this file won't exist.
|
|
||||||
if stash_path.exists() {
|
|
||||||
if let Ok(stash_file) = File::open(stash_path) {
|
|
||||||
let mut stash_reader = BufReader::new(stash_file);
|
|
||||||
let mut crlite_stash = HashMap::new();
|
|
||||||
match load_crlite_stash_from_reader_into_map(&mut stash_reader, &mut crlite_stash) {
|
|
||||||
Ok(()) => maybe_crlite_stash = Some(crlite_stash),
|
|
||||||
Err(e) => {
|
|
||||||
error!("error loading crlite stash: {}", e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error!("error opening stash file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let Ok(mut ss) = self.security_state.write() else {
|
let Ok(mut ss) = self.security_state.write() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -1414,7 +1098,6 @@ impl Task for BackgroundReadStashTask {
|
|||||||
error!("error opening security state db: {}", e.message);
|
error!("error opening security state db: {}", e.message);
|
||||||
}
|
}
|
||||||
ss.crlite_filters.append(&mut delta_filters);
|
ss.crlite_filters.append(&mut delta_filters);
|
||||||
ss.crlite_stash = maybe_crlite_stash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn done(&self) -> Result<(), nsresult> {
|
fn done(&self) -> Result<(), nsresult> {
|
||||||
@@ -1434,23 +1117,21 @@ fn do_construct_cert_storage(
|
|||||||
});
|
});
|
||||||
let memory_reporter = MemoryReporter::allocate(InitMemoryReporter { security_state });
|
let memory_reporter = MemoryReporter::allocate(InitMemoryReporter { security_state });
|
||||||
|
|
||||||
// Dispatch a task to the background task queue to asynchronously read the CRLite stash file (if
|
// Dispatch a task to the background task queue to asynchronously read CRLite delta files (if
|
||||||
// present) and load it into cert_storage. This task does not hold the
|
// present) and load them into cert_storage. This task does not hold the
|
||||||
// cert_storage.security_state mutex for the majority of its operation, which allows certificate
|
// cert_storage.security_state mutex for the majority of its operation, which allows certificate
|
||||||
// verification threads to query cert_storage without blocking. This is important for
|
// verification threads to query cert_storage without blocking. This is important for
|
||||||
// performance, but it means that certificate verifications that happen before the task has
|
// performance, but it means that certificate verifications that happen before the task has
|
||||||
// completed will not have stash information, and thus may not know of revocations that have
|
// completed will not have delta information, and thus may not know of revocations that have
|
||||||
// occurred since the last full CRLite filter was downloaded. As long as the last full filter
|
// occurred since the last full CRLite filter was downloaded.
|
||||||
// was downloaded no more than 10 days ago, this is no worse than relying on OCSP responses,
|
|
||||||
// which have a maximum validity of 10 days.
|
|
||||||
// NB: because the background task queue is serial, this task will complete before other tasks
|
// NB: because the background task queue is serial, this task will complete before other tasks
|
||||||
// later dispatched to the queue run. This means that other tasks that interact with the stash
|
// later dispatched to the queue run. This means that other tasks that depend on deltas will do
|
||||||
// will do so with the correct set of preconditions.
|
// so with the correct set of preconditions.
|
||||||
let load_crlite_stash_task = Box::new(BackgroundReadStashTask::new(
|
let load_crlite_deltas_task = Box::new(BackgroundReadDeltasTask::new(
|
||||||
path_buf,
|
path_buf,
|
||||||
&cert_storage.security_state,
|
&cert_storage.security_state,
|
||||||
));
|
));
|
||||||
let runnable = TaskRunnable::new("LoadCrliteStash", load_crlite_stash_task)?;
|
let runnable = TaskRunnable::new("LoadCrliteDeltas", load_crlite_deltas_task)?;
|
||||||
TaskRunnable::dispatch(runnable, cert_storage.queue.coerce())?;
|
TaskRunnable::dispatch(runnable, cert_storage.queue.coerce())?;
|
||||||
|
|
||||||
if let Some(reporter) = memory_reporter.query_interface::<nsIMemoryReporter>() {
|
if let Some(reporter) = memory_reporter.query_interface::<nsIMemoryReporter>() {
|
||||||
@@ -1729,72 +1410,27 @@ impl CertStorage {
|
|||||||
unsafe fn SetFullCRLiteFilter(
|
unsafe fn SetFullCRLiteFilter(
|
||||||
&self,
|
&self,
|
||||||
filter: *const ThinVec<u8>,
|
filter: *const ThinVec<u8>,
|
||||||
enrolled_issuers: *const ThinVec<nsCString>,
|
|
||||||
coverage: *const ThinVec<Option<RefPtr<nsICRLiteCoverage>>>,
|
|
||||||
callback: *const nsICertStorageCallback,
|
callback: *const nsICertStorageCallback,
|
||||||
) -> nserror::nsresult {
|
) -> nserror::nsresult {
|
||||||
if !is_main_thread() {
|
if !is_main_thread() {
|
||||||
return NS_ERROR_NOT_SAME_THREAD;
|
return NS_ERROR_NOT_SAME_THREAD;
|
||||||
}
|
}
|
||||||
if filter.is_null()
|
if filter.is_null() || callback.is_null() {
|
||||||
|| coverage.is_null()
|
|
||||||
|| callback.is_null()
|
|
||||||
|| enrolled_issuers.is_null()
|
|
||||||
{
|
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter_owned = (*filter).to_vec();
|
let filter_owned = (*filter).to_vec();
|
||||||
let enrolled_issuers_owned = (*enrolled_issuers).to_vec();
|
|
||||||
|
|
||||||
let coverage = &*coverage;
|
|
||||||
let mut coverage_entries = Vec::with_capacity(coverage.len());
|
|
||||||
for entry in coverage.iter().flatten() {
|
|
||||||
let mut b64_log_id = nsCString::new();
|
|
||||||
try_ns!((*entry).GetB64LogID(&mut *b64_log_id).to_result(), or continue);
|
|
||||||
let mut min_timestamp: u64 = 0;
|
|
||||||
try_ns!((*entry).GetMinTimestamp(&mut min_timestamp).to_result(), or continue);
|
|
||||||
let mut max_timestamp: u64 = 0;
|
|
||||||
try_ns!((*entry).GetMaxTimestamp(&mut max_timestamp).to_result(), or continue);
|
|
||||||
coverage_entries.push((b64_log_id, min_timestamp, max_timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
let task = Box::new(try_ns!(SecurityStateTask::new(
|
let task = Box::new(try_ns!(SecurityStateTask::new(
|
||||||
&*callback,
|
&*callback,
|
||||||
&self.security_state,
|
&self.security_state,
|
||||||
move |ss| ss.set_full_crlite_filter(
|
move |ss| ss.set_full_crlite_filter(filter_owned),
|
||||||
filter_owned,
|
|
||||||
enrolled_issuers_owned,
|
|
||||||
&coverage_entries
|
|
||||||
),
|
|
||||||
)));
|
)));
|
||||||
let runnable = try_ns!(TaskRunnable::new("SetFullCRLiteFilter", task));
|
let runnable = try_ns!(TaskRunnable::new("SetFullCRLiteFilter", task));
|
||||||
try_ns!(TaskRunnable::dispatch(runnable, self.queue.coerce()));
|
try_ns!(TaskRunnable::dispatch(runnable, self.queue.coerce()));
|
||||||
NS_OK
|
NS_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn AddCRLiteStash(
|
|
||||||
&self,
|
|
||||||
stash: *const ThinVec<u8>,
|
|
||||||
callback: *const nsICertStorageCallback,
|
|
||||||
) -> nserror::nsresult {
|
|
||||||
if !is_main_thread() {
|
|
||||||
return NS_ERROR_NOT_SAME_THREAD;
|
|
||||||
}
|
|
||||||
if stash.is_null() || callback.is_null() {
|
|
||||||
return NS_ERROR_NULL_POINTER;
|
|
||||||
}
|
|
||||||
let stash_owned = (*stash).to_vec();
|
|
||||||
let task = Box::new(try_ns!(SecurityStateTask::new(
|
|
||||||
&*callback,
|
|
||||||
&self.security_state,
|
|
||||||
move |ss| ss.add_crlite_stash(stash_owned),
|
|
||||||
)));
|
|
||||||
let runnable = try_ns!(TaskRunnable::new("AddCRLiteStash", task));
|
|
||||||
try_ns!(TaskRunnable::dispatch(runnable, self.queue.coerce()));
|
|
||||||
NS_OK
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn AddCRLiteDelta(
|
unsafe fn AddCRLiteDelta(
|
||||||
&self,
|
&self,
|
||||||
delta: *const ThinVec<u8>,
|
delta: *const ThinVec<u8>,
|
||||||
@@ -1819,26 +1455,25 @@ impl CertStorage {
|
|||||||
NS_OK
|
NS_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn IsCertRevokedByStash(
|
unsafe fn TestNoteCRLiteUpdateTime(
|
||||||
&self,
|
&self,
|
||||||
issuer_spki: *const ThinVec<u8>,
|
callback: *const nsICertStorageCallback,
|
||||||
serial_number: *const ThinVec<u8>,
|
|
||||||
is_revoked: *mut bool,
|
|
||||||
) -> nserror::nsresult {
|
) -> nserror::nsresult {
|
||||||
if issuer_spki.is_null() || serial_number.is_null() || is_revoked.is_null() {
|
if !is_main_thread() {
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NOT_SAME_THREAD;
|
||||||
}
|
}
|
||||||
let ss = get_security_state!(self);
|
let task = Box::new(try_ns!(SecurityStateTask::new(
|
||||||
*is_revoked = match ss.is_cert_revoked_by_stash(&*issuer_spki, &*serial_number) {
|
&*callback,
|
||||||
Ok(is_revoked) => is_revoked,
|
&self.security_state,
|
||||||
Err(_) => return NS_ERROR_FAILURE,
|
move |ss| ss.note_crlite_update_time(),
|
||||||
};
|
)));
|
||||||
|
let runnable = try_ns!(TaskRunnable::new("TestNoteCRLiteUpdateTime", task));
|
||||||
|
try_ns!(TaskRunnable::dispatch(runnable, self.queue.coerce()));
|
||||||
NS_OK
|
NS_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn GetCRLiteRevocationState(
|
unsafe fn GetCRLiteRevocationState(
|
||||||
&self,
|
&self,
|
||||||
issuer: *const ThinVec<u8>,
|
|
||||||
issuerSPKI: *const ThinVec<u8>,
|
issuerSPKI: *const ThinVec<u8>,
|
||||||
serialNumber: *const ThinVec<u8>,
|
serialNumber: *const ThinVec<u8>,
|
||||||
timestamps: *const ThinVec<Option<RefPtr<nsICRLiteTimestamp>>>,
|
timestamps: *const ThinVec<Option<RefPtr<nsICRLiteTimestamp>>>,
|
||||||
@@ -1846,11 +1481,7 @@ impl CertStorage {
|
|||||||
) -> nserror::nsresult {
|
) -> nserror::nsresult {
|
||||||
// TODO (bug 1541212): We really want to restrict this to non-main-threads only, but we
|
// TODO (bug 1541212): We really want to restrict this to non-main-threads only, but we
|
||||||
// can't do so until bug 1406854 is fixed.
|
// can't do so until bug 1406854 is fixed.
|
||||||
if issuer.is_null()
|
if issuerSPKI.is_null() || serialNumber.is_null() || state.is_null() || timestamps.is_null()
|
||||||
|| issuerSPKI.is_null()
|
|
||||||
|| serialNumber.is_null()
|
|
||||||
|| state.is_null()
|
|
||||||
|| timestamps.is_null()
|
|
||||||
{
|
{
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
}
|
}
|
||||||
@@ -1864,12 +1495,7 @@ impl CertStorage {
|
|||||||
timestamp_entries.push(CRLiteTimestamp { log_id, timestamp });
|
timestamp_entries.push(CRLiteTimestamp { log_id, timestamp });
|
||||||
}
|
}
|
||||||
let ss = get_security_state!(self);
|
let ss = get_security_state!(self);
|
||||||
*state = ss.get_crlite_revocation_state(
|
*state = ss.get_crlite_revocation_state(&*issuerSPKI, &*serialNumber, ×tamp_entries);
|
||||||
&*issuer,
|
|
||||||
&*issuerSPKI,
|
|
||||||
&*serialNumber,
|
|
||||||
×tamp_entries,
|
|
||||||
);
|
|
||||||
NS_OK
|
NS_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,23 +51,6 @@ interface nsISubjectAndPubKeyRevocationState : nsIRevocationState {
|
|||||||
readonly attribute ACString pubKey;
|
readonly attribute ACString pubKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface representing a set of certificates that are covered by a CRLite
|
|
||||||
* filter. The set is represented by a certificate transparency log ID and a
|
|
||||||
* pair of timestamps. The timestamps are such that the CRLite aggregator has
|
|
||||||
* seen every certificate from the specified log with an SCT between the two
|
|
||||||
* timestamps.
|
|
||||||
* b64LogID is a base 64-encoded RFC 6962 LogID.
|
|
||||||
* minTimestamp is the smallest timestamp that the CRLite filter covers.
|
|
||||||
* maxTimestamp is the largest timestamp that the CRLite filter covers.
|
|
||||||
*/
|
|
||||||
[scriptable, uuid(416453f7-29bd-4820-a039-9c2e055d3715)]
|
|
||||||
interface nsICRLiteCoverage : nsISupports {
|
|
||||||
readonly attribute ACString b64LogID;
|
|
||||||
readonly attribute unsigned long long minTimestamp;
|
|
||||||
readonly attribute unsigned long long maxTimestamp;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface representing the id and timestamp fields from an RFC 6962
|
* An interface representing the id and timestamp fields from an RFC 6962
|
||||||
* SignedCertificateTimestamp struct.
|
* SignedCertificateTimestamp struct.
|
||||||
@@ -148,23 +131,20 @@ interface nsICertStorage : nsISupports {
|
|||||||
in Array<octet> pubkey);
|
in Array<octet> pubkey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the contents of a new CRLite filter, a list containing
|
* Given the contents of a new CRLite filter, replaces any existing filter
|
||||||
* `base64(sha256(subject DN || subject SPKI))` for each enrolled issuer, and
|
* with the new one. Also clears any previously-set incremental revocation
|
||||||
* the filter's timestamp coverage, replaces any existing filter with the new
|
* updates ("deltas").
|
||||||
* one. Also clears any previously-set incremental revocation updates
|
|
||||||
* ("stashes" or "deltas").
|
|
||||||
*/
|
*/
|
||||||
[must_use]
|
[must_use]
|
||||||
void setFullCRLiteFilter(in Array<octet> filter,
|
void setFullCRLiteFilter(in Array<octet> filter,
|
||||||
in Array<ACString> enrolledIssuers,
|
|
||||||
in Array<nsICRLiteCoverage> coverage,
|
|
||||||
in nsICertStorageCallback callback);
|
in nsICertStorageCallback callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the DER-encoded issuer distinguished name, DER-encoded issuer subject public key info,
|
* Given the DER-encoded issuer subject public key info, the bytes of the
|
||||||
* the bytes of the value of the serial number (so, not including the DER tag and length) of a
|
* value of the serial number (so, not including the DER tag and length) of a
|
||||||
* certificate, and the timestamps from that certificate's embedded SCTs, returns the result of
|
* certificate, and the timestamps from that certificate's embedded SCTs,
|
||||||
* looking up the corresponding entry in the currently-saved CRLite filter (if any).
|
* returns the result of looking up the corresponding entry in the
|
||||||
|
* currently-saved CRLite filter (if any).
|
||||||
* Returns
|
* Returns
|
||||||
* - STATE_ENFORCE if the lookup indicates the certificate is revoked via CRLite,
|
* - STATE_ENFORCE if the lookup indicates the certificate is revoked via CRLite,
|
||||||
* - STATE_UNSET if the lookup indicates the certificate is not revoked via CRLite,
|
* - STATE_UNSET if the lookup indicates the certificate is not revoked via CRLite,
|
||||||
@@ -175,28 +155,10 @@ interface nsICertStorage : nsISupports {
|
|||||||
* No lookup is performed in the STATE_NOT_ENROLLED and STATE_NOT_COVERED cases.
|
* No lookup is performed in the STATE_NOT_ENROLLED and STATE_NOT_COVERED cases.
|
||||||
*/
|
*/
|
||||||
[must_use, noscript]
|
[must_use, noscript]
|
||||||
short getCRLiteRevocationState(in Array<octet> issuer,
|
short getCRLiteRevocationState(in Array<octet> issuerSPKI,
|
||||||
in Array<octet> issuerSPKI,
|
|
||||||
in Array<octet> serialNumber,
|
in Array<octet> serialNumber,
|
||||||
in Array<nsICRLiteTimestamp> timestamps);
|
in Array<nsICRLiteTimestamp> timestamps);
|
||||||
|
|
||||||
/**
|
|
||||||
* Given the contents of a CRLite incremental revocation update ("stash"), adds the revocation
|
|
||||||
* information to the current set of stashed revocations. The basic unit of the stash file is an
|
|
||||||
* issuer subject public key info hash (sha-256) followed by a number of serial numbers
|
|
||||||
* corresponding to revoked certificates issued by that issuer. More specifically, each unit
|
|
||||||
* consists of:
|
|
||||||
* 4 bytes little-endian: the number of serial numbers following the issuer spki hash
|
|
||||||
* 1 byte: the length of the issuer spki hash
|
|
||||||
* issuer spki hash length bytes: the issuer spki hash
|
|
||||||
* as many times as the indicated serial numbers:
|
|
||||||
* 1 byte: the length of the serial number
|
|
||||||
* serial number length bytes: the serial number
|
|
||||||
* The stash file consists of any number of these units concatenated together.
|
|
||||||
*/
|
|
||||||
[must_use]
|
|
||||||
void addCRLiteStash(in Array<octet> stash, in nsICertStorageCallback callback);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new CRLite filter for consideration in revocation checks. This
|
* Add a new CRLite filter for consideration in revocation checks. This
|
||||||
* filter is treated as a delta update to the current full filter. Calling
|
* filter is treated as a delta update to the current full filter. Calling
|
||||||
@@ -208,13 +170,10 @@ interface nsICertStorage : nsISupports {
|
|||||||
void addCRLiteDelta(in Array<octet> delta, in ACString filename, in nsICertStorageCallback callback);
|
void addCRLiteDelta(in Array<octet> delta, in ACString filename, in nsICertStorageCallback callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a DER-encoded issuer subject public key info and the bytes of the value of the serial
|
* Mark CRLite filters as fresh. For use in tests only.
|
||||||
* number (so, not including the DER tag and length), determines if the certificate identified by
|
|
||||||
* this issuer SPKI and serial number is revoked according to the current set of stashed CRLite
|
|
||||||
* revocation information.
|
|
||||||
*/
|
*/
|
||||||
[must_use, noscript]
|
[must_use]
|
||||||
boolean isCertRevokedByStash(in Array<octet> issuerSPKI, in Array<octet> serialNumber);
|
void testNoteCRLiteUpdateTime(in nsICertStorageCallback callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trust flags to use when adding a adding a certificate.
|
* Trust flags to use when adding a adding a certificate.
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
// -*- 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/.
|
|
||||||
|
|
||||||
// Helper file for tests that initialize CRLite with corrupted `security_state`
|
|
||||||
// files.
|
|
||||||
//
|
|
||||||
// Usage:
|
|
||||||
// Define nsILocalFile variables for the `crlite.filter`, `crlite.coverage`,
|
|
||||||
// and `crlite.enrollment` files that should be copied to the new profile, and
|
|
||||||
// then load this file. The variables should be called `filter`, `coverage`,
|
|
||||||
// and `enrollment`, respectively. To omit a file, leave the corresponding
|
|
||||||
// variable `undefined`.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// let filter = do_get_file("some_test_dir/crlite.filter");
|
|
||||||
// let coverage = undefined;
|
|
||||||
// let enrollment = do_get_file("some_test_dir/crlite.enrollment");
|
|
||||||
// load("./corrupted_crlite_helper.js");
|
|
||||||
//
|
|
||||||
// Note:
|
|
||||||
// The cert_storage library only attempts to read security_state once. So
|
|
||||||
// this task can only be included once per test file.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-undef */
|
|
||||||
|
|
||||||
add_task(async function test_crlite_corrupted() {
|
|
||||||
let securityStateDirectory = do_get_profile();
|
|
||||||
securityStateDirectory.append("security_state");
|
|
||||||
|
|
||||||
Services.prefs.setIntPref(
|
|
||||||
"security.pki.crlite_mode",
|
|
||||||
CRLiteModeEnforcePrefValue
|
|
||||||
);
|
|
||||||
|
|
||||||
if (coverage != undefined) {
|
|
||||||
coverage.copyTo(securityStateDirectory, "crlite.coverage");
|
|
||||||
}
|
|
||||||
if (enrollment != undefined) {
|
|
||||||
enrollment.copyTo(securityStateDirectory, "crlite.enrollment");
|
|
||||||
}
|
|
||||||
if (filter != undefined) {
|
|
||||||
filter.copyTo(securityStateDirectory, "crlite.filter");
|
|
||||||
}
|
|
||||||
|
|
||||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
|
||||||
Ci.nsIX509CertDB
|
|
||||||
);
|
|
||||||
|
|
||||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
|
||||||
Ci.nsICertStorage
|
|
||||||
);
|
|
||||||
|
|
||||||
// This certificate is revoked according to `test_crlite_filters/20201017-0-filter`.
|
|
||||||
// Its issuer is enrolled according to `test_crlite_preexisting/crlite.enrollment`,
|
|
||||||
// and it is covered according to `test_crlite_preexisting/crlite.coverage`.
|
|
||||||
let revokedCert = constructCertFromFile("test_crlite_filters/revoked.pem");
|
|
||||||
|
|
||||||
// The issuer's certificate needs to be available for path building.
|
|
||||||
let issuerCert = constructCertFromFile("test_crlite_filters/issuer.pem");
|
|
||||||
ok(issuerCert, "issuer certificate should decode successfully");
|
|
||||||
|
|
||||||
// If we copied a corrupted file to security_state, then CRLite should not be
|
|
||||||
// initialized, and we should fall back to OCSP. By setting
|
|
||||||
// Ci.nsIX509CertDB.FLAG_LOCAL_ONLY here we skip the OCSP test, so there's no
|
|
||||||
// revocation checking, and the revoked certificate should pass inspection.
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2020-10-20T00:00:00Z").getTime() / 1000,
|
|
||||||
undefined,
|
|
||||||
"us-datarecovery.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
|
|
||||||
// We should not have a filter or a stash.
|
|
||||||
let hasFilter = await new Promise(resolve => {
|
|
||||||
certStorage.hasPriorData(
|
|
||||||
Ci.nsICertStorage.DATA_TYPE_CRLITE_FILTER_FULL,
|
|
||||||
(rv, result) => {
|
|
||||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
Assert.equal(hasFilter, false, "CRLite should not have a filter");
|
|
||||||
|
|
||||||
let hasStash = await new Promise(resolve => {
|
|
||||||
certStorage.hasPriorData(
|
|
||||||
Ci.nsICertStorage.DATA_TYPE_CRLITE_FILTER_INCREMENTAL,
|
|
||||||
(rv, result) => {
|
|
||||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
Assert.equal(hasStash, false, "CRLite should not have a stash");
|
|
||||||
});
|
|
||||||
@@ -241,177 +241,3 @@ add_task(async function test_batched_removal() {
|
|||||||
);
|
);
|
||||||
Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now");
|
Assert.equal(storedCerts.length, 0, "shouldn't have any certificates now");
|
||||||
});
|
});
|
||||||
|
|
||||||
class CRLiteCoverage {
|
|
||||||
constructor(ctLogID, minTimestamp, maxTimestamp) {
|
|
||||||
this.b64LogID = ctLogID;
|
|
||||||
this.minTimestamp = minTimestamp;
|
|
||||||
this.maxTimestamp = maxTimestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CRLiteCoverage.prototype.QueryInterface = ChromeUtils.generateQI([
|
|
||||||
"nsICRLiteCoverage",
|
|
||||||
]);
|
|
||||||
|
|
||||||
add_task(async function test_crlite_filter() {
|
|
||||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
|
||||||
Ci.nsIX509CertDB
|
|
||||||
);
|
|
||||||
addCertFromFile(
|
|
||||||
certdb,
|
|
||||||
"test_cert_storage_direct/valid-cert-issuer.pem",
|
|
||||||
",,"
|
|
||||||
);
|
|
||||||
let validCert = constructCertFromFile(
|
|
||||||
"test_cert_storage_direct/valid-cert.pem"
|
|
||||||
);
|
|
||||||
addCertFromFile(
|
|
||||||
certdb,
|
|
||||||
"test_cert_storage_direct/revoked-cert-issuer.pem",
|
|
||||||
",,"
|
|
||||||
);
|
|
||||||
let revokedCert = constructCertFromFile(
|
|
||||||
"test_cert_storage_direct/revoked-cert.pem"
|
|
||||||
);
|
|
||||||
let filterFile = do_get_file(
|
|
||||||
"test_cert_storage_direct/test-filter.crlite",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
ok(filterFile.exists(), "test filter file should exist");
|
|
||||||
let enrollment = [];
|
|
||||||
let coverage = [];
|
|
||||||
let filterBytes = stringToArray(readFile(filterFile));
|
|
||||||
// First simualte a filter that does not cover any certificates. With CRLite
|
|
||||||
// enabled, none of the certificates should appear to be revoked.
|
|
||||||
let setFullCRLiteFilterResult = await new Promise(resolve => {
|
|
||||||
certStorage.setFullCRLiteFilter(filterBytes, enrollment, coverage, resolve);
|
|
||||||
});
|
|
||||||
Assert.equal(
|
|
||||||
setFullCRLiteFilterResult,
|
|
||||||
Cr.NS_OK,
|
|
||||||
"setFullCRLiteFilter should succeed"
|
|
||||||
);
|
|
||||||
|
|
||||||
Services.prefs.setIntPref(
|
|
||||||
"security.pki.crlite_mode",
|
|
||||||
CRLiteModeEnforcePrefValue
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
validCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"skynew.jp",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"schunk-group.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now replace the filter with one that covers the "valid" and "revoked"
|
|
||||||
// certificates. CRLite should flag the revoked certificate.
|
|
||||||
coverage.push(
|
|
||||||
new CRLiteCoverage(
|
|
||||||
"pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA=",
|
|
||||||
0,
|
|
||||||
1641612275000
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// crlite_enrollment_id.py test_crlite_filters/issuer.pem
|
|
||||||
enrollment.push("UbH9/ZAnjuqf79Xhah1mFOWo6ZvgQCgsdheWfjvVUM8=");
|
|
||||||
// crlite_enrollment_id.py test_crlite_filters/no-sct-issuer.pem
|
|
||||||
enrollment.push("Myn7EasO1QikOtNmo/UZdh6snCAw0BOY6wgU8OsUeeY=");
|
|
||||||
// crlite_enrollment_id.py test_cert_storage_direct/revoked-cert-issuer.pem
|
|
||||||
enrollment.push("HTvSp2263dqBYtgYA2fldKAoTYcEVLPVTlRia9XaoCQ=");
|
|
||||||
|
|
||||||
setFullCRLiteFilterResult = await new Promise(resolve => {
|
|
||||||
certStorage.setFullCRLiteFilter(filterBytes, enrollment, coverage, resolve);
|
|
||||||
});
|
|
||||||
Assert.equal(
|
|
||||||
setFullCRLiteFilterResult,
|
|
||||||
Cr.NS_OK,
|
|
||||||
"setFullCRLiteFilter should succeed"
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
validCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"skynew.jp",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"schunk-group.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
|
|
||||||
// If we're only collecting telemetry, none of the certificates should appear to be revoked.
|
|
||||||
Services.prefs.setIntPref(
|
|
||||||
"security.pki.crlite_mode",
|
|
||||||
CRLiteModeTelemetryOnlyPrefValue
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
validCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"skynew.jp",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"schunk-group.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
|
|
||||||
// If CRLite is disabled, none of the certificates should appear to be revoked.
|
|
||||||
Services.prefs.setIntPref(
|
|
||||||
"security.pki.crlite_mode",
|
|
||||||
CRLiteModeDisabledPrefValue
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
validCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"skynew.jp",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"schunk-group.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEoDCCA4igAwIBAgIQBpaPlkroI1bHThfCtTZbADANBgkqhkiG9w0BAQsFADBs
|
|
||||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
|
||||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
|
||||||
ZSBFViBSb290IENBMB4XDTE3MTEwNjEyMjI1N1oXDTI3MTEwNjEyMjI1N1owXzEL
|
|
||||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
|
||||||
LmRpZ2ljZXJ0LmNvbTEeMBwGA1UEAxMVVGhhd3RlIEVWIFJTQSBDQSAyMDE4MIIB
|
|
||||||
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp0Cu52zmdJFnSezXMKvL0rso
|
|
||||||
WgA/1X7OxjMQHsAllID1eDG836ptJXSTPg+DoEenHfkKyw++wXobgahr0cU/2v8R
|
|
||||||
WR3fID53ZDhEGHzS+Ol7V+HRtZG5teMWCY7gldtBQH0r7xUEp/3ISVsZUVBqtUmL
|
|
||||||
VJlf9nxJD6Cxp4LBlcJJ8+N6kSkV+fA+WdQc0HYhXSg3PxJP7XSU28Wc7gf6y9kZ
|
|
||||||
zQhK4WrZLRrHHbHC2QXdqQYUxR927QV+UCNXnlbTcZy2QpxWTPLzK+/cKXX4cwP6
|
|
||||||
MGF7+8RnUgHlij/5V2k/tIF9ep4B72ucqaS/UhEPpIN/T7A3OAw995yrB38glQID
|
|
||||||
AQABo4IBSTCCAUUwHQYDVR0OBBYEFOcB/AwWGMp9sozshyejb2GBO4Q5MB8GA1Ud
|
|
||||||
IwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA4GA1UdDwEB/wQEAwIBhjAdBgNV
|
|
||||||
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADA0
|
|
||||||
BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0
|
|
||||||
LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
|
|
||||||
RGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2MDQwMgYE
|
|
||||||
VR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
|
|
||||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAWGka+5ffLpfFuzT+WlwDRwhyTZSunnvecZWZT
|
|
||||||
PPKXipynjpXx5dK8YG+2XoH74285GR1UABuvHMFV94XeDET9Pzz5s/NHS1/eAr5e
|
|
||||||
GdwfBl80XwPkwXaYqzRtw6J4RAxeLqcbibhUQv9Iev9QcP0kNPyJu413Xov76mSu
|
|
||||||
JlGThKzcurJPive2eLmwmoIgTPH11N/IIO9nHLVe8KTkt+FGgZCOWHA3kbFBZR39
|
|
||||||
Mn2hFS974rhUkM+VS9KbCiQQ5OwkfbZ/6BINkE1CMtiESZ2WkbxJKPsF3dN7p9DF
|
|
||||||
YWiQSbYjFP+rCT0/MkaHHYUkEvLNPgyJ6z29eMf0DjLu/SXJ
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIHOzCCBiOgAwIBAgIQBi31aKBRMQgg1+xDJ+G6/TANBgkqhkiG9w0BAQsFADBf
|
|
||||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
|
||||||
d3cuZGlnaWNlcnQuY29tMR4wHAYDVQQDExVUaGF3dGUgRVYgUlNBIENBIDIwMTgw
|
|
||||||
HhcNMTgwNTI4MDAwMDAwWhcNMjAwNTIxMTIwMDAwWjCB6zEdMBsGA1UEDwwUUHJp
|
|
||||||
dmF0ZSBPcmdhbml6YXRpb24xEzARBgsrBgEEAYI3PAIBAxMCREUxFjAUBgsrBgEE
|
|
||||||
AYI3PAIBAhMFSGVzc2UxGDAWBgsrBgEEAYI3PAIBAQwHR2llw59lbjERMA8GA1UE
|
|
||||||
BRMISFJCIDY5MDIxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZIZXNzZW4xFDASBgNV
|
|
||||||
BAcTC0hldWNoZWxoZWltMRQwEgYDVQQKEwtTY2h1bmsgR21iSDELMAkGA1UECxMC
|
|
||||||
SVQxGTAXBgNVBAMTEHNjaHVuay1ncm91cC5jb20wggEiMA0GCSqGSIb3DQEBAQUA
|
|
||||||
A4IBDwAwggEKAoIBAQCvkuQZz2ExPv9paJb622OOk+o4bWnjDe1zHGK6qnK25mMT
|
|
||||||
Zldk74sXF+Wfr9lbwqHTcjGhQFwmVDqvtr55KVX8FOv0CSqNaewOrnNrFz8Xg4rn
|
|
||||||
OlIs3+MmqD5CIK+el0rA+xltEY8WvNlwZKG7yeJYrdsr+5DAThDuwCVe8bU7it4h
|
|
||||||
sjsMsof5ocee9zDkFThNVGR4sMk5EgBxb1Gt4n9wXUj4OBT78whhlkLH/pVZrrhs
|
|
||||||
tQwC3q90MOPC5RJcEolSCNjGdHCKRbexmRqJgbJj/qZ9JT+fQ+Ko6a+UAWvc2BUc
|
|
||||||
POnzGV2GzCdFFGOubJb6RjU0nuPG4Lmdc/BuS9kFAgMBAAGjggNkMIIDYDAfBgNV
|
|
||||||
HSMEGDAWgBTnAfwMFhjKfbKM7Icno29hgTuEOTAdBgNVHQ4EFgQUNb1SY8Bkil98
|
|
||||||
tD8zoxE30jBA1NIwZwYDVR0RBGAwXoIQc2NodW5rLWdyb3VwLmNvbYIUd3d3LnNj
|
|
||||||
aHVuay1ncm91cC5jb22CG3NjaHVuay1jYXJib250ZWNobm9sb2d5LmNvbYIXc2No
|
|
||||||
dW5rLXNpbnRlcm1ldGFscy5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG
|
|
||||||
CCsGAQUFBwMBBggrBgEFBQcDAjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY2Rw
|
|
||||||
LnRoYXd0ZS5jb20vVGhhd3RlRVZSU0FDQTIwMTguY3JsMEsGA1UdIAREMEIwNwYJ
|
|
||||||
YIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv
|
|
||||||
bS9DUFMwBwYFZ4EMAQEwcQYIKwYBBQUHAQEEZTBjMCQGCCsGAQUFBzABhhhodHRw
|
|
||||||
Oi8vc3RhdHVzLnRoYXd0ZS5jb20wOwYIKwYBBQUHMAKGL2h0dHA6Ly9jYWNlcnRz
|
|
||||||
LnRoYXd0ZS5jb20vVGhhd3RlRVZSU0FDQTIwMTguY3J0MAkGA1UdEwQCMAAwggF7
|
|
||||||
BgorBgEEAdZ5AgQCBIIBawSCAWcBZQB1AKS5CZC0GFgUh7sTosxncAo8NZgE+Rvf
|
|
||||||
uON3zQ7IDdwQAAABY6Ze9XAAAAQDAEYwRAIgNUeXL3GwlpGQtTS/wKBlOkHJvHR5
|
|
||||||
knSop0OPumeCfQECIEdxY7qr/WRVbWkQFvP48fgWkZHkd4vTq70Y0aaSZTbPAHUA
|
|
||||||
VhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0AAAFjpl71tQAABAMARjBE
|
|
||||||
AiAtxKdc/wum3TE7r9BoRd/gkrjYLWyqeLuL/opRBRy9xwIgPF6uEZxyhEoLZ+9G
|
|
||||||
AFBAP+X89zjZphVALjIXu0RRea4AdQC72d+8H4pxtZOUI5eqkntHOFeVCqtS6BqQ
|
|
||||||
lmQ2jh7RhQAAAWOmXvY1AAAEAwBGMEQCIHc04ERlUbIkVrlC+I89C9xtugvRCwbR
|
|
||||||
a7qZzSdqHltUAiBRVwTacf1dnO9AgLSgrxft5LV32DvH3qNT7pWYh8dFNjANBgkq
|
|
||||||
hkiG9w0BAQsFAAOCAQEARJ+tbnM+yS6chgpyzfB3e7IWPq2Den46Ja1H6/4qaKrd
|
|
||||||
nsbElcvd4cCQf1zYY6jlQkO6qtfMUChKrEar5aqqnyX8x/8T9PkpHp8XyUxgGlmT
|
|
||||||
hrnHML0gDJFS8O4MB5pFnGkgoOQa+OIQokWCXr4/a4AwsTG3Ms+lC+R+vRYz90lg
|
|
||||||
TEJLNHB2fSvQyvpXDUL9aAjACBp/9pKxfM9iq06MFO5jP483xJUfdqtVteHMw75w
|
|
||||||
1mb8IrM9R1dP47GsblTrf2rZYdaoxdyLjtJQG2aaOdU5unE6QeFrXbz0qeTPePs8
|
|
||||||
ftuXSW9xb053HjAkCcVo48j07b2cHfU1hxzGGptVbQ==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
Binary file not shown.
@@ -1,27 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEkDCCA3igAwIBAgIJIrmxUyPlrv3NMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
|
|
||||||
BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw
|
|
||||||
JQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTIwHhcNMTgwODIy
|
|
||||||
MDczMjI0WhcNMjgwODIyMDczMjI0WjBQMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
|
|
||||||
U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEaMBgGA1UEAxMRQ3Jvc3NUcnVz
|
|
||||||
dCBEViBDQTUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCnTNi5Kgrt
|
|
||||||
FL8qBuEmpL2gvLFY7f9MEgjzClvic/45ebM+DxZ2CMuqtMtImgf8XPIpLaFFbozx
|
|
||||||
3VgqH41cmGHbpAoDRKpwfF1f53peHYhRxpOVgcnsiVCPZJPBPCUM9St+cuEjfo0d
|
|
||||||
YGbr3aG5urdT2zeKIFyxKbggdkU0LVRHwvLFsIpXCn/YK/8Rmx87yW9VB80OXkzf
|
|
||||||
IQoZop83+aebq1VwzjNCN3u4bWSFLYDyJGqE40WlZ53NZh+TwBsa6gld9YXPGQfx
|
|
||||||
k8x38zkFXberlMQOYhX9KyuTOMdlFkbx6LfIUqVKJavpcr54+XPzVyeroNPpKxtZ
|
|
||||||
mEqUYiFjAqUVAgMBAAGjggFeMIIBWjAdBgNVHQ4EFgQUT4twz6lAHJbllF13rNZv
|
|
||||||
TS2b8ncwHwYDVR0jBBgwFoAUCoWpd2UFmHxAgfgPlyw48QrsPM8wEgYDVR0TAQH/
|
|
||||||
BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwSQYDVR0fBEIwQDA+oDygOoY4aHR0
|
|
||||||
cDovL3JlcG9zaXRvcnkuc2Vjb210cnVzdC5uZXQvU0MtUm9vdDIvU0NSb290MkNS
|
|
||||||
TC5jcmwwUgYDVR0gBEswSTBHBgoqgwiMmxtkhwUEMDkwNwYIKwYBBQUHAgEWK2h0
|
|
||||||
dHBzOi8vcmVwb3NpdG9yeS5zZWNvbXRydXN0Lm5ldC9TQy1Sb290Mi8wQAYIKwYB
|
|
||||||
BQUHAQEENDAyMDAGCCsGAQUFBzABhiRodHRwOi8vc2Nyb290Y2EyLm9jc3Auc2Vj
|
|
||||||
b210cnVzdC5uZXQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQAD
|
|
||||||
ggEBABEDSrrhhR+Js5q45yih2Ne4cMLZmrH0AZwU3eM+7HZplzi1EhppgvcYk/2k
|
|
||||||
LM9haQGWnAZ5wiixLqKu7WlWrHgblZbXyCxALmMBK1rqeP0omxXExqKVqWNHU8KZ
|
|
||||||
t3jahH1wDYSzfetM7guWR+PAPpb9oQCtAx8DVyI/3Ocswvti/uWb517Bdo6Nd0+9
|
|
||||||
mf0LiphNKcSzSFX0s1Cb47cJROYHGBe2J6NUSWR7wE0asPtKsznGyNO+NJCUR+0h
|
|
||||||
OLN2cA2KJwPhZjYJt8UkucAF/EE7qC0Fc8B9Q/gttQ52en5BZxdkDrHCi4qnsSvi
|
|
||||||
gueQme/RzYkEaQlNT1WCZ9AIgVE=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIF4DCCBMigAwIBAgIQC3d196+a5UJlyc0yVxB3jjANBgkqhkiG9w0BAQsFADBQ
|
|
||||||
MQswCQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4s
|
|
||||||
TFRELjEaMBgGA1UEAxMRQ3Jvc3NUcnVzdCBEViBDQTUwHhcNMTkwNjExMDUyMjEy
|
|
||||||
WhcNMjEwNjMwMTQ1OTU5WjAUMRIwEAYDVQQDEwlza3luZXcuanAwggEiMA0GCSqG
|
|
||||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeciw7C297026HA4oIwc29vL2h29GVrRF7
|
|
||||||
HGdeXzAJA7kh+qwo8rTBFfdX7sgHy6nnE1+flEtFt91Ss8i3BZMEqoFUZFb1jGXd
|
|
||||||
DbQtmIWxz7O5skkjR1gdKwt9GImy1hEPt8dwU52mwVsSUEKvlZlsjeofUPAEbnYY
|
|
||||||
+iA/nYaYXiXyCxJzk6Y09VlzghyMIhkLwDa7rL3S9FgUQI6tSUwsiNYNoQzlYgXF
|
|
||||||
yPfQfd57LbBwZJtqVPC6rjPOZZd0sw7uvrDNuxnAM2k2mzlML9Vwt8EvSlZX60xD
|
|
||||||
oGQCsQQ/ZgjEQTA8WRZ+fxW/LqQNYYm70KU/1M+e8o4MKmA9xkH5AgMBAAGjggLw
|
|
||||||
MIIC7DAfBgNVHSMEGDAWgBRPi3DPqUAcluWUXXes1m9NLZvydzA8BggrBgEFBQcB
|
|
||||||
AQQwMC4wLAYIKwYBBQUHMAGGIGh0dHA6Ly9kdmNhNS5vY3NwLnNlY29tdHJ1c3Qu
|
|
||||||
bmV0MCMGA1UdEQQcMBqCCXNreW5ldy5qcIINd3d3LnNreW5ldy5qcDBaBgNVHSAE
|
|
||||||
UzBRMEUGCiqDCIybG26BVQIwNzA1BggrBgEFBQcCARYpaHR0cHM6Ly9yZXBvMS5z
|
|
||||||
ZWNvbXRydXN0Lm5ldC9zcHBjYS94dGR2NS8wCAYGZ4EMAQIBMBMGA1UdJQQMMAoG
|
|
||||||
CCsGAQUFBwMBMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9yZXBvMS5zZWNvbXRy
|
|
||||||
dXN0Lm5ldC9zcHBjYS94dGR2NS9mdWxsY3JsLmNybDAdBgNVHQ4EFgQUuj9305tQ
|
|
||||||
JIeVAQtsz9JHx3PTqaQwDgYDVR0PAQH/BAQDAgWgMIIBfgYKKwYBBAHWeQIEAgSC
|
|
||||||
AW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWtF
|
|
||||||
Bb6pAAAEAwBHMEUCIHUQkmFzUh01r1Px/zWMZSL21dNNQwM+rN1z0gutxV3JAiEA
|
|
||||||
jSb2/GAm4+2qiNWDtx1EkHsMXjNW+5S4GhJePexjJR8AdgDuS723dc5guuFCaR+r
|
|
||||||
4Z5mow9+X7By2IMAxHuJeqj9ywAAAWtFBcdeAAAEAwBHMEUCIDVHdfP9wnVgz45l
|
|
||||||
eX80DpRCRNEV/OCDwfW+B0g/dveYAiEArbpLQb5Z9hul3r00kF2LrivNuI7kwEBy
|
|
||||||
MpkYsLtSPJoAdgBvU3asMfAxGdiZAKRRFf93FRwR2QLBACkGjbIImjfZEwAAAWtF
|
|
||||||
BdCQAAAEAwBHMEUCIE2GUo6x3qDrIhacnCmjikBCHF2yT6Fv5GAehZB569YCAiEA
|
|
||||||
vXwMXV8+y3xNFys+A6u9EjKiy8CTKv+SQxqsJ4s6jK0wDQYJKoZIhvcNAQELBQAD
|
|
||||||
ggEBAAzlm9W+N5fviTJ9wDsc5nXKYur3744V/cm75+8dUM61Rko1isK6IZt5aNPN
|
|
||||||
wOfhBsTzHHSYmAFMR9Xjoq8iDYZtIk01IGI6LEWuls9F2hVcERiHMWJOLTiH35xN
|
|
||||||
vRNTG0AbBdIpTX2sURsoCPJ+8DTnVUr3pTzXnIY4EQ4UXfANuYwceOHShF6UJo/L
|
|
||||||
PK0uRdHcd5SmMa03gFUdkTc9gU6PIEO/UgubazGh9xDBHtHECeleL+gpSfOP3SkF
|
|
||||||
7W1RgmbE6WJdVPlto7FRQtl2xIzHs/gNaPezqNKPHgFlx4c+ECTjPLqoW8LdeXu+
|
|
||||||
N8dueJg1+h+lQifkmgl23DqEIiI=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/* -*- 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/. */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// This file tests that cert_storage correctly persists its information across
|
|
||||||
// runs of the browser specifically in the case of CRLite.
|
|
||||||
// (The test DB files for this test were created by running the test
|
|
||||||
// `test_cert_storage_direct.js` and copying them from that test's profile
|
|
||||||
// directory.)
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
add_task(async function () {
|
|
||||||
Services.prefs.setIntPref(
|
|
||||||
"security.pki.crlite_mode",
|
|
||||||
CRLiteModeEnforcePrefValue
|
|
||||||
);
|
|
||||||
|
|
||||||
let dbDirectory = do_get_profile();
|
|
||||||
dbDirectory.append("security_state");
|
|
||||||
let crliteFile = do_get_file(
|
|
||||||
"test_cert_storage_preexisting_crlite/crlite.filter"
|
|
||||||
);
|
|
||||||
crliteFile.copyTo(dbDirectory, "crlite.filter");
|
|
||||||
let coverageFile = do_get_file(
|
|
||||||
"test_cert_storage_preexisting_crlite/crlite.coverage"
|
|
||||||
);
|
|
||||||
coverageFile.copyTo(dbDirectory, "crlite.coverage");
|
|
||||||
let enrollmentFile = do_get_file(
|
|
||||||
"test_cert_storage_preexisting_crlite/crlite.enrollment"
|
|
||||||
);
|
|
||||||
enrollmentFile.copyTo(dbDirectory, "crlite.enrollment");
|
|
||||||
|
|
||||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
|
||||||
Ci.nsICertStorage
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
|
||||||
Ci.nsIX509CertDB
|
|
||||||
);
|
|
||||||
let validCertIssuer = constructCertFromFile(
|
|
||||||
"test_cert_storage_direct/valid-cert-issuer.pem"
|
|
||||||
);
|
|
||||||
let validCert = constructCertFromFile(
|
|
||||||
"test_cert_storage_direct/valid-cert.pem"
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
validCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-10-28T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"skynew.jp",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
|
|
||||||
let revokedCertIssuer = constructCertFromFile(
|
|
||||||
"test_cert_storage_direct/revoked-cert-issuer.pem"
|
|
||||||
);
|
|
||||||
let revokedCert = constructCertFromFile(
|
|
||||||
"test_cert_storage_direct/revoked-cert.pem"
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2019-11-04T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"schunk-group.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
});
|
|
||||||
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
3)<29><11><0E><08>:<3A>f<EFBFBD><66>v<1E><> 0<><13><><14><>y<>Q<EFBFBD><51><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jf<14><><EFBFBD><EFBFBD><EFBFBD>@(,v<17>~;<3B>P<EFBFBD>;ҧm<D2A7><6D>ځb<DA81>g<>t<EFBFBD>(M<>T<><54>NTbk<62>ڠ$
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
Binary file not shown.
@@ -1,2 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,17 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted coverage file. Specifically, this handles the case
|
|
||||||
// where the coverage file is missing.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = undefined;
|
|
||||||
let enrollment = do_get_file("test_crlite_preexisting/crlite.enrollment");
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted coverage file. Specifically, this handles the case
|
|
||||||
// where the coverage file is truncated in a LogID field.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = do_get_file("test_crlite_corrupted/trunc-log-id.coverage");
|
|
||||||
let enrollment = do_get_file("test_crlite_preexisting/crlite.enrollment");
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted coverage file. Specifically, this handles the case
|
|
||||||
// where the coverage file is truncated in a MinTimestamp field.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = do_get_file(
|
|
||||||
"test_crlite_corrupted/trunc-min-timestamp.coverage"
|
|
||||||
);
|
|
||||||
let enrollment = do_get_file("test_crlite_preexisting/crlite.enrollment");
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted coverage file. Specifically, this handles the case
|
|
||||||
// where the coverage file is truncated in a MaxTimestamp field.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = do_get_file(
|
|
||||||
"test_crlite_corrupted/trunc-max-timestamp.coverage"
|
|
||||||
);
|
|
||||||
let enrollment = do_get_file("test_crlite_preexisting/crlite.enrollment");
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted coverage file. Specifically, this handles the case
|
|
||||||
// where the coverage file's version is not recognized.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = do_get_file("test_crlite_corrupted/version-0.coverage");
|
|
||||||
let enrollment = do_get_file("test_crlite_preexisting/crlite.enrollment");
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted enrollment file. Specifically, this handles the case
|
|
||||||
// where the enrollment file is truncated in an issuer ID field.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = do_get_file("test_crlite_preexisting/crlite.coverage");
|
|
||||||
let enrollment = do_get_file(
|
|
||||||
"test_crlite_corrupted/trunc-issuer-id.enrollment"
|
|
||||||
);
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted enrollment file. Specifically, this handles the case
|
|
||||||
// where the enrollment file's version is not recognized.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = do_get_file("test_crlite_preexisting/crlite.coverage");
|
|
||||||
let enrollment = do_get_file("test_crlite_corrupted/version-0.enrollment");
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted filter file.
|
|
||||||
//
|
|
||||||
// There are many ways that a filter file could be corrupted, but the parsing
|
|
||||||
// is done in rust-cascade, not cert_storage, so it is sufficient for us to
|
|
||||||
// test any form of corruption here. For simplicity we just try to load a
|
|
||||||
// single \x00 byte as the filter.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let coverage = do_get_file("test_crlite_preexisting/crlite.coverage");
|
|
||||||
let enrollment = do_get_file("test_crlite_preexisting/crlite.enrollment");
|
|
||||||
let filter = do_get_file("test_crlite_corrupted/hash-alg-0.filter");
|
|
||||||
|
|
||||||
load("./corrupted_crlite_helper.js");
|
|
||||||
@@ -49,7 +49,6 @@
|
|||||||
// "MinEntry": 0
|
// "MinEntry": 0
|
||||||
// }]
|
// }]
|
||||||
//
|
//
|
||||||
// $ rust-create-cascade --filter-type cascade --known ./known/ --revoked ./revoked --outdir ./cascade
|
|
||||||
// $ rust-create-cascade --filter-type clubcard --ct-logs-json ./ct-logs.json --known ./known/ --revoked ./revoked --outdir ./clubcard
|
// $ rust-create-cascade --filter-type clubcard --ct-logs-json ./ct-logs.json --known ./known/ --revoked ./revoked --outdir ./clubcard
|
||||||
//
|
//
|
||||||
// Additional revoked certificates were then added to the /known/ and /revoked/
|
// Additional revoked certificates were then added to the /known/ and /revoked/
|
||||||
@@ -118,28 +117,14 @@ function getHash(aStr) {
|
|||||||
// Get the name of the file in the test directory to serve as the attachment
|
// Get the name of the file in the test directory to serve as the attachment
|
||||||
// for the given filter.
|
// for the given filter.
|
||||||
function getFilenameForFilter(filter) {
|
function getFilenameForFilter(filter) {
|
||||||
if (filter.type == "clubcard") {
|
if (filter.type == "filter") {
|
||||||
return "20201017-0-clubcard-filter";
|
|
||||||
}
|
|
||||||
if (filter.type == "cascade") {
|
|
||||||
return "20201017-0-filter";
|
return "20201017-0-filter";
|
||||||
}
|
}
|
||||||
if (filter.id == "0001") {
|
if (filter.id == "0001") {
|
||||||
return "20201017-1-filter.stash";
|
|
||||||
}
|
|
||||||
if (filter.id == "1000") {
|
|
||||||
return "20201017-1-filter.delta";
|
return "20201017-1-filter.delta";
|
||||||
}
|
}
|
||||||
if (filter.id == "2000") {
|
|
||||||
return "20201201-3-filter.delta";
|
return "20201201-3-filter.delta";
|
||||||
}
|
}
|
||||||
// The addition of another stash file was written more than a month after
|
|
||||||
// other parts of this test. As such, the second stash file for October 17th,
|
|
||||||
// 2020 was not readily available. Since the structure of stash files don't
|
|
||||||
// depend on each other, though, any two stash files are compatible, and so
|
|
||||||
// this stash from December 1st is used instead.
|
|
||||||
return "20201201-3-filter.stash";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate a Remote Settings synchronization by filling up the local data with
|
* Simulate a Remote Settings synchronization by filling up the local data with
|
||||||
@@ -217,7 +202,7 @@ add_task(async function test_crlite_filters_disabled() {
|
|||||||
let result = await syncAndDownload([
|
let result = await syncAndDownload([
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-01T00:00:00Z",
|
timestamp: "2019-01-01T00:00:00Z",
|
||||||
type: "cascade",
|
type: "filter",
|
||||||
id: "0000",
|
id: "0000",
|
||||||
coverage: [
|
coverage: [
|
||||||
{
|
{
|
||||||
@@ -250,7 +235,7 @@ add_task(async function test_crlite_no_filters_in_channel() {
|
|||||||
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
||||||
|
|
||||||
let result = await syncAndDownload(
|
let result = await syncAndDownload(
|
||||||
[{ timestamp: "2019-01-01T00:00:00Z", type: "cascade", id: "0000" }],
|
[{ timestamp: "2019-01-01T00:00:00Z", type: "filter", id: "0000" }],
|
||||||
true,
|
true,
|
||||||
"other"
|
"other"
|
||||||
);
|
);
|
||||||
@@ -299,7 +284,7 @@ add_task(async function test_crlite_incremental_filters_with_wrong_parent() {
|
|||||||
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
||||||
|
|
||||||
let result = await syncAndDownload([
|
let result = await syncAndDownload([
|
||||||
{ timestamp: "2019-01-01T00:00:00Z", type: "cascade", id: "0000" },
|
{ timestamp: "2019-01-01T00:00:00Z", type: "filter", id: "0000" },
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-01T06:00:00Z",
|
timestamp: "2019-01-01T06:00:00Z",
|
||||||
type: "diff",
|
type: "diff",
|
||||||
@@ -320,7 +305,7 @@ add_task(async function test_crlite_incremental_filters_with_wrong_parent() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expectDownloads(result, [
|
expectDownloads(result, [
|
||||||
"2019-01-01T00:00:00Z-cascade",
|
"2019-01-01T00:00:00Z-filter",
|
||||||
"2019-01-01T06:00:00Z-diff",
|
"2019-01-01T06:00:00Z-diff",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -331,7 +316,7 @@ add_task(async function test_crlite_incremental_filter_too_early() {
|
|||||||
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
||||||
|
|
||||||
let result = await syncAndDownload([
|
let result = await syncAndDownload([
|
||||||
{ timestamp: "2019-01-02T00:00:00Z", type: "cascade", id: "0000" },
|
{ timestamp: "2019-01-02T00:00:00Z", type: "filter", id: "0000" },
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-01T00:00:00Z",
|
timestamp: "2019-01-01T00:00:00Z",
|
||||||
type: "diff",
|
type: "diff",
|
||||||
@@ -341,7 +326,7 @@ add_task(async function test_crlite_incremental_filter_too_early() {
|
|||||||
]);
|
]);
|
||||||
equal(
|
equal(
|
||||||
result,
|
result,
|
||||||
"finished;2019-01-02T00:00:00Z-cascade",
|
"finished;2019-01-02T00:00:00Z-filter",
|
||||||
"CRLite filter download should have run"
|
"CRLite filter download should have run"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -352,11 +337,11 @@ add_task(async function test_crlite_filters_basic() {
|
|||||||
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
||||||
|
|
||||||
let result = await syncAndDownload([
|
let result = await syncAndDownload([
|
||||||
{ timestamp: "2019-01-01T00:00:00Z", type: "cascade", id: "0000" },
|
{ timestamp: "2019-01-01T00:00:00Z", type: "filter", id: "0000" },
|
||||||
]);
|
]);
|
||||||
equal(
|
equal(
|
||||||
result,
|
result,
|
||||||
"finished;2019-01-01T00:00:00Z-cascade",
|
"finished;2019-01-01T00:00:00Z-filter",
|
||||||
"CRLite filter download should have run"
|
"CRLite filter download should have run"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -366,12 +351,12 @@ add_task(async function test_crlite_filters_basic() {
|
|||||||
add_task(async function test_crlite_filters_not_cached() {
|
add_task(async function test_crlite_filters_not_cached() {
|
||||||
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
||||||
let filters = [
|
let filters = [
|
||||||
{ timestamp: "2019-01-01T00:00:00Z", type: "cascade", id: "0000" },
|
{ timestamp: "2019-01-01T00:00:00Z", type: "filter", id: "0000" },
|
||||||
];
|
];
|
||||||
let result = await syncAndDownload(filters);
|
let result = await syncAndDownload(filters);
|
||||||
equal(
|
equal(
|
||||||
result,
|
result,
|
||||||
"finished;2019-01-01T00:00:00Z-cascade",
|
"finished;2019-01-01T00:00:00Z-filter",
|
||||||
"CRLite filter download should have run"
|
"CRLite filter download should have run"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -399,7 +384,7 @@ add_task(async function test_crlite_filters_full_and_incremental() {
|
|||||||
id: "0001",
|
id: "0001",
|
||||||
parent: "0000",
|
parent: "0000",
|
||||||
},
|
},
|
||||||
{ timestamp: "2019-01-01T00:00:00Z", type: "cascade", id: "0000" },
|
{ timestamp: "2019-01-01T00:00:00Z", type: "filter", id: "0000" },
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-01T18:00:00Z",
|
timestamp: "2019-01-01T18:00:00Z",
|
||||||
type: "diff",
|
type: "diff",
|
||||||
@@ -414,7 +399,7 @@ add_task(async function test_crlite_filters_full_and_incremental() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expectDownloads(result, [
|
expectDownloads(result, [
|
||||||
"2019-01-01T00:00:00Z-cascade",
|
"2019-01-01T00:00:00Z-filter",
|
||||||
"2019-01-01T06:00:00Z-diff",
|
"2019-01-01T06:00:00Z-diff",
|
||||||
"2019-01-01T12:00:00Z-diff",
|
"2019-01-01T12:00:00Z-diff",
|
||||||
"2019-01-01T18:00:00Z-diff",
|
"2019-01-01T18:00:00Z-diff",
|
||||||
@@ -458,8 +443,8 @@ add_task(async function test_crlite_filters_multiple_days() {
|
|||||||
id: "0013",
|
id: "0013",
|
||||||
parent: "0012",
|
parent: "0012",
|
||||||
},
|
},
|
||||||
{ timestamp: "2019-01-02T00:00:00Z", type: "cascade", id: "0010" },
|
{ timestamp: "2019-01-02T00:00:00Z", type: "filter", id: "0010" },
|
||||||
{ timestamp: "2019-01-03T00:00:00Z", type: "cascade", id: "0020" },
|
{ timestamp: "2019-01-03T00:00:00Z", type: "filter", id: "0020" },
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-01T06:00:00Z",
|
timestamp: "2019-01-01T06:00:00Z",
|
||||||
type: "diff",
|
type: "diff",
|
||||||
@@ -478,7 +463,7 @@ add_task(async function test_crlite_filters_multiple_days() {
|
|||||||
id: "0002",
|
id: "0002",
|
||||||
parent: "0001",
|
parent: "0001",
|
||||||
},
|
},
|
||||||
{ timestamp: "2019-01-01T00:00:00Z", type: "cascade", id: "0000" },
|
{ timestamp: "2019-01-01T00:00:00Z", type: "filter", id: "0000" },
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-03T06:00:00Z",
|
timestamp: "2019-01-03T06:00:00Z",
|
||||||
type: "diff",
|
type: "diff",
|
||||||
@@ -487,7 +472,7 @@ add_task(async function test_crlite_filters_multiple_days() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expectDownloads(result, [
|
expectDownloads(result, [
|
||||||
"2019-01-03T00:00:00Z-cascade",
|
"2019-01-03T00:00:00Z-filter",
|
||||||
"2019-01-03T06:00:00Z-diff",
|
"2019-01-03T06:00:00Z-diff",
|
||||||
"2019-01-03T12:00:00Z-diff",
|
"2019-01-03T12:00:00Z-diff",
|
||||||
"2019-01-03T18:00:00Z-diff",
|
"2019-01-03T18:00:00Z-diff",
|
||||||
@@ -513,7 +498,7 @@ add_task(async function test_crlite_confirm_revocations_mode() {
|
|||||||
let result = await syncAndDownload([
|
let result = await syncAndDownload([
|
||||||
{
|
{
|
||||||
timestamp: "2020-10-17T00:00:00Z",
|
timestamp: "2020-10-17T00:00:00Z",
|
||||||
type: "cascade",
|
type: "filter",
|
||||||
id: "0000",
|
id: "0000",
|
||||||
coverage: [
|
coverage: [
|
||||||
{
|
{
|
||||||
@@ -532,7 +517,7 @@ add_task(async function test_crlite_confirm_revocations_mode() {
|
|||||||
]);
|
]);
|
||||||
equal(
|
equal(
|
||||||
result,
|
result,
|
||||||
"finished;2020-10-17T00:00:00Z-cascade",
|
"finished;2020-10-17T00:00:00Z-filter",
|
||||||
"CRLite filter download should have run"
|
"CRLite filter download should have run"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -565,39 +550,10 @@ add_task(async function test_crlite_confirm_revocations_mode() {
|
|||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reload the filter w/o coverage and enrollment metadata.
|
|
||||||
result = await syncAndDownload([
|
|
||||||
{
|
|
||||||
timestamp: "2020-10-17T00:00:00Z",
|
|
||||||
type: "cascade",
|
|
||||||
id: "0000",
|
|
||||||
coverage: [],
|
|
||||||
enrolledIssuers: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
equal(
|
|
||||||
result,
|
|
||||||
"finished;2020-10-17T00:00:00Z-cascade",
|
|
||||||
"CRLite filter download should have run"
|
|
||||||
);
|
|
||||||
|
|
||||||
// OCSP will be consulted for the revoked certificate, but a soft-failure
|
|
||||||
// should now result in a Success return.
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2020-10-20T00:00:00Z").getTime() / 1000,
|
|
||||||
undefined,
|
|
||||||
"us-datarecovery.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
|
|
||||||
await syncAndDownload([], true);
|
await syncAndDownload([], true);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function test_crlite_filters_and_check_revocation(filter_type) {
|
add_task(async function test_crlite_filters_and_check_revocation() {
|
||||||
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
||||||
Services.prefs.setIntPref(
|
Services.prefs.setIntPref(
|
||||||
"security.pki.crlite_mode",
|
"security.pki.crlite_mode",
|
||||||
@@ -614,32 +570,13 @@ async function test_crlite_filters_and_check_revocation(filter_type) {
|
|||||||
let result = await syncAndDownload([
|
let result = await syncAndDownload([
|
||||||
{
|
{
|
||||||
timestamp: "2020-10-17T00:00:00Z",
|
timestamp: "2020-10-17T00:00:00Z",
|
||||||
type: filter_type,
|
type: "filter",
|
||||||
id: "0000",
|
id: "0000",
|
||||||
coverage:
|
|
||||||
filter_type == "clubcard"
|
|
||||||
? undefined
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
logID: "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
|
|
||||||
minTimestamp: 0,
|
|
||||||
maxTimestamp: 9999999999999,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
logID: "pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA=",
|
|
||||||
minTimestamp: 0,
|
|
||||||
maxTimestamp: 9999999999999,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
enrolledIssuers:
|
|
||||||
filter_type == "clubcard"
|
|
||||||
? undefined
|
|
||||||
: [ISSUER_PEM_UID, NO_SCT_ISSUER_PEM_UID],
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
equal(
|
equal(
|
||||||
result,
|
result,
|
||||||
`finished;2020-10-17T00:00:00Z-${filter_type}`,
|
`finished;2020-10-17T00:00:00Z-filter`,
|
||||||
"CRLite filter download should have run"
|
"CRLite filter download should have run"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -692,7 +629,7 @@ async function test_crlite_filters_and_check_revocation(filter_type) {
|
|||||||
{
|
{
|
||||||
timestamp: "2020-10-17T03:00:00Z",
|
timestamp: "2020-10-17T03:00:00Z",
|
||||||
type: "diff",
|
type: "diff",
|
||||||
id: filter_type == "clubcard" ? "1000" : "0001",
|
id: "0001",
|
||||||
parent: "0000",
|
parent: "0000",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -736,8 +673,8 @@ async function test_crlite_filters_and_check_revocation(filter_type) {
|
|||||||
{
|
{
|
||||||
timestamp: "2020-10-17T06:00:00Z",
|
timestamp: "2020-10-17T06:00:00Z",
|
||||||
type: "diff",
|
type: "diff",
|
||||||
id: filter_type == "clubcard" ? "2000" : "0002",
|
id: "0002",
|
||||||
parent: filter_type == "clubcard" ? "1000" : "0001",
|
parent: "0001",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
false
|
false
|
||||||
@@ -840,123 +777,6 @@ async function test_crlite_filters_and_check_revocation(filter_type) {
|
|||||||
Services.prefs.clearUserPref("security.OCSP.require");
|
Services.prefs.clearUserPref("security.OCSP.require");
|
||||||
Services.prefs.clearUserPref("security.OCSP.enabled");
|
Services.prefs.clearUserPref("security.OCSP.enabled");
|
||||||
|
|
||||||
// The revoked certificate example has one SCT from the log with ID "9ly...="
|
|
||||||
// at time 1598140096613 and another from the log with ID "XNx...=" at time
|
|
||||||
// 1598140096917. The filter we construct here fails to cover it by one
|
|
||||||
// millisecond in each case. The implementation will fall back to OCSP
|
|
||||||
// fetching. Since this would result in a crash and test failure, the
|
|
||||||
// Ci.nsIX509CertDB.FLAG_LOCAL_ONLY is used.
|
|
||||||
result = await syncAndDownload([
|
|
||||||
{
|
|
||||||
timestamp: "2020-10-17T00:00:00Z",
|
|
||||||
type: "cascade",
|
|
||||||
id: "0000",
|
|
||||||
coverage: [
|
|
||||||
{
|
|
||||||
logID: "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
|
|
||||||
minTimestamp: 0,
|
|
||||||
maxTimestamp: 1598140096612,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
logID: "XNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbHDso=",
|
|
||||||
minTimestamp: 1598140096917,
|
|
||||||
maxTimestamp: 9999999999999,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
enrolledIssuers: [ISSUER_PEM_UID, NO_SCT_ISSUER_PEM_UID],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
equal(
|
|
||||||
result,
|
|
||||||
"finished;2020-10-17T00:00:00Z-cascade",
|
|
||||||
"CRLite filter download should have run"
|
|
||||||
);
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2020-10-20T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"us-datarecovery.com",
|
|
||||||
Ci.nsIX509CertDB.FLAG_LOCAL_ONLY
|
|
||||||
);
|
|
||||||
|
|
||||||
await syncAndDownload([], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
add_task(async function test_crlite_cascade_filter() {
|
|
||||||
await test_crlite_filters_and_check_revocation("cascade");
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_crlite_clubcard_filter() {
|
|
||||||
await test_crlite_filters_and_check_revocation("clubcard");
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_crlite_clubcard_bad_coverage_in_remote_settings() {
|
|
||||||
Services.prefs.setBoolPref(CRLITE_FILTERS_ENABLED_PREF, true);
|
|
||||||
Services.prefs.setIntPref(
|
|
||||||
"security.pki.crlite_mode",
|
|
||||||
CRLiteModeEnforcePrefValue
|
|
||||||
);
|
|
||||||
Services.prefs.setBoolPref(INTERMEDIATES_ENABLED_PREF, true);
|
|
||||||
|
|
||||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
|
||||||
Ci.nsIX509CertDB
|
|
||||||
);
|
|
||||||
addCertFromFile(certdb, "test_crlite_filters/issuer.pem", ",,");
|
|
||||||
addCertFromFile(certdb, "test_crlite_filters/no-sct-issuer.pem", ",,");
|
|
||||||
|
|
||||||
let result = await syncAndDownload([
|
|
||||||
{
|
|
||||||
timestamp: "2020-10-17T00:00:00Z",
|
|
||||||
type: "clubcard",
|
|
||||||
id: "0000",
|
|
||||||
coverage: [
|
|
||||||
{
|
|
||||||
logID: "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
|
|
||||||
minTimestamp: 0,
|
|
||||||
maxTimestamp: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
logID: "pLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BA=",
|
|
||||||
minTimestamp: 0,
|
|
||||||
maxTimestamp: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
enrolledIssuers: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
equal(
|
|
||||||
result,
|
|
||||||
`finished;2020-10-17T00:00:00Z-clubcard`,
|
|
||||||
"CRLite filter download should have run"
|
|
||||||
);
|
|
||||||
|
|
||||||
let validCert = constructCertFromFile("test_crlite_filters/valid.pem");
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
validCert,
|
|
||||||
PRErrorCodeSuccess,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2020-10-20T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"vpn.worldofspeed.org",
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
let revokedCert = constructCertFromFile("test_crlite_filters/revoked.pem");
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2020-10-20T00:00:00Z").getTime() / 1000,
|
|
||||||
false,
|
|
||||||
"us-datarecovery.com",
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
await syncAndDownload([], true);
|
await syncAndDownload([], true);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -966,7 +786,7 @@ add_task(async function test_crlite_filters_avoid_reprocessing_filters() {
|
|||||||
let result = await syncAndDownload([
|
let result = await syncAndDownload([
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-01T00:00:00Z",
|
timestamp: "2019-01-01T00:00:00Z",
|
||||||
type: "cascade",
|
type: "filter",
|
||||||
id: "0000",
|
id: "0000",
|
||||||
coverage: [
|
coverage: [
|
||||||
{
|
{
|
||||||
@@ -997,7 +817,7 @@ add_task(async function test_crlite_filters_avoid_reprocessing_filters() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expectDownloads(result, [
|
expectDownloads(result, [
|
||||||
"2019-01-01T00:00:00Z-cascade",
|
"2019-01-01T00:00:00Z-filter",
|
||||||
"2019-01-01T06:00:00Z-diff",
|
"2019-01-01T06:00:00Z-diff",
|
||||||
"2019-01-01T12:00:00Z-diff",
|
"2019-01-01T12:00:00Z-diff",
|
||||||
"2019-01-01T18:00:00Z-diff",
|
"2019-01-01T18:00:00Z-diff",
|
||||||
@@ -1038,7 +858,7 @@ add_task(
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
timestamp: "2019-01-01T00:00:00Z",
|
timestamp: "2019-01-01T00:00:00Z",
|
||||||
type: "cascade",
|
type: "filter",
|
||||||
id: "0000",
|
id: "0000",
|
||||||
coverage: [
|
coverage: [
|
||||||
{
|
{
|
||||||
@@ -1060,7 +880,7 @@ add_task(
|
|||||||
"specified"
|
"specified"
|
||||||
);
|
);
|
||||||
expectDownloads(result, [
|
expectDownloads(result, [
|
||||||
"2019-01-01T00:00:00Z-cascade",
|
"2019-01-01T00:00:00Z-filter",
|
||||||
"2019-01-01T06:00:00Z-diff",
|
"2019-01-01T06:00:00Z-diff",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -1070,7 +890,7 @@ add_task(
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
timestamp: "2020-01-01T00:00:00Z",
|
timestamp: "2020-01-01T00:00:00Z",
|
||||||
type: "cascade",
|
type: "filter",
|
||||||
id: "0002",
|
id: "0002",
|
||||||
coverage: [
|
coverage: [
|
||||||
{
|
{
|
||||||
@@ -1099,7 +919,7 @@ add_task(
|
|||||||
Services.prefs.setStringPref(CRLITE_FILTER_CHANNEL_PREF, "priority");
|
Services.prefs.setStringPref(CRLITE_FILTER_CHANNEL_PREF, "priority");
|
||||||
result = await syncAndDownload([], false);
|
result = await syncAndDownload([], false);
|
||||||
expectDownloads(result, [
|
expectDownloads(result, [
|
||||||
"2020-01-01T00:00:00Z-cascade",
|
"2020-01-01T00:00:00Z-filter",
|
||||||
"2020-01-01T06:00:00Z-diff",
|
"2020-01-01T06:00:00Z-diff",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -1108,7 +928,7 @@ add_task(
|
|||||||
Services.prefs.setStringPref(CRLITE_FILTER_CHANNEL_PREF, "specified");
|
Services.prefs.setStringPref(CRLITE_FILTER_CHANNEL_PREF, "specified");
|
||||||
result = await syncAndDownload([], false);
|
result = await syncAndDownload([], false);
|
||||||
expectDownloads(result, [
|
expectDownloads(result, [
|
||||||
"2019-01-01T00:00:00Z-cascade",
|
"2019-01-01T00:00:00Z-filter",
|
||||||
"2019-01-01T06:00:00Z-diff",
|
"2019-01-01T06:00:00Z-diff",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -8,12 +8,31 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
add_task(async function test_preexisting_crlite_data() {
|
add_task(async function () {
|
||||||
Services.prefs.setIntPref(
|
Services.prefs.setIntPref(
|
||||||
"security.pki.crlite_mode",
|
"security.pki.crlite_mode",
|
||||||
CRLiteModeEnforcePrefValue
|
CRLiteModeEnforcePrefValue
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let securityStateDirectory = do_get_profile();
|
||||||
|
securityStateDirectory.append("security_state");
|
||||||
|
|
||||||
|
// For simplicity, re-use the filters from test_crlite_filters.js.
|
||||||
|
do_get_file("test_crlite_filters/20201017-0-filter").copyTo(
|
||||||
|
securityStateDirectory,
|
||||||
|
"crlite.filter"
|
||||||
|
);
|
||||||
|
|
||||||
|
do_get_file("test_crlite_filters/20201017-1-filter.delta").copyTo(
|
||||||
|
securityStateDirectory,
|
||||||
|
"20201017-1-filter.delta"
|
||||||
|
);
|
||||||
|
|
||||||
|
do_get_file("test_crlite_filters/20201201-3-filter.delta").copyTo(
|
||||||
|
securityStateDirectory,
|
||||||
|
"20201201-3-filter.delta"
|
||||||
|
);
|
||||||
|
|
||||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
||||||
Ci.nsICertStorage
|
Ci.nsICertStorage
|
||||||
);
|
);
|
||||||
@@ -21,65 +40,20 @@ add_task(async function test_preexisting_crlite_data() {
|
|||||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
||||||
Ci.nsIX509CertDB
|
Ci.nsIX509CertDB
|
||||||
);
|
);
|
||||||
// These need to be available to be able to find them during path building
|
|
||||||
// for certificate verification.
|
// This needs to be available for path building.
|
||||||
let issuerCert = constructCertFromFile("test_crlite_filters/issuer.pem");
|
let issuerCert = constructCertFromFile("test_crlite_filters/issuer.pem");
|
||||||
ok(issuerCert, "issuer certificate should decode successfully");
|
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");
|
// Mark CRLite filter as fresh
|
||||||
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,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
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 => {
|
await new Promise(resolve => {
|
||||||
certStorage.addCRLiteStash(new Uint8Array([]), (rv, _) => {
|
certStorage.testNoteCRLiteUpdateTime((rv, _) => {
|
||||||
Assert.equal(rv, Cr.NS_OK, "marked filter as fresh");
|
Assert.equal(rv, Cr.NS_OK, "marked filter as fresh");
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// NB: by not specifying Ci.nsIX509CertDB.FLAG_LOCAL_ONLY, this tests that
|
let validCert = constructCertFromFile("test_crlite_filters/valid.pem");
|
||||||
// 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,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
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(
|
await checkCertErrorGenericAtTime(
|
||||||
certdb,
|
certdb,
|
||||||
validCert,
|
validCert,
|
||||||
@@ -91,6 +65,7 @@ add_task(async function test_preexisting_crlite_data() {
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let revokedCert = constructCertFromFile("test_crlite_filters/revoked.pem");
|
||||||
await checkCertErrorGenericAtTime(
|
await checkCertErrorGenericAtTime(
|
||||||
certdb,
|
certdb,
|
||||||
revokedCert,
|
revokedCert,
|
||||||
@@ -105,17 +80,6 @@ add_task(async function test_preexisting_crlite_data() {
|
|||||||
let revokedInStashCert = constructCertFromFile(
|
let revokedInStashCert = constructCertFromFile(
|
||||||
"test_crlite_filters/revoked-in-stash.pem"
|
"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(
|
await checkCertErrorGenericAtTime(
|
||||||
certdb,
|
certdb,
|
||||||
revokedInStashCert,
|
revokedInStashCert,
|
||||||
@@ -140,69 +104,4 @@ add_task(async function test_preexisting_crlite_data() {
|
|||||||
"icsreps.com",
|
"icsreps.com",
|
||||||
0
|
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,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
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,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
3)<29><11><0E><08>:<3A>f<EFBFBD><66>v<1E><> 0<><13><><14><>y<>Q<EFBFBD><51><EFBFBD><EFBFBD>'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>jf<14><><EFBFBD><EFBFBD><EFBFBD>@(,v<17>~;<3B>P<EFBFBD>
|
|
||||||
Binary file not shown.
@@ -1,91 +0,0 @@
|
|||||||
// -*- 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 CRLite is left in the uninitialized state when the profile
|
|
||||||
// contains a corrupted stash file.
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
add_task(async function test_crlite_stash_corrupted() {
|
|
||||||
let securityStateDirectory = do_get_profile();
|
|
||||||
securityStateDirectory.append("security_state");
|
|
||||||
|
|
||||||
Services.prefs.setIntPref(
|
|
||||||
"security.pki.crlite_mode",
|
|
||||||
CRLiteModeEnforcePrefValue
|
|
||||||
);
|
|
||||||
|
|
||||||
let coverage = do_get_file("test_crlite_preexisting/crlite.coverage");
|
|
||||||
coverage.copyTo(securityStateDirectory, "crlite.coverage");
|
|
||||||
|
|
||||||
let enrollment = do_get_file("test_crlite_preexisting/crlite.enrollment");
|
|
||||||
enrollment.copyTo(securityStateDirectory, "crlite.enrollment");
|
|
||||||
|
|
||||||
let filter = do_get_file("test_crlite_filters/20201017-0-filter");
|
|
||||||
filter.copyTo(securityStateDirectory, "crlite.filter");
|
|
||||||
|
|
||||||
let stash = do_get_file("test_crlite_corrupted/bad.stash");
|
|
||||||
stash.copyTo(securityStateDirectory, "crlite.stash");
|
|
||||||
|
|
||||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
|
||||||
Ci.nsIX509CertDB
|
|
||||||
);
|
|
||||||
|
|
||||||
let certStorage = Cc["@mozilla.org/security/certstorage;1"].getService(
|
|
||||||
Ci.nsICertStorage
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// This certificate is revoked according to `test_crlite_filters/20201017-0-filter`.
|
|
||||||
// Its issuer is enrolled according to `test_crlite_preexisting/crlite.enrollment`,
|
|
||||||
// and it is covered according to `test_crlite_preexisting/crlite.coverage`.
|
|
||||||
let revokedCert = constructCertFromFile("test_crlite_filters/revoked.pem");
|
|
||||||
|
|
||||||
// The issuer's certificate needs to be available for path building.
|
|
||||||
let issuerCert = constructCertFromFile("test_crlite_filters/issuer.pem");
|
|
||||||
ok(issuerCert, "issuer certificate should decode successfully");
|
|
||||||
|
|
||||||
// Loading the stash should not have caused any problems, and `revokedCert`
|
|
||||||
// should be marked as revoked.
|
|
||||||
await checkCertErrorGenericAtTime(
|
|
||||||
certdb,
|
|
||||||
revokedCert,
|
|
||||||
SEC_ERROR_REVOKED_CERTIFICATE,
|
|
||||||
Ci.nsIX509CertDB.verifyUsageTLSServer,
|
|
||||||
new Date("2020-10-20T00:00:00Z").getTime() / 1000,
|
|
||||||
undefined,
|
|
||||||
"us-datarecovery.com",
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
let hasFilter = await new Promise(resolve => {
|
|
||||||
certStorage.hasPriorData(
|
|
||||||
Ci.nsICertStorage.DATA_TYPE_CRLITE_FILTER_FULL,
|
|
||||||
(rv, result) => {
|
|
||||||
Assert.equal(rv, Cr.NS_OK, "hasPriorData should succeed");
|
|
||||||
resolve(result);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
Assert.equal(hasFilter, true, "CRLite should have a filter");
|
|
||||||
});
|
|
||||||
@@ -7,7 +7,6 @@ prefs = [
|
|||||||
]
|
]
|
||||||
skip-if = ["os == 'win' && msix"] # https://bugzilla.mozilla.org/show_bug.cgi?id=1809477
|
skip-if = ["os == 'win' && msix"] # https://bugzilla.mozilla.org/show_bug.cgi?id=1809477
|
||||||
support-files = [
|
support-files = [
|
||||||
"corrupted_crlite_helper.js",
|
|
||||||
"bad_certs/**",
|
"bad_certs/**",
|
||||||
"ocsp_certs/**",
|
"ocsp_certs/**",
|
||||||
"test_baseline_requirements/**",
|
"test_baseline_requirements/**",
|
||||||
@@ -19,17 +18,13 @@ support-files = [
|
|||||||
"test_cert_overrides_read_only/**",
|
"test_cert_overrides_read_only/**",
|
||||||
"test_cert_sha1/**",
|
"test_cert_sha1/**",
|
||||||
"test_cert_signatures/**",
|
"test_cert_signatures/**",
|
||||||
"test_cert_storage_direct/**",
|
|
||||||
"test_cert_storage_preexisting/**",
|
"test_cert_storage_preexisting/**",
|
||||||
"test_cert_storage_preexisting_crlite/**",
|
|
||||||
"test_cert_trust/**",
|
"test_cert_trust/**",
|
||||||
"test_cert_utf8/**",
|
"test_cert_utf8/**",
|
||||||
"test_cert_version/**",
|
"test_cert_version/**",
|
||||||
"test_certDB_import/**",
|
"test_certDB_import/**",
|
||||||
"test_content_signing/**",
|
"test_content_signing/**",
|
||||||
"test_crlite_filters/**",
|
"test_crlite_filters/**",
|
||||||
"test_crlite_preexisting/**",
|
|
||||||
"test_crlite_corrupted/**",
|
|
||||||
"test_ct/**",
|
"test_ct/**",
|
||||||
"test_delegated_credentials/**",
|
"test_delegated_credentials/**",
|
||||||
"test_encrypted_client_hello/**",
|
"test_encrypted_client_hello/**",
|
||||||
@@ -126,10 +121,6 @@ tags = "addons psm blocklist"
|
|||||||
|
|
||||||
["test_cert_storage_preexisting.js"]
|
["test_cert_storage_preexisting.js"]
|
||||||
|
|
||||||
["test_cert_storage_preexisting_crlite.js"]
|
|
||||||
# This test cannot succeed on 32-bit platforms. See bugs 1546361 and 1548956.
|
|
||||||
skip-if = ["bits != 64"]
|
|
||||||
|
|
||||||
["test_cert_trust.js"]
|
["test_cert_trust.js"]
|
||||||
|
|
||||||
["test_cert_utf8.js"]
|
["test_cert_utf8.js"]
|
||||||
@@ -143,29 +134,11 @@ skip-if = ["condprof"]
|
|||||||
|
|
||||||
["test_content_signing.js"]
|
["test_content_signing.js"]
|
||||||
|
|
||||||
["test_crlite_coverage_missing.js"]
|
|
||||||
|
|
||||||
["test_crlite_coverage_trunc1.js"]
|
|
||||||
|
|
||||||
["test_crlite_coverage_trunc2.js"]
|
|
||||||
|
|
||||||
["test_crlite_coverage_trunc3.js"]
|
|
||||||
|
|
||||||
["test_crlite_coverage_version.js"]
|
|
||||||
|
|
||||||
["test_crlite_enrollment_trunc1.js"]
|
|
||||||
|
|
||||||
["test_crlite_enrollment_version.js"]
|
|
||||||
|
|
||||||
["test_crlite_filter_corrupted.js"]
|
|
||||||
|
|
||||||
["test_crlite_filters.js"]
|
["test_crlite_filters.js"]
|
||||||
tags = "remote-settings psm"
|
tags = "remote-settings psm"
|
||||||
|
|
||||||
["test_crlite_preexisting.js"]
|
["test_crlite_preexisting.js"]
|
||||||
|
|
||||||
["test_crlite_stash_corrupted.js"]
|
|
||||||
|
|
||||||
["test_ct.js"]
|
["test_ct.js"]
|
||||||
# Requires hard-coded debug-only data
|
# Requires hard-coded debug-only data
|
||||||
skip-if = ["!debug"]
|
skip-if = ["!debug"]
|
||||||
|
|||||||
Reference in New Issue
Block a user