test_ocsp_stapling_expired.js (10309B)
1 // -*- indent-tabs-mode: nil; js-indent-level: 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 // Enable the collection (during test) for all products so even products 8 // that don't collect the data will be able to run the test without failure. 9 Services.prefs.setBoolPref( 10 "toolkit.telemetry.testing.overrideProductsCheck", 11 true 12 ); 13 14 // In which we connect to a number of domains (as faked by a server running 15 // locally) with OCSP stapling enabled to determine that good things happen 16 // and bad things don't, specifically with respect to various expired OCSP 17 // responses (stapled and otherwise). 18 // According to RFC 6066, if a stapled OCSP response can't be satisfactorilly 19 // verified, the client should terminate the connection. Unfortunately, due to 20 // some bugs where servers will staple any old garbage without verifying it, we 21 // can't be this strict in practice. Originally this caveat only applied to 22 // expired responses, but recent high-profile failures have caused us to expand 23 // this to "try later" responses and responses where the signing certificate 24 // doesn't verify successfully. 25 26 var gCurrentOCSPResponse = null; 27 var gOCSPRequestCount = 0; 28 29 function add_ocsp_test( 30 aHost, 31 aExpectedResult, 32 aOCSPResponseToServe, 33 aExpectedRequestCount 34 ) { 35 add_connection_test( 36 aHost, 37 aExpectedResult, 38 function () { 39 clearOCSPCache(); 40 clearSessionCache(); 41 gCurrentOCSPResponse = aOCSPResponseToServe; 42 gOCSPRequestCount = 0; 43 }, 44 function () { 45 equal( 46 gOCSPRequestCount, 47 aExpectedRequestCount, 48 "Should have made " + 49 aExpectedRequestCount + 50 " fallback OCSP request" + 51 (aExpectedRequestCount == 1 ? "" : "s") 52 ); 53 } 54 ); 55 } 56 57 do_get_profile(); 58 Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true); 59 Services.prefs.setIntPref("security.OCSP.enabled", 1); 60 // Sometimes this test will fail on android due to an OCSP request timing out. 61 // That aspect of OCSP requests is not what we're testing here, so we can just 62 // bump the timeout and hopefully avoid these failures. 63 Services.prefs.setIntPref("security.OCSP.timeoutMilliseconds.soft", 5000); 64 var args = [ 65 ["good", "default-ee", "unused", 0], 66 ["expiredresponse", "default-ee", "unused", 0], 67 ["oldvalidperiod", "default-ee", "unused", 0], 68 ["revoked", "default-ee", "unused", 0], 69 ["unknown", "default-ee", "unused", 0], 70 ["good", "must-staple-ee", "unused", 0], 71 ]; 72 var ocspResponses = generateOCSPResponses(args, "ocsp_certs"); 73 // Fresh response, certificate is good. 74 var ocspResponseGood = ocspResponses[0]; 75 // Expired response, certificate is good. 76 var expiredOCSPResponseGood = ocspResponses[1]; 77 // Fresh signature, old validity period, certificate is good. 78 var oldValidityPeriodOCSPResponseGood = ocspResponses[2]; 79 // Fresh signature, certificate is revoked. 80 var ocspResponseRevoked = ocspResponses[3]; 81 // Fresh signature, certificate is unknown. 82 var ocspResponseUnknown = ocspResponses[4]; 83 var ocspResponseGoodMustStaple = ocspResponses[5]; 84 85 // sometimes we expect a result without re-fetch 86 var willNotRetry = 1; 87 // but sometimes, since a bad response is in the cache, OCSP fetch will be 88 // attempted for each validation - in practice, for these test certs, this 89 // means 2 requests because various key sizes are tried. 90 var willRetry = 2; 91 92 function run_test() { 93 let ocspResponder = new HttpServer(); 94 ocspResponder.registerPrefixHandler("/", function (request, response) { 95 if (gCurrentOCSPResponse) { 96 response.setStatusLine(request.httpVersion, 200, "OK"); 97 response.setHeader("Content-Type", "application/ocsp-response"); 98 response.write(gCurrentOCSPResponse); 99 } else { 100 response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); 101 response.write("Internal Server Error"); 102 } 103 gOCSPRequestCount++; 104 }); 105 ocspResponder.start(8888); 106 add_tls_server_setup("OCSPStaplingServer", "ocsp_certs"); 107 108 // In these tests, the OCSP stapling server gives us a stapled 109 // response based on the host name ("ocsp-stapling-expired" or 110 // "ocsp-stapling-expired-fresh-ca"). We then ensure that we're 111 // properly falling back to fetching revocation information. 112 // For ocsp-stapling-expired.example.com, the OCSP stapling server 113 // staples an expired OCSP response. The certificate has not expired. 114 // For ocsp-stapling-expired-fresh-ca.example.com, the OCSP stapling 115 // server staples an OCSP response with a recent signature but with an 116 // out-of-date validity period. The certificate has not expired. 117 add_ocsp_test( 118 "ocsp-stapling-expired.example.com", 119 PRErrorCodeSuccess, 120 ocspResponseGood, 121 willNotRetry 122 ); 123 add_ocsp_test( 124 "ocsp-stapling-expired-fresh-ca.example.com", 125 PRErrorCodeSuccess, 126 ocspResponseGood, 127 willNotRetry 128 ); 129 // if we can't fetch a more recent response when 130 // given an expired stapled response, we terminate the connection. 131 add_ocsp_test( 132 "ocsp-stapling-expired.example.com", 133 SEC_ERROR_OCSP_OLD_RESPONSE, 134 expiredOCSPResponseGood, 135 willRetry 136 ); 137 add_ocsp_test( 138 "ocsp-stapling-expired-fresh-ca.example.com", 139 SEC_ERROR_OCSP_OLD_RESPONSE, 140 expiredOCSPResponseGood, 141 willRetry 142 ); 143 add_ocsp_test( 144 "ocsp-stapling-expired.example.com", 145 SEC_ERROR_OCSP_OLD_RESPONSE, 146 oldValidityPeriodOCSPResponseGood, 147 willRetry 148 ); 149 add_ocsp_test( 150 "ocsp-stapling-expired-fresh-ca.example.com", 151 SEC_ERROR_OCSP_OLD_RESPONSE, 152 oldValidityPeriodOCSPResponseGood, 153 willRetry 154 ); 155 add_ocsp_test( 156 "ocsp-stapling-expired.example.com", 157 SEC_ERROR_OCSP_OLD_RESPONSE, 158 null, 159 willNotRetry 160 ); 161 add_ocsp_test( 162 "ocsp-stapling-expired.example.com", 163 SEC_ERROR_OCSP_OLD_RESPONSE, 164 null, 165 willNotRetry 166 ); 167 // Of course, if the newer response indicates Revoked or Unknown, 168 // that status must be returned. 169 add_ocsp_test( 170 "ocsp-stapling-expired.example.com", 171 SEC_ERROR_REVOKED_CERTIFICATE, 172 ocspResponseRevoked, 173 willNotRetry 174 ); 175 add_ocsp_test( 176 "ocsp-stapling-expired-fresh-ca.example.com", 177 SEC_ERROR_REVOKED_CERTIFICATE, 178 ocspResponseRevoked, 179 willNotRetry 180 ); 181 add_ocsp_test( 182 "ocsp-stapling-expired.example.com", 183 SEC_ERROR_OCSP_UNKNOWN_CERT, 184 ocspResponseUnknown, 185 willRetry 186 ); 187 add_ocsp_test( 188 "ocsp-stapling-expired-fresh-ca.example.com", 189 SEC_ERROR_OCSP_UNKNOWN_CERT, 190 ocspResponseUnknown, 191 willRetry 192 ); 193 194 // If the response is expired but indicates Revoked or Unknown and a 195 // newer status can't be fetched, the Revoked or Unknown status will 196 // be returned. 197 add_ocsp_test( 198 "ocsp-stapling-revoked-old.example.com", 199 SEC_ERROR_REVOKED_CERTIFICATE, 200 null, 201 willNotRetry 202 ); 203 add_ocsp_test( 204 "ocsp-stapling-unknown-old.example.com", 205 SEC_ERROR_OCSP_UNKNOWN_CERT, 206 null, 207 willNotRetry 208 ); 209 // If the response is expired but indicates Revoked or Unknown and 210 // a newer status can be fetched and successfully verified, this 211 // should result in a successful certificate verification. 212 add_ocsp_test( 213 "ocsp-stapling-revoked-old.example.com", 214 PRErrorCodeSuccess, 215 ocspResponseGood, 216 willNotRetry 217 ); 218 add_ocsp_test( 219 "ocsp-stapling-unknown-old.example.com", 220 PRErrorCodeSuccess, 221 ocspResponseGood, 222 willNotRetry 223 ); 224 // If a newer status can be fetched but it fails to verify, the 225 // Revoked or Unknown status of the expired stapled response 226 // should be returned. 227 add_ocsp_test( 228 "ocsp-stapling-revoked-old.example.com", 229 SEC_ERROR_REVOKED_CERTIFICATE, 230 expiredOCSPResponseGood, 231 willRetry 232 ); 233 add_ocsp_test( 234 "ocsp-stapling-unknown-old.example.com", 235 SEC_ERROR_OCSP_UNKNOWN_CERT, 236 expiredOCSPResponseGood, 237 willRetry 238 ); 239 240 // These tests are verifying that an valid but very old response 241 // is rejected as a valid stapled response, requiring a fetch 242 // from the ocsp responder. 243 add_ocsp_test( 244 "ocsp-stapling-ancient-valid.example.com", 245 PRErrorCodeSuccess, 246 ocspResponseGood, 247 willNotRetry 248 ); 249 add_ocsp_test( 250 "ocsp-stapling-ancient-valid.example.com", 251 SEC_ERROR_REVOKED_CERTIFICATE, 252 ocspResponseRevoked, 253 willNotRetry 254 ); 255 add_ocsp_test( 256 "ocsp-stapling-ancient-valid.example.com", 257 SEC_ERROR_OCSP_UNKNOWN_CERT, 258 ocspResponseUnknown, 259 willRetry 260 ); 261 262 // Test how OCSP-must-staple (i.e. TLS feature) interacts with stapled OCSP 263 // responses that don't successfully verify. 264 // A strict reading of the relevant RFCs might say that these connections 265 // should all fail because a satisfactory stapled OCSP response is not 266 // present, but for compatibility reasons we fall back to active OCSP fetching 267 // in these situations. If the fetch succeeds, then connection succeeds. 268 add_ocsp_test( 269 "ocsp-stapling-must-staple-expired.example.com", 270 PRErrorCodeSuccess, 271 ocspResponseGoodMustStaple, 272 willNotRetry 273 ); 274 add_ocsp_test( 275 "ocsp-stapling-must-staple-try-later.example.com", 276 PRErrorCodeSuccess, 277 ocspResponseGoodMustStaple, 278 willNotRetry 279 ); 280 add_ocsp_test( 281 "ocsp-stapling-must-staple-invalid-signer.example.com", 282 PRErrorCodeSuccess, 283 ocspResponseGoodMustStaple, 284 willNotRetry 285 ); 286 287 add_test(function () { 288 ocspResponder.stop(run_next_test); 289 }); 290 add_test(check_ocsp_stapling_telemetry); 291 run_next_test(); 292 } 293 294 function check_ocsp_stapling_telemetry() { 295 let histogram = Services.telemetry 296 .getHistogramById("SSL_OCSP_STAPLING") 297 .snapshot(); 298 equal( 299 histogram.values[0] || 0, 300 0, 301 "Should have 0 connections for unused histogram bucket 0" 302 ); 303 equal( 304 histogram.values[1] || 0, 305 0, 306 "Actual and expected connections with a good response should match" 307 ); 308 equal( 309 histogram.values[2] || 0, 310 0, 311 "Actual and expected connections with no stapled response should match" 312 ); 313 equal( 314 histogram.values[3], 315 22, 316 "Actual and expected connections with an expired response should match" 317 ); 318 equal( 319 histogram.values[4], 320 2, 321 "Actual and expected connections with bad responses should match" 322 ); 323 run_next_test(); 324 }