Bug 1434300 - Update Imminent Distrust status for future Symantec sanctions r=fkiefer,keeler

This patch does a few things:

1) It adds a permament test mechanism for the "imminent distrust" trust status
in nsNSSCallbacks: a simple xpcshell test to exercise a clause in the imminent
distrust logic in nsNSSCallbacks' IsCertificateDistrustImminent method.

2) This test removes test_symantec_apple_google_unaffected.js as its
functionality is rolled into the new test_imminent_distrust.js.

3) It updates the Symantec imminent distrust warning algorithm to remove the
validity date exception; this warns of the upcoming distrust for those affected
certs in Firefox 63.

This patch does not attempt to edit the browser chrome test that checks the
console; that is a subsequent patch.

MozReview-Commit-ID: 1HyVLfmEOP7

--HG--
extra : rebase_source : 48c9caae2d26a7e36102b4770c4044101acf0712
This commit is contained in:
J.C. Jones 2018-02-19 09:33:36 -07:00
Родитель ad6889fdd2
Коммит d1bff6c67a
11 изменённых файлов: 110 добавлений и 55 удалений

Просмотреть файл

@ -0,0 +1,22 @@
// Script from security/manager/tools/crtshToDNStruct/crtshToDNStruct.py
// Invocation: security/manager/tools/crtshToDNStruct/crtshToDNStruct.py security/manager/ssl/tests/unit/bad_certs/ee-imminently-distrusted.pem
// This file is used by test_imminent_distrust.js and by
// browser_console_certificate_imminent_distrust.js to ensure that the UI for
// alerting users to an upcoming CA distrust action continues to function.
// /C=US/CN=Imminently Distrusted End Entity
// SHA256 Fingerprint: 63:3A:70:8A:67:42:91:95:98:E9:D1:CB:8B:5D:73:80
// BA:6D:AD:25:82:62:52:AD:5E:5E:DC:06:BF:03:1F:D0
static const uint8_t CAImminentlyDistrustedEndEntityDN[58] = {
0x30, 0x38, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x55, 0x53, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20,
0x49, 0x6D, 0x6D, 0x69, 0x6E, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x44, 0x69,
0x73, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x20, 0x45, 0x6E, 0x64, 0x20,
0x45, 0x6E, 0x74, 0x69, 0x74, 0x79,
};
static const DataAndLength TestImminentDistrustEndEntityDNs[]= {
{ CAImminentlyDistrustedEndEntityDN,
sizeof(CAImminentlyDistrustedEndEntityDN) },
};

Просмотреть файл

