Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 // -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 "use strict";
7 // In which we connect to a number of domains (as faked by a server running
8 // locally) with OCSP stapling enabled to determine that good things happen
9 // and bad things don't, specifically with respect to various expired OCSP
10 // responses (stapled and otherwise).
12 let gCurrentOCSPResponse = null;
13 let gOCSPRequestCount = 0;
15 function add_ocsp_test(aHost, aExpectedResult, aOCSPResponseToServe) {
16 add_connection_test(aHost, aExpectedResult,
17 function() {
18 clearOCSPCache();
19 clearSessionCache();
20 gCurrentOCSPResponse = aOCSPResponseToServe;
21 gOCSPRequestCount = 0;
22 },
23 function() {
24 do_check_eq(gOCSPRequestCount, 1);
25 });
26 }
28 do_get_profile();
29 Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
30 let args = [["good", "localhostAndExampleCom", "unused"],
31 ["expiredresponse", "localhostAndExampleCom", "unused"],
32 ["oldvalidperiod", "localhostAndExampleCom", "unused"],
33 ["revoked", "localhostAndExampleCom", "unused"],
34 ["unknown", "localhostAndExampleCom", "unused"],
35 ];
36 let ocspResponses = generateOCSPResponses(args, "tlsserver");
37 // Fresh response, certificate is good.
38 let ocspResponseGood = ocspResponses[0];
39 // Expired response, certificate is good.
40 let expiredOCSPResponseGood = ocspResponses[1];
41 // Fresh signature, old validity period, certificate is good.
42 let oldValidityPeriodOCSPResponseGood = ocspResponses[2];
43 // Fresh signature, certificate is revoked.
44 let ocspResponseRevoked = ocspResponses[3];
45 // Fresh signature, certificate is unknown.
46 let ocspResponseUnknown = ocspResponses[4];
48 function run_test() {
49 let ocspResponder = new HttpServer();
50 ocspResponder.registerPrefixHandler("/", function(request, response) {
51 if (gCurrentOCSPResponse) {
52 response.setStatusLine(request.httpVersion, 200, "OK");
53 response.setHeader("Content-Type", "application/ocsp-response");
54 response.write(gCurrentOCSPResponse);
55 } else {
56 response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
57 response.write("Internal Server Error");
58 }
59 gOCSPRequestCount++;
60 });
61 ocspResponder.start(8080);
62 add_tls_server_setup("OCSPStaplingServer");
63 add_tests_in_mode(true);
64 add_tests_in_mode(false);
65 add_test(function () { ocspResponder.stop(run_next_test); });
66 add_test(check_ocsp_stapling_telemetry);
67 run_next_test();
68 }
70 function add_tests_in_mode(useMozillaPKIX)
71 {
72 add_test(function () {
73 Services.prefs.setBoolPref("security.use_mozillapkix_verification",
74 useMozillaPKIX);
75 run_next_test();
76 });
78 // In these tests, the OCSP stapling server gives us a stapled
79 // response based on the host name ("ocsp-stapling-expired" or
80 // "ocsp-stapling-expired-fresh-ca"). We then ensure that we're
81 // properly falling back to fetching revocation information.
82 // For ocsp-stapling-expired.example.com, the OCSP stapling server
83 // staples an expired OCSP response. The certificate has not expired.
84 // For ocsp-stapling-expired-fresh-ca.example.com, the OCSP stapling
85 // server staples an OCSP response with a recent signature but with an
86 // out-of-date validity period. The certificate has not expired.
87 add_ocsp_test("ocsp-stapling-expired.example.com", Cr.NS_OK,
88 ocspResponseGood);
89 add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", Cr.NS_OK,
90 ocspResponseGood);
91 // With mozilla::pkix, if we can't fetch a more recent response when
92 // given an expired stapled response, we terminate the connection.
93 add_ocsp_test("ocsp-stapling-expired.example.com",
94 useMozillaPKIX
95 ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE)
96 : Cr.NS_OK,
97 expiredOCSPResponseGood);
98 add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
99 useMozillaPKIX
100 ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE)
101 : Cr.NS_OK,
102 expiredOCSPResponseGood);
103 add_ocsp_test("ocsp-stapling-expired.example.com",
104 useMozillaPKIX
105 ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE)
106 : Cr.NS_OK,
107 oldValidityPeriodOCSPResponseGood);
108 add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
109 useMozillaPKIX
110 ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE)
111 : Cr.NS_OK,
112 oldValidityPeriodOCSPResponseGood);
113 add_ocsp_test("ocsp-stapling-expired.example.com",
114 useMozillaPKIX
115 ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE)
116 : Cr.NS_OK,
117 null);
118 add_ocsp_test("ocsp-stapling-expired.example.com",
119 useMozillaPKIX
120 ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE)
121 : Cr.NS_OK,
122 null);
123 // Of course, if the newer response indicates Revoked or Unknown,
124 // that status must be returned.
125 add_ocsp_test("ocsp-stapling-expired.example.com",
126 getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
127 ocspResponseRevoked);
128 add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
129 getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
130 ocspResponseRevoked);
131 add_ocsp_test("ocsp-stapling-expired.example.com",
132 getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT),
133 ocspResponseUnknown);
134 add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com",
135 getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT),
136 ocspResponseUnknown);
138 if (useMozillaPKIX) {
139 // If the response is expired but indicates Revoked or Unknown and a
140 // newer status can't be fetched, the Revoked or Unknown status will
141 // be returned.
142 add_ocsp_test("ocsp-stapling-revoked-old.example.com",
143 getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
144 null);
145 add_ocsp_test("ocsp-stapling-unknown-old.example.com",
146 getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT),
147 null);
148 // If the response is expired but indicates Revoked or Unknown and
149 // a newer status can be fetched and successfully verified, this
150 // should result in a successful certificate verification.
151 add_ocsp_test("ocsp-stapling-revoked-old.example.com", Cr.NS_OK,
152 ocspResponseGood);
153 add_ocsp_test("ocsp-stapling-unknown-old.example.com", Cr.NS_OK,
154 ocspResponseGood);
155 // If a newer status can be fetched but it fails to verify, the
156 // Revoked or Unknown status of the expired stapled response
157 // should be returned.
158 add_ocsp_test("ocsp-stapling-revoked-old.example.com",
159 getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
160 expiredOCSPResponseGood);
161 add_ocsp_test("ocsp-stapling-unknown-old.example.com",
162 getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT),
163 expiredOCSPResponseGood);
164 }
166 if (useMozillaPKIX) {
167 // These tests are verifying that an valid but very old response
168 // is rejected as a valid stapled response, requiring a fetch
169 // from the ocsp responder.
170 add_ocsp_test("ocsp-stapling-ancient-valid.example.com", Cr.NS_OK,
171 ocspResponseGood);
172 add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
173 getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE),
174 ocspResponseRevoked);
175 add_ocsp_test("ocsp-stapling-ancient-valid.example.com",
176 getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT),
177 ocspResponseUnknown);
178 }
179 }
181 function check_ocsp_stapling_telemetry() {
182 let histogram = Cc["@mozilla.org/base/telemetry;1"]
183 .getService(Ci.nsITelemetry)
184 .getHistogramById("SSL_OCSP_STAPLING")
185 .snapshot();
186 do_check_eq(histogram.counts[0], 2 * 0); // histogram bucket 0 is unused
187 do_check_eq(histogram.counts[1], 2 * 0); // 0 connections with a good response
188 do_check_eq(histogram.counts[2], 2 * 0); // 0 connections with no stapled resp.
189 do_check_eq(histogram.counts[3], 2 * 12 + 9); // 12 connections with an expired response
190 // +9 more mozilla::pkix-only expired responses
191 do_check_eq(histogram.counts[4], 2 * 0); // 0 connections with bad responses
192 run_next_test();
193 }