Bug 998057: Add tests for certificate pinning (r=cviecco,dkeeler)

This commit is contained in:
Monica Chew 2014-04-30 19:56:03 -07:00
parent cf6decae49
commit 68b3043845
15 changed files with 124 additions and 8 deletions

View File

@ -82,13 +82,15 @@
"Baltimore CyberTrust Root"
]
},
// For pinning tests on pinning.example.com, the issuer must be testCA.
// For pinning tests on pinning.example.com, the certificate must be 'End
// Entity Test Cert'
{
"name": "mozilla_test",
"static_spki_hashes": [
"End Entity Test Cert"
]
} ],
}
],
"entries": [
{ "name": "addons.mozilla.org", "include_subdomains": true, "pins": "mozilla" },
@ -96,7 +98,7 @@
{ "name": "cdn.mozilla.net", "include_subdomains": true, "pins": "mozilla_cdn" },
{ "name": "cdn.mozilla.org", "include_subdomains": true, "pins": "mozilla_cdn" },
{ "name": "media.mozilla.com", "include_subdomains": true, "pins": "mozilla_cdn" },
{ "name": "include-subdomain.pinning.example.com", "include_subdomains": true, "pins": "mozilla_test" },
{ "name": "include-subdomains.pinning.example.com", "include_subdomains": true, "pins": "mozilla_test" },
{ "name": "exclude-subdomains.pinning.example.com", "include_subdomains": false, "pins": "mozilla_test" }
]
}

View File

@ -25,7 +25,7 @@ static const char kDigiCert_High_Assurance_EV_Root_CAFingerprint[]=
/* End Entity Test Cert */
static const char kEnd_Entity_Test_CertFingerprint[]=
"97H5CNFJ2u3u1NvH3ru67t5OiCO8KydOyNh9GCEyAeM=";
"sEIYDccDj1ULE64YxhvqV7ASqc2qfIofVyArzg+62hU=";
/* Equifax Secure CA */
static const char kEquifax_Secure_CAFingerprint[]=
@ -196,10 +196,10 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
{ "cdn.mozilla.net", true, &kPinSet_mozilla_cdn },
{ "cdn.mozilla.org", true, &kPinSet_mozilla_cdn },
{ "exclude-subdomains.pinning.example.com", false, &kPinSet_mozilla_test },
{ "include-subdomain.pinning.example.com", true, &kPinSet_mozilla_test },
{ "include-subdomains.pinning.example.com", true, &kPinSet_mozilla_test },
{ "media.mozilla.com", true, &kPinSet_mozilla_cdn },
};
static const int kPublicKeyPinningPreloadListLength = 7;
const PRTime kPreloadPKPinsExpirationTime = INT64_C(1409763023059000);
const PRTime kPreloadPKPinsExpirationTime = INT64_C(1409782406553000);

View File

@ -51,6 +51,7 @@ const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144;
const SEC_ERROR_POLICY_VALIDATION_FAILED = SEC_ERROR_BASE + 160; // -8032
const SEC_ERROR_OCSP_BAD_SIGNATURE = SEC_ERROR_BASE + 157;
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
const SEC_ERROR_APPLICATION_CALLBACK_ERROR = SEC_ERROR_BASE + 178;
const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12;

View File

@ -230,7 +230,7 @@ function add_distrust_override_test(certFileName, hostName,
let certToDistrust = constructCertFromFile(certFileName);
add_test(function () {
// "pu" means the cert is actively distrusted.
// Add an entry to the NSS certDB that says to distrust the cert
setCertTrust(certToDistrust, "pu,,");
clearSessionCache();
run_next_test();

View File

@ -0,0 +1,96 @@
// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/.
//
// For all cases, the acceptable pinset includes only certificates pinned to
// Test End Entity Cert (signed by issuer testCA). Other certificates
// are issued by otherCA, which is never in the pinset but is a user-specified
// trust anchor. This test covers multiple cases:
//
// Pinned domain include-subdomains.pinning.example.com includes subdomains
// - PASS: include-subdomains.pinning.example.com serves a correct cert
// - PASS: good.include-subdomains.pinning.example.com serves a correct cert
// - FAIL (strict): bad.include-subdomains.pinning.example.com serves a cert
// not in the pinset
// - PASS (mitm): bad.include-subdomains.pinning.example.com serves a cert not
// in the pinset, but issued by a user-specified trust domain
//
// Pinned domain exclude-subdomains.pinning.example.com excludes subdomains
// - PASS: exclude-subdomains.pinning.example.com serves a correct cert
// - FAIL: exclude-subdomains.pinning.example.com services an incorrect cert
// (TODO: test using verifyCertnow)
// - PASS: sub.exclude-subdomains.pinning.example.com serves an incorrect cert
"use strict";
do_get_profile(); // must be called before getting nsIX509CertDB
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
function test_strict() {
// In strict mode, we always evaluate pinning data, regardless of whether the
// issuer is a built-in trust anchor.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
run_next_test();
});
// Issued by otherCA, which is not in the pinset for pinning.example.com.
add_connection_test("bad.include-subdomains.pinning.example.com",
getXPCOMStatusFromNSS(SEC_ERROR_APPLICATION_CALLBACK_ERROR));
// These domains serve certs that match the pinset.
add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK);
// This domain serves a cert that doesn't match the pinset, but subdomains
// are excluded.
add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK);
};
function test_mitm() {
// In MITM mode, we allow pinning to pass if the chain resolves to any
// user-specified trust anchor, even if it is not in the pinset.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
run_next_test();
});
add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK);
// In this case, even though otherCA is not in the pinset, it is a
// user-specified trust anchor and the pinning check succeeds.
add_connection_test("bad.include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK);
};
function test_disabled() {
// Disable pinning.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0);
run_next_test();
});
add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("bad.include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK);
};
function run_test() {
add_tls_server_setup("BadCertServer");
// Add a user-specified trust anchor.
addCertFromFile(certdb, "tlsserver/other-test-ca.der", "CTu,u,u");
test_strict();
test_mitm();
test_disabled();
run_next_test();
}

View File

@ -24,6 +24,7 @@ struct BadCertHost
const char *mCertName;
};
// Hostname, cert nickname pairs.
const BadCertHost sBadCertHosts[] =
{
{ "expired.example.com", "expired" },
@ -42,6 +43,15 @@ const BadCertHost sBadCertHosts[] =
{ "inadequatekeyusage.example.com", "inadequatekeyusage" },
{ "selfsigned-inadequateEKU.example.com", "selfsigned-inadequateEKU" },
{ "self-signed-end-entity-with-cA-true.example.com", "self-signed-EE-with-cA-true" },
// All of include-subdomains.pinning.example.com is pinned to End Entity Test
// Cert with nick localhostAndExampleCom. Any other nick will only pass
// pinning when security.cert_pinning.enforcement.level != strict and otherCA
// is added as a user-specified trust anchor. See StaticHPKPins.h.
{ "include-subdomains.pinning.example.com", "localhostAndExampleCom" },
{ "good.include-subdomains.pinning.example.com", "localhostAndExampleCom" },
{ "bad.include-subdomains.pinning.example.com", "otherIssuerEE" },
{ "exclude-subdomains.pinning.example.com", "localhostAndExampleCom" },
{ "sub.exclude-subdomains.pinning.example.com", "otherIssuerEE" },
{ nullptr, nullptr }
};

View File

@ -139,7 +139,10 @@ function make_delegated {
make_CA testCA 'CN=Test CA' test-ca.der
make_CA otherCA 'CN=Other test CA' other-test-ca.der
make_EE localhostAndExampleCom 'CN=Test End-entity' testCA "localhost,*.example.com,*.pinning.example.com"
make_EE localhostAndExampleCom 'CN=Test End-entity' testCA "localhost,*.example.com,*.pinning.example.com,*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com"
# Make an EE cert issued by otherCA
make_EE otherIssuerEE 'CN=Wrong CA Pin Test End-Entity' otherCA "*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com"
$RUN_MOZILLA $CERTUTIL -d $OUTPUT_DIR -L -n localhostAndExampleCom -r > $OUTPUT_DIR/default-ee.der
# A cert that is like localhostAndExampleCom, but with a different serial number for

View File

@ -66,3 +66,7 @@ fail-if = os == "android" || buildapp == "b2g"
# Bug 989485 : this test this fails on slow devices
skip-if = os == "android" || (buildapp == "b2g" && processor == "arm")
requesttimeoutfactor = 4
[test_pinning.js]
run-sequentially = hardcoded ports
# Bug 676972: test fails consistently on Android and B2G
fail-if = os == "android" || buildapp == "b2g"