From d026d78753db69c8a0bd8c69fd647cf11a17da7f Mon Sep 17 00:00:00 2001 From: David Keeler Date: Fri, 22 Aug 2014 12:07:08 -0700 Subject: [PATCH] bug 1034124 - allow overrides when a CA cert is used as an end-entity cert r=briansmith --- .../BrowserElementChildPreload.js | 4 ++++ security/manager/ssl/src/NSSErrorsService.cpp | 1 + .../ssl/src/SSLServerCertVerification.cpp | 5 ++++- security/manager/ssl/tests/unit/head_psm.js | 1 + .../ssl/tests/unit/test_cert_overrides.js | 16 +++++++++++++++- .../ssl/tests/unit/test_ocsp_stapling.js | 5 ++++- .../manager/ssl/tests/unit/tlsserver/cert9.db | Bin 294912 -> 294912 bytes .../unit/tlsserver/cmd/BadCertServer.cpp | 2 ++ .../unit/tlsserver/cmd/OCSPStaplingServer.cpp | 1 + .../tests/unit/tlsserver/generate_certs.sh | 1 + .../manager/ssl/tests/unit/tlsserver/key4.db | Bin 425984 -> 458752 bytes 11 files changed, 33 insertions(+), 3 deletions(-) diff --git a/dom/browser-element/BrowserElementChildPreload.js b/dom/browser-element/BrowserElementChildPreload.js index 887c55d41d6b..0a18d5a506ed 100644 --- a/dom/browser-element/BrowserElementChildPreload.js +++ b/dom/browser-element/BrowserElementChildPreload.js @@ -81,6 +81,9 @@ let SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = (SEC_ERROR_BASE + 176); let SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE; let SSL_ERROR_BAD_CERT_DOMAIN = (SSL_ERROR_BASE + 12); +let MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE; +let MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = (MOZILLA_PKIX_ERROR_BASE + 1); + function getErrorClass(errorCode) { let NSPRCode = -1 * NS_ERROR_GET_CODE(errorCode); @@ -92,6 +95,7 @@ function getErrorClass(errorCode) { case SSL_ERROR_BAD_CERT_DOMAIN: case SEC_ERROR_EXPIRED_CERTIFICATE: case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: + case MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: return Ci.nsINSSErrorsService.ERROR_CLASS_BAD_CERT; default: return Ci.nsINSSErrorsService.ERROR_CLASS_SSL_PROTOCOL; diff --git a/security/manager/ssl/src/NSSErrorsService.cpp b/security/manager/ssl/src/NSSErrorsService.cpp index 744ec60e206e..75784a7c6626 100644 --- a/security/manager/ssl/src/NSSErrorsService.cpp +++ b/security/manager/ssl/src/NSSErrorsService.cpp @@ -141,6 +141,7 @@ NSSErrorsService::GetErrorClass(nsresult aXPCOMErrorCode, uint32_t *aErrorClass) case SSL_ERROR_BAD_CERT_DOMAIN: case SEC_ERROR_EXPIRED_CERTIFICATE: case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: + case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: *aErrorClass = ERROR_CLASS_BAD_CERT; break; // Non-overridable errors. diff --git a/security/manager/ssl/src/SSLServerCertVerification.cpp b/security/manager/ssl/src/SSLServerCertVerification.cpp index 708fd0428e68..71b907c08286 100644 --- a/security/manager/ssl/src/SSLServerCertVerification.cpp +++ b/security/manager/ssl/src/SSLServerCertVerification.cpp @@ -97,6 +97,7 @@ #include #include "pkix/pkixtypes.h" +#include "pkix/pkixnss.h" #include "CertVerifier.h" #include "CryptoTask.h" #include "ExtendedValidation.h" @@ -300,9 +301,10 @@ MapCertErrorToProbeValue(PRErrorCode errorCode) case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: return 8; case SSL_ERROR_BAD_CERT_DOMAIN: return 9; case SEC_ERROR_EXPIRED_CERTIFICATE: return 10; + case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: return 11; } NS_WARNING("Unknown certificate error code. Does MapCertErrorToProbeValue " - "handle everything in PRErrorCodeToOverrideType?"); + "handle everything in DetermineCertOverrideErrors?"); return 0; } @@ -328,6 +330,7 @@ DetermineCertOverrideErrors(CERTCertificate* cert, const char* hostName, case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: case SEC_ERROR_UNKNOWN_ISSUER: + case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: { collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED; errorCodeTrust = defaultErrorCodeToReport; diff --git a/security/manager/ssl/tests/unit/head_psm.js b/security/manager/ssl/tests/unit/head_psm.js index 9741ea820901..bad05be4d7f9 100644 --- a/security/manager/ssl/tests/unit/head_psm.js +++ b/security/manager/ssl/tests/unit/head_psm.js @@ -60,6 +60,7 @@ const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12; const SSL_ERROR_BAD_CERT_ALERT = SSL_ERROR_BASE + 17; const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = MOZILLA_PKIX_ERROR_BASE + 0; +const MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = MOZILLA_PKIX_ERROR_BASE + 1; const MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = MOZILLA_PKIX_ERROR_BASE + 2; // -16382 // Supported Certificate Usages diff --git a/security/manager/ssl/tests/unit/test_cert_overrides.js b/security/manager/ssl/tests/unit/test_cert_overrides.js index 960794bc12d7..ad4cfc61d5bb 100644 --- a/security/manager/ssl/tests/unit/test_cert_overrides.js +++ b/security/manager/ssl/tests/unit/test_cert_overrides.js @@ -59,8 +59,9 @@ function check_telemetry() { do_check_eq(histogram.counts[ 6], 0); // SEC_ERROR_UNTRUSTED_CERT do_check_eq(histogram.counts[ 7], 0); // SEC_ERROR_INADEQUATE_KEY_USAGE do_check_eq(histogram.counts[ 8], 2); // SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED - do_check_eq(histogram.counts[ 9], 4); // SSL_ERROR_BAD_CERT_DOMAIN + do_check_eq(histogram.counts[ 9], 5); // SSL_ERROR_BAD_CERT_DOMAIN do_check_eq(histogram.counts[10], 5); // SEC_ERROR_EXPIRED_CERTIFICATE + do_check_eq(histogram.counts[11], 2); // MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY run_next_test(); } @@ -121,6 +122,10 @@ function add_simple_tests() { add_cert_override_test("self-signed-end-entity-with-cA-true.example.com", Ci.nsICertOverrideService.ERROR_UNTRUSTED, getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER)); + + add_cert_override_test("ca-used-as-end-entity.example.com", + Ci.nsICertOverrideService.ERROR_UNTRUSTED, + getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY)); } function add_combo_tests() { @@ -147,6 +152,11 @@ function add_combo_tests() { Ci.nsICertOverrideService.ERROR_TIME, getXPCOMStatusFromNSS( SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED)); + + add_cert_override_test("ca-used-as-end-entity-name-mismatch.example.com", + Ci.nsICertOverrideService.ERROR_MISMATCH | + Ci.nsICertOverrideService.ERROR_UNTRUSTED, + getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY)); } function add_distrust_tests() { @@ -160,6 +170,10 @@ function add_distrust_tests() { add_distrust_override_test("tlsserver/other-test-ca.der", "untrustedissuer.example.com", getXPCOMStatusFromNSS(SEC_ERROR_UNTRUSTED_ISSUER)); + + add_distrust_override_test("tlsserver/test-ca.der", + "ca-used-as-end-entity.example.com", + getXPCOMStatusFromNSS(SEC_ERROR_UNTRUSTED_ISSUER)); } function add_distrust_override_test(certFileName, hostName, expectedResult) { diff --git a/security/manager/ssl/tests/unit/test_ocsp_stapling.js b/security/manager/ssl/tests/unit/test_ocsp_stapling.js index 0f843b730dfa..8337399bd950 100644 --- a/security/manager/ssl/tests/unit/test_ocsp_stapling.js +++ b/security/manager/ssl/tests/unit/test_ocsp_stapling.js @@ -143,6 +143,9 @@ function add_tests(certDB, otherTestCA) { add_ocsp_test("keysize-ocsp-delegated.example.com", getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE), true); + + add_ocsp_test("revoked-ca-cert-used-as-end-entity.example.com", + getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), true); } function check_ocsp_stapling_telemetry() { @@ -154,7 +157,7 @@ function check_ocsp_stapling_telemetry() { do_check_eq(histogram.counts[1], 5); // 5 connections with a good response do_check_eq(histogram.counts[2], 18); // 18 connections with no stapled resp. do_check_eq(histogram.counts[3], 0); // 0 connections with an expired response - do_check_eq(histogram.counts[4], 20); // 20 connections with bad responses + do_check_eq(histogram.counts[4], 21); // 21 connections with bad responses run_next_test(); } diff --git a/security/manager/ssl/tests/unit/tlsserver/cert9.db b/security/manager/ssl/tests/unit/tlsserver/cert9.db index 621d07da1523ac7e8489dd37fc1362dbec092f76..fe22bc496350c880eacd0b1ebb0b44a3f3e3136c 100644 GIT binary patch delta 1504 zcmZo@5Nc=;njp=%d!mdpP_4qj%)%)6 z?RG{6l#!keWu&En8Mkj6r*6Md!>Gf|oK~JcoxOq4m8E=H`NHWw4U9f4E&!(0z zMX*$;RLB6`!dvbQ(vV@woX2ROZ>Vda&Bh$c!Yr&3l3HA%;F(vFT9libl9^bNs!&>- znxc?ctl*lLqU)Mhl37xj&dw~vxRfC(4N9kO*QsE-!OoFZwVR>3rRwl>t_G$vf)63ixyPgfiiT-+^RD}TAw zA=Ko-zi&VN{-)!SNCQdiOL?tOeNV?^cgmxjwtG)X(jO}1r*3~=!7SR&Y@sMRm7OJ% zL(N-NLh+@dDA2OG3e1gx8PglpS;|;I@j1QlKC_%FQ^0=4bHUER$e6+Hrw*sjg{ZWj zg3Bc&Um5+jKQ^cIdg*%qt7@7b?TXVMIozK!t4$}poJE9>&y1m?WO|$iOP&GH&~yd{ z21Z5(tN~`w#AIO5#5i*SGZP~d6VTr24tXrvc1A{q7RJVgCQ;(NCME{va4vB%JbmL~ zW{vve0S_|6gQYT9PWOC0JmYfM922gdc2lFHSC`NJzyG{_ZDH-3i;6E^a|u3FaXWEy z6Jv$e-~PpS0(c#F{L(o1%qFow-07g%Wy_Db zH_aE!OGzw}aj5_NASwCo+M7jRD=VM0>=gR+=*yaf935UJW=00a#T5o+20FkrDJ#gL zYM|Vth&33d2fSogV?dy&|etP|r zin6nf$AYvZCG&f;n7&TzoZN7M*V;gVC7UZUuC+h!K~Qtd)4%LHq?s4@nQz>l#dvFa zqdAMD4=^f-3v8t9ge|o)HW{Q%pPvKt#ygeBIk zN|UIt^48C&k_dOWHBGnSdYHw_>Nm4u!$nON{dkhWaDQ@1NV0a;6@|OEnBtza9@%82 UX7yHU>oRAE7q-`_vou8j0840Ia{vGU delta 186 zcmZo@5Nc=;njp=%exi&sOgd95m?D5CB$RL0 zsbIRn&X!d5mZ7?3I!^=BA)v5g)%Lf)n8aCuI^IuZX9ntEF5s!VTDPZmWo<}Je2v@I kGt8IEfyPH{e_z2Y+RkjEUN@DUB@?KXPknoxI!jXo0Buf6O#lD@ diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp index e93ddbf6044c..b9b7f104a76c 100644 --- a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp +++ b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp @@ -43,6 +43,8 @@ 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" }, + { "ca-used-as-end-entity.example.com", "ca-used-as-end-entity" }, + { "ca-used-as-end-entity-name-mismatch.example.com", "ca-used-as-end-entity" }, // 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 diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp index 052a986b41f5..3e19ef820ec3 100644 --- a/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp +++ b/security/manager/ssl/tests/unit/tlsserver/cmd/OCSPStaplingServer.cpp @@ -53,6 +53,7 @@ const OCSPHost sOCSPHosts[] = { "ocsp-stapling-delegated-wrong-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage" }, { "ocsp-stapling-ancient-valid.example.com", ORTAncientAlmostExpired, nullptr}, { "keysize-ocsp-delegated.example.com", ORTDelegatedIncluded, "badKeysizeDelegatedSigner" }, + { "revoked-ca-cert-used-as-end-entity.example.com", ORTRevoked, "ca-used-as-end-entity" }, { nullptr, ORTNull, nullptr } }; diff --git a/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh b/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh index 17d1a5144f0e..736e4a25b52d 100755 --- a/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh +++ b/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh @@ -279,6 +279,7 @@ make_delegated invalidDelegatedSignerKeyUsageCrlSigning 'CN=Test Invalid Delegat make_delegated invalidDelegatedSignerWrongExtKeyUsage 'CN=Test Invalid Delegated Responder Wrong extKeyUsage' testCA "--extKeyUsage codeSigning" make_INT self-signed-EE-with-cA-true 'CN=Test Self-signed End-entity with CA true' unused "-x -8 self-signed-end-entity-with-cA-true.example.com" +make_INT ca-used-as-end-entity 'CN=Test Intermediate used as End-Entity' testCA "-8 ca-used-as-end-entity.example.com" make_delegated badKeysizeDelegatedSigner 'CN=Bad Keysize Delegated Responder' testCA "--extKeyUsage ocspResponder -g 1008" diff --git a/security/manager/ssl/tests/unit/tlsserver/key4.db b/security/manager/ssl/tests/unit/tlsserver/key4.db index 3f953b9c1e9c30c1ae05001d8662bd9103de7fc3..9d6453d125c50d86bf079d3ecd276263fa697309 100644 GIT binary patch delta 5476 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 aWW1I*bLUw8eT$4P_^5iI%P>!Z)4u?^v<%?@ delta 267 zcmZo@kZEX;njp=(hJk^BccOwl