@ -39,7 +39,7 @@
#include "TrustOverrideUtils.h"
#include "TrustOverride-SymantecData.inc"
#include "TrustOverride-AppleGoogleData.inc"
#include "TrustOverride-TestImminentDistrustData.inc"
using namespace mozilla;
using namespace mozilla::pkix;
@ -1255,30 +1255,25 @@ IsCertificateDistrustImminent(nsIX509CertList* aCertList,
return rv;
}
// We need to verify the age of the end entity
nsCOMPtr<nsIX509CertValidity> validity;
rv = eeCert->GetValidity(getter_AddRefs(validity));
if (NS_FAILED(rv)) {
return rv;
// Check the test certificate condition first; this is a special certificate
// that gets the 'imminent distrust' treatment; this is so that the distrust
// UX code does not become stale, as it will need regular use. See Bug 1409257
// for context. Please do not remove this when adjusting the rest of the
// method.
UniqueCERTCertificate nssEECert(eeCert->GetCert());
if (!nssEECert) {
return NS_ERROR_FAILURE;
}
PRTime notBefore;
rv = validity->GetNotBefore(&notBefore);
if (NS_FAILED(rv)) {
return rv;
}
// PRTime is microseconds since the epoch, whereas JS time is milliseconds.
// (new Date("2016-06-01T00:00:00Z")).getTime() * 1000
static const PRTime JUNE_1_2016 = 1464739200000000;
// If the end entity's notBefore date is after 2016-06-01, this algorithm
// doesn't apply, so exit false before we do any iterating
if (notBefore >= JUNE_1_2016) {
aResult = false;
aResult = CertDNIsInList(nssEECert.get(), TestImminentDistrustEndEntityDNs);
if (aResult) {
// Exit early
return NS_OK;
}
// Proceed with the Symantec imminent distrust algorithm. This algorithm is
// to be removed in Firefox 63, when the validity period check will also be
// removed from the code in NSSCertDBTrustDomain.
// We need an owning handle when calling nsIX509Cert::GetCert().
UniqueCERTCertificate nssRootCert(rootCert->GetCert());
// If the root is not one of the Symantec roots, exit false

Просмотреть файл

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDSzCCAjOgAwIBAgIUa5hfI/44eCaBMFte+oFrCN4wsOAwDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAiGA8yMDE2MTEyNzAwMDAwMFoYDzIwMTkw
MjA1MDAwMDAwWjA4MQswCQYDVQQGEwJVUzEpMCcGA1UEAxMgSW1taW5lbnRseSBE
aXN0cnVzdGVkIEVuZCBFbnRpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwG
m24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJr
bA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4
SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3
/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+Z
FzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjbzBtMDcGA1UdEQQwMC6CCWxvY2Fs
aG9zdIIhaW1taW5lbnRseS1kaXN0cnVzdGVkLmV4YW1wbGUuY29tMDIGCCsGAQUF
BwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzANBgkq
hkiG9w0BAQsFAAOCAQEAZbcXYrr6V3GvIjGsHEvI7X5P5kwuu7XADxBZItcu9eLv
s3Sa7U3tIlhZkLYzsLuPz2q3ZkG+baFayOJgXPPaleEDrxDpElyPYtD+oTvO5oVv
2G8UlObIdzuym5FPDpvuiQIcDIZELUOQO9V+fjeK0CZ4luFnox+cIvnB39pLa5Xd
hHUyWMgsf9cW/T1yjjRAS2YX/HUYGjSH9MNhSriiAABers1fyJkn7fdVTav2pQTp
5yNdtwrFYkWjw1DG17uj/gtkll3ACw9oztjYTGj/okDI+ViLJqL4QeQb4G4Lpp77
+A8JfHGf/yFprXMMExy8FNN8FLIxdN2lX4WwBS5WHQ==
-----END CERTIFICATE-----

Просмотреть файл

@ -0,0 +1,4 @@
issuer:Test CA
subject:printableString/C=US/CN=Imminently Distrusted End Entity
extension:subjectAlternativeName:localhost,imminently-distrusted.example.com
extension:authorityInformationAccess:http://localhost:8888/

Просмотреть файл

@ -13,6 +13,7 @@
# 'ca-used-as-end-entity.pem',
# 'default-ee.pem',
# 'ee-from-missing-intermediate.pem',
# 'ee-imminently-distrusted.pem',
# 'eeIssuedByNonCA.pem',
# 'eeIssuedByV1Cert.pem',
# 'emptyIssuerName.pem',

Просмотреть файл

@ -0,0 +1,29 @@
/* 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";
// Tests handling of certificates that are selected to emit a distrust warning
// to the console.
function shouldBeImminentlyDistrusted(aTransportSecurityInfo) {
let isDistrust = aTransportSecurityInfo.securityState &
Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
Assert.ok(isDistrust, "This host should be imminently distrusted");
}
function shouldNotBeImminentlyDistrusted(aTransportSecurityInfo) {
let isDistrust = aTransportSecurityInfo.securityState &
Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
Assert.ok(!isDistrust, "This host should not be imminently distrusted");
}
do_get_profile();
add_tls_server_setup("BadCertServer", "bad_certs");
add_connection_test("imminently-distrusted.example.com",
PRErrorCodeSuccess, null, shouldBeImminentlyDistrusted);
add_connection_test("include-subdomains.pinning.example.com",
PRErrorCodeSuccess, null, shouldNotBeImminentlyDistrusted);

Просмотреть файл

@ -31,9 +31,9 @@ add_connection_test("symantec-whitelist-after-cutoff.example.com",
add_connection_test("symantec-whitelist-before-cutoff.example.com",
PRErrorCodeSuccess, null, shouldNotBeImminentlyDistrusted);
// Not-whitelisted certs after the cutoff aren't distrusted
// Not-whitelisted certs after the cutoff are to be distrusted
add_connection_test("symantec-not-whitelisted-after-cutoff.example.com",
PRErrorCodeSuccess, null, shouldNotBeImminentlyDistrusted);
PRErrorCodeSuccess, null, shouldBeImminentlyDistrusted);
// Not whitelisted certs before the cutoff are to be distrusted
add_connection_test("symantec-not-whitelisted-before-cutoff.example.com",

Просмотреть файл

@ -1,22 +0,0 @@
/* 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";
// Tests handling of certificates issued by Symantec. If such
// certificates have a notBefore before 1 June 2016, and are not
// issued by an Apple or Google intermediate, they should emit a
// warning to the console.
function shouldNotBeImminentlyDistrusted(aTransportSecurityInfo) {
let isDistrust = aTransportSecurityInfo.securityState &
Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
Assert.ok(!isDistrust, "This host should not be imminently distrusted");
}
do_get_profile();
add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
add_connection_test("ocsp-stapling-good.example.com",
PRErrorCodeSuccess, null, shouldNotBeImminentlyDistrusted);

Просмотреть файл

@ -78,6 +78,7 @@ const BadCertHost sBadCertHosts[] =
{ "emptyissuername.example.com", "emptyIssuerName" },
{ "ev-test.example.com", "ev-test" },
{ "ee-from-missing-intermediate.example.com", "ee-from-missing-intermediate" },
{ "imminently-distrusted.example.com", "ee-imminently-distrusted" },
{ "localhost", "unknownissuer" },
{ nullptr, nullptr }
};

Просмотреть файл

@ -97,6 +97,8 @@ skip-if = toolkit == 'android'
skip-if = toolkit == 'android'
[test_hmac.js]
[test_intermediate_basic_usage_constraints.js]
[test_imminent_distrust.js]
run-sequentially = hardcoded ports
[test_js_cert_override_service.js]
run-sequentially = hardcoded ports
[test_keysize.js]
@ -179,8 +181,6 @@ skip-if = toolkit == 'android'
[test_sts_preloadlist_selfdestruct.js]
[test_symantec_apple_google.js]
run-sequentially = hardcoded ports
[test_symantec_apple_google_unaffected.js]
run-sequentially = hardcoded ports
[test_validity.js]
run-sequentially = hardcoded ports
[test_x509.js]

Просмотреть файл

@ -48,7 +48,7 @@ def nameOIDtoString(oid):
return "OU"
raise Exception("Unknown OID: {}".format(oid))
def print_block(pemData):
def print_block(pemData, crtshId):
substrate = pem.readPemFromFile(io.StringIO(pemData.decode("utf-8")))
cert, rest = decoder.decode(substrate, asn1Spec=rfc5280.Certificate())
der_subject = encoder.encode(cert['tbsCertificate']['subject'])
@ -67,8 +67,9 @@ def print_block(pemData):
print("// {dn}".format(dn=distinguished_name))
print("// SHA256 Fingerprint: " + ":".join(fingerprint[:16]))
print("// " + ":".join(fingerprint[16:]))
print("// https://crt.sh/?id={crtsh} (crt.sh ID={crtsh})"
.format(crtsh=crtshId))
if crtshId:
print("// https://crt.sh/?id={crtsh} (crt.sh ID={crtsh})"
.format(crtsh=crtshId))
print("static const uint8_t {}[{}] = ".format(block_name, len(octets)) + "{")
while len(octets) > 0:
@ -89,11 +90,14 @@ if __name__ == "__main__":
print("// Invocation: {} {}".format(sys.argv[0], " ".join(certshIds)))
print()
for crtshId in certshIds:
r = requests.get('https://crt.sh/?d={}'.format(crtshId))
r.raise_for_status()
pemData = r.content
blocks.append(print_block(pemData))
# Try a local file first, then crt.sh
try:
with open(crtshId, "rb") as pemFile:
blocks.append(print_block(pemFile.read(), None))
except FileNotFoundError:
r = requests.get('https://crt.sh/?d={}'.format(crtshId))
r.raise_for_status()
blocks.append(print_block(r.content, crtshId))
print("static const DataAndLength RootDNs[]= {")
for structName in blocks: