|
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"; |
|
6 |
|
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). |
|
11 |
|
12 let gCurrentOCSPResponse = null; |
|
13 let gOCSPRequestCount = 0; |
|
14 |
|
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 } |
|
27 |
|
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]; |
|
47 |
|
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 } |
|
69 |
|
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 }); |
|
77 |
|
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); |
|
137 |
|
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 } |
|
165 |
|
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 } |
|
180 |
|
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 } |