security/manager/ssl/tests/unit/head_psm.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4 */
michael@0 5 "use strict";
michael@0 6
michael@0 7 const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Components;
michael@0 8
michael@0 9 let { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
michael@0 10 let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
michael@0 11 let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
michael@0 12 let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
michael@0 13 let { HttpServer } = Cu.import("resource://testing-common/httpd.js", {});
michael@0 14 let { ctypes } = Cu.import("resource://gre/modules/ctypes.jsm");
michael@0 15
michael@0 16 let gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
michael@0 17
michael@0 18 const isDebugBuild = Cc["@mozilla.org/xpcom/debug;1"]
michael@0 19 .getService(Ci.nsIDebug2).isDebugBuild;
michael@0 20
michael@0 21 const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
michael@0 22 const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
michael@0 23
michael@0 24 // Sort in numerical order
michael@0 25 const SEC_ERROR_INVALID_ARGS = SEC_ERROR_BASE + 5; // -8187
michael@0 26 const SEC_ERROR_BAD_DER = SEC_ERROR_BASE + 9;
michael@0 27 const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
michael@0 28 const SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12; // -8180
michael@0 29 const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
michael@0 30 const SEC_ERROR_BAD_DATABASE = SEC_ERROR_BASE + 18;
michael@0 31 const SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20; // -8172
michael@0 32 const SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21; // -8171
michael@0 33 const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30; // -8162
michael@0 34 const SEC_ERROR_EXTENSION_VALUE_INVALID = SEC_ERROR_BASE + 34; // -8158
michael@0 35 const SEC_ERROR_EXTENSION_NOT_FOUND = SEC_ERROR_BASE + 35; // -8157
michael@0 36 const SEC_ERROR_CA_CERT_INVALID = SEC_ERROR_BASE + 36;
michael@0 37 const SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION = SEC_ERROR_BASE + 41;
michael@0 38 const SEC_ERROR_INADEQUATE_KEY_USAGE = SEC_ERROR_BASE + 90; // -8102
michael@0 39 const SEC_ERROR_INADEQUATE_CERT_TYPE = SEC_ERROR_BASE + 91; // -8101
michael@0 40 const SEC_ERROR_CERT_NOT_IN_NAME_SPACE = SEC_ERROR_BASE + 112; // -8080
michael@0 41 const SEC_ERROR_CERT_BAD_ACCESS_LOCATION = SEC_ERROR_BASE + 117; // -8075
michael@0 42 const SEC_ERROR_OCSP_MALFORMED_REQUEST = SEC_ERROR_BASE + 120;
michael@0 43 const SEC_ERROR_OCSP_SERVER_ERROR = SEC_ERROR_BASE + 121; // -8071
michael@0 44 const SEC_ERROR_OCSP_TRY_SERVER_LATER = SEC_ERROR_BASE + 122;
michael@0 45 const SEC_ERROR_OCSP_REQUEST_NEEDS_SIG = SEC_ERROR_BASE + 123;
michael@0 46 const SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST = SEC_ERROR_BASE + 124;
michael@0 47 const SEC_ERROR_OCSP_UNKNOWN_CERT = SEC_ERROR_BASE + 126; // -8066
michael@0 48 const SEC_ERROR_OCSP_MALFORMED_RESPONSE = SEC_ERROR_BASE + 129;
michael@0 49 const SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE = SEC_ERROR_BASE + 130;
michael@0 50 const SEC_ERROR_OCSP_OLD_RESPONSE = SEC_ERROR_BASE + 132;
michael@0 51 const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144;
michael@0 52 const SEC_ERROR_POLICY_VALIDATION_FAILED = SEC_ERROR_BASE + 160; // -8032
michael@0 53 const SEC_ERROR_OCSP_BAD_SIGNATURE = SEC_ERROR_BASE + 157;
michael@0 54 const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
michael@0 55 const SEC_ERROR_APPLICATION_CALLBACK_ERROR = SEC_ERROR_BASE + 178;
michael@0 56
michael@0 57 const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12;
michael@0 58
michael@0 59 // Supported Certificate Usages
michael@0 60 const certificateUsageSSLClient = 0x0001;
michael@0 61 const certificateUsageSSLServer = 0x0002;
michael@0 62 const certificateUsageSSLCA = 0x0008;
michael@0 63 const certificateUsageEmailSigner = 0x0010;
michael@0 64 const certificateUsageEmailRecipient = 0x0020;
michael@0 65 const certificateUsageObjectSigner = 0x0040;
michael@0 66 const certificateUsageVerifyCA = 0x0100;
michael@0 67 const certificateUsageStatusResponder = 0x0400;
michael@0 68
michael@0 69 const NO_FLAGS = 0;
michael@0 70
michael@0 71 function readFile(file) {
michael@0 72 let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
michael@0 73 .createInstance(Ci.nsIFileInputStream);
michael@0 74 fstream.init(file, -1, 0, 0);
michael@0 75 let data = NetUtil.readInputStreamToString(fstream, fstream.available());
michael@0 76 fstream.close();
michael@0 77 return data;
michael@0 78 }
michael@0 79
michael@0 80 function addCertFromFile(certdb, filename, trustString) {
michael@0 81 let certFile = do_get_file(filename, false);
michael@0 82 let der = readFile(certFile);
michael@0 83 certdb.addCert(der, trustString, null);
michael@0 84 }
michael@0 85
michael@0 86 function constructCertFromFile(filename) {
michael@0 87 let certFile = do_get_file(filename, false);
michael@0 88 let certDER = readFile(certFile);
michael@0 89 let certdb = Cc["@mozilla.org/security/x509certdb;1"]
michael@0 90 .getService(Ci.nsIX509CertDB);
michael@0 91 return certdb.constructX509(certDER, certDER.length);
michael@0 92 }
michael@0 93
michael@0 94 function setCertTrust(cert, trustString) {
michael@0 95 let certdb = Cc["@mozilla.org/security/x509certdb;1"]
michael@0 96 .getService(Ci.nsIX509CertDB);
michael@0 97 certdb.setCertTrustFromString(cert, trustString);
michael@0 98 }
michael@0 99
michael@0 100 function getXPCOMStatusFromNSS(statusNSS) {
michael@0 101 let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"]
michael@0 102 .getService(Ci.nsINSSErrorsService);
michael@0 103 return nssErrorsService.getXPCOMFromNSSError(statusNSS);
michael@0 104 }
michael@0 105
michael@0 106 function checkCertErrorGeneric(certdb, cert, expectedError, usage) {
michael@0 107 let hasEVPolicy = {};
michael@0 108 let verifiedChain = {};
michael@0 109 let error = certdb.verifyCertNow(cert, usage, NO_FLAGS, verifiedChain,
michael@0 110 hasEVPolicy);
michael@0 111 // expected error == -1 is a special marker for any error is OK
michael@0 112 if (expectedError != -1 ) {
michael@0 113 do_check_eq(error, expectedError);
michael@0 114 } else {
michael@0 115 do_check_neq (error, 0);
michael@0 116 }
michael@0 117 }
michael@0 118
michael@0 119 function _getLibraryFunctionWithNoArguments(functionName, libraryName) {
michael@0 120 // Open the NSS library. copied from services/crypto/modules/WeaveCrypto.js
michael@0 121 let path = ctypes.libraryName(libraryName);
michael@0 122
michael@0 123 // XXX really want to be able to pass specific dlopen flags here.
michael@0 124 let nsslib;
michael@0 125 try {
michael@0 126 nsslib = ctypes.open(path);
michael@0 127 } catch(e) {
michael@0 128 // In case opening the library without a full path fails,
michael@0 129 // try again with a full path.
michael@0 130 let file = Services.dirsvc.get("GreD", Ci.nsILocalFile);
michael@0 131 file.append(path);
michael@0 132 nsslib = ctypes.open(file.path);
michael@0 133 }
michael@0 134
michael@0 135 let SECStatus = ctypes.int;
michael@0 136 let func = nsslib.declare(functionName, ctypes.default_abi, SECStatus);
michael@0 137 return func;
michael@0 138 }
michael@0 139
michael@0 140 function clearOCSPCache() {
michael@0 141 let certdb = Cc["@mozilla.org/security/x509certdb;1"]
michael@0 142 .getService(Ci.nsIX509CertDB);
michael@0 143 certdb.clearOCSPCache();
michael@0 144 }
michael@0 145
michael@0 146 function clearSessionCache() {
michael@0 147 let SSL_ClearSessionCache = null;
michael@0 148 try {
michael@0 149 SSL_ClearSessionCache =
michael@0 150 _getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "ssl3");
michael@0 151 } catch (e) {
michael@0 152 // On Windows, this is actually in the nss3 library.
michael@0 153 SSL_ClearSessionCache =
michael@0 154 _getLibraryFunctionWithNoArguments("SSL_ClearSessionCache", "nss3");
michael@0 155 }
michael@0 156 if (!SSL_ClearSessionCache || SSL_ClearSessionCache() != 0) {
michael@0 157 throw "Failed to clear SSL session cache";
michael@0 158 }
michael@0 159 }
michael@0 160
michael@0 161 // Set up a TLS testing environment that has a TLS server running and
michael@0 162 // ready to accept connections. This async function starts the server and
michael@0 163 // waits for the server to indicate that it is ready.
michael@0 164 //
michael@0 165 // Each test should have its own subdomain of example.com, for example
michael@0 166 // my-first-connection-test.example.com. The server can use the server
michael@0 167 // name (passed through the SNI TLS extension) to determine what behavior
michael@0 168 // the server side of the text should exhibit. See TLSServer.h for more
michael@0 169 // information on how to write the server side of tests.
michael@0 170 //
michael@0 171 // Create a new source file for your new server executable in
michael@0 172 // security/manager/ssl/tests/unit/tlsserver/cmd similar to the other ones in
michael@0 173 // that directory, and add a reference to it to the sources variable in that
michael@0 174 // directory's moz.build.
michael@0 175 //
michael@0 176 // Modify TEST_HARNESS_BINS in
michael@0 177 // testing/mochitest/Makefile.in and NO_PKG_FILES in
michael@0 178 // toolkit/mozapps/installer/packager.mk to make sure the new executable
michael@0 179 // gets included in the packages used for shipping the tests to the test
michael@0 180 // runners in our build/test farm. (Things will work fine locally without
michael@0 181 // these changes but will break on TBPL.)
michael@0 182 //
michael@0 183 // Your test script should look something like this:
michael@0 184 /*
michael@0 185
michael@0 186 // -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 187 // This Source Code Form is subject to the terms of the Mozilla Public
michael@0 188 // License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 189 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 190 "use strict";
michael@0 191
michael@0 192 // <documentation on your test>
michael@0 193
michael@0 194 function run_test() {
michael@0 195 do_get_profile();
michael@0 196 add_tls_server_setup("<test-server-name>");
michael@0 197
michael@0 198 add_connection_test("<test-name-1>.example.com",
michael@0 199 getXPCOMStatusFromNSS(SEC_ERROR_xxx),
michael@0 200 function() { ... },
michael@0 201 function(aTransportSecurityInfo) { ... });
michael@0 202 [...]
michael@0 203 add_connection_test("<test-name-n>.example.com", Cr.NS_OK);
michael@0 204
michael@0 205 run_next_test();
michael@0 206 }
michael@0 207
michael@0 208 */
michael@0 209 function add_tls_server_setup(serverBinName) {
michael@0 210 add_test(function() {
michael@0 211 _setupTLSServerTest(serverBinName);
michael@0 212 });
michael@0 213 }
michael@0 214
michael@0 215 // Add a TLS connection test case. aHost is the hostname to pass in the SNI TLS
michael@0 216 // extension; this should unambiguously identifiy which test is being run.
michael@0 217 // aExpectedResult is the expected nsresult of the connection.
michael@0 218 // aBeforeConnect is a callback function that takes no arguments that will be
michael@0 219 // called before the connection is attempted.
michael@0 220 // aWithSecurityInfo is a callback function that takes an
michael@0 221 // nsITransportSecurityInfo, which is called after the TLS handshake succeeds.
michael@0 222 function add_connection_test(aHost, aExpectedResult,
michael@0 223 aBeforeConnect, aWithSecurityInfo) {
michael@0 224 const REMOTE_PORT = 8443;
michael@0 225
michael@0 226 function Connection(aHost) {
michael@0 227 this.host = aHost;
michael@0 228 let threadManager = Cc["@mozilla.org/thread-manager;1"]
michael@0 229 .getService(Ci.nsIThreadManager);
michael@0 230 this.thread = threadManager.currentThread;
michael@0 231 this.defer = Promise.defer();
michael@0 232 let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
michael@0 233 .getService(Ci.nsISocketTransportService);
michael@0 234 this.transport = sts.createTransport(["ssl"], 1, aHost, REMOTE_PORT, null);
michael@0 235 this.transport.setEventSink(this, this.thread);
michael@0 236 this.inputStream = null;
michael@0 237 this.outputStream = null;
michael@0 238 this.connected = false;
michael@0 239 }
michael@0 240
michael@0 241 Connection.prototype = {
michael@0 242 // nsITransportEventSink
michael@0 243 onTransportStatus: function(aTransport, aStatus, aProgress, aProgressMax) {
michael@0 244 if (!this.connected && aStatus == Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
michael@0 245 this.connected = true;
michael@0 246 this.outputStream.asyncWait(this, 0, 0, this.thread);
michael@0 247 }
michael@0 248 },
michael@0 249
michael@0 250 // nsIInputStreamCallback
michael@0 251 onInputStreamReady: function(aStream) {
michael@0 252 try {
michael@0 253 // this will throw if the stream has been closed by an error
michael@0 254 let str = NetUtil.readInputStreamToString(aStream, aStream.available());
michael@0 255 do_check_eq(str, "0");
michael@0 256 this.inputStream.close();
michael@0 257 this.outputStream.close();
michael@0 258 this.result = Cr.NS_OK;
michael@0 259 } catch (e) {
michael@0 260 this.result = e.result;
michael@0 261 }
michael@0 262 this.defer.resolve(this);
michael@0 263 },
michael@0 264
michael@0 265 // nsIOutputStreamCallback
michael@0 266 onOutputStreamReady: function(aStream) {
michael@0 267 let sslSocketControl = this.transport.securityInfo
michael@0 268 .QueryInterface(Ci.nsISSLSocketControl);
michael@0 269 sslSocketControl.proxyStartSSL();
michael@0 270 this.outputStream.write("0", 1);
michael@0 271 let inStream = this.transport.openInputStream(0, 0, 0)
michael@0 272 .QueryInterface(Ci.nsIAsyncInputStream);
michael@0 273 this.inputStream = inStream;
michael@0 274 this.inputStream.asyncWait(this, 0, 0, this.thread);
michael@0 275 },
michael@0 276
michael@0 277 go: function() {
michael@0 278 this.outputStream = this.transport.openOutputStream(0, 0, 0)
michael@0 279 .QueryInterface(Ci.nsIAsyncOutputStream);
michael@0 280 return this.defer.promise;
michael@0 281 }
michael@0 282 };
michael@0 283
michael@0 284 /* Returns a promise to connect to aHost that resolves to the result of that
michael@0 285 * connection */
michael@0 286 function connectTo(aHost) {
michael@0 287 Services.prefs.setCharPref("network.dns.localDomains", aHost);
michael@0 288 let connection = new Connection(aHost);
michael@0 289 return connection.go();
michael@0 290 }
michael@0 291
michael@0 292 add_test(function() {
michael@0 293 if (aBeforeConnect) {
michael@0 294 aBeforeConnect();
michael@0 295 }
michael@0 296 connectTo(aHost).then(function(conn) {
michael@0 297 do_check_eq(conn.result, aExpectedResult);
michael@0 298 if (aWithSecurityInfo) {
michael@0 299 aWithSecurityInfo(conn.transport.securityInfo
michael@0 300 .QueryInterface(Ci.nsITransportSecurityInfo));
michael@0 301 }
michael@0 302 run_next_test();
michael@0 303 });
michael@0 304 });
michael@0 305 }
michael@0 306
michael@0 307 function _getBinaryUtil(binaryUtilName) {
michael@0 308 let directoryService = Cc["@mozilla.org/file/directory_service;1"]
michael@0 309 .getService(Ci.nsIProperties);
michael@0 310
michael@0 311 let utilBin = directoryService.get("CurProcD", Ci.nsILocalFile);
michael@0 312 utilBin.append(binaryUtilName + (gIsWindows ? ".exe" : ""));
michael@0 313 // If we're testing locally, the above works. If not, the server executable
michael@0 314 // is in another location.
michael@0 315 if (!utilBin.exists()) {
michael@0 316 utilBin = directoryService.get("CurWorkD", Ci.nsILocalFile);
michael@0 317 while (utilBin.path.indexOf("xpcshell") != -1) {
michael@0 318 utilBin = utilBin.parent;
michael@0 319 }
michael@0 320 utilBin.append("bin");
michael@0 321 utilBin.append(binaryUtilName + (gIsWindows ? ".exe" : ""));
michael@0 322 }
michael@0 323 do_check_true(utilBin.exists());
michael@0 324 return utilBin;
michael@0 325 }
michael@0 326
michael@0 327 // Do not call this directly; use add_tls_server_setup
michael@0 328 function _setupTLSServerTest(serverBinName)
michael@0 329 {
michael@0 330 let certdb = Cc["@mozilla.org/security/x509certdb;1"]
michael@0 331 .getService(Ci.nsIX509CertDB);
michael@0 332 // The trusted CA that is typically used for "good" certificates.
michael@0 333 addCertFromFile(certdb, "tlsserver/test-ca.der", "CTu,u,u");
michael@0 334
michael@0 335 const CALLBACK_PORT = 8444;
michael@0 336
michael@0 337 let directoryService = Cc["@mozilla.org/file/directory_service;1"]
michael@0 338 .getService(Ci.nsIProperties);
michael@0 339 let envSvc = Cc["@mozilla.org/process/environment;1"]
michael@0 340 .getService(Ci.nsIEnvironment);
michael@0 341 let greDir = directoryService.get("GreD", Ci.nsIFile);
michael@0 342 envSvc.set("DYLD_LIBRARY_PATH", greDir.path);
michael@0 343 envSvc.set("LD_LIBRARY_PATH", greDir.path);
michael@0 344 envSvc.set("MOZ_TLS_SERVER_DEBUG_LEVEL", "3");
michael@0 345 envSvc.set("MOZ_TLS_SERVER_CALLBACK_PORT", CALLBACK_PORT);
michael@0 346
michael@0 347 let httpServer = new HttpServer();
michael@0 348 httpServer.registerPathHandler("/",
michael@0 349 function handleServerCallback(aRequest, aResponse) {
michael@0 350 aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
michael@0 351 aResponse.setHeader("Content-Type", "text/plain");
michael@0 352 let responseBody = "OK!";
michael@0 353 aResponse.bodyOutputStream.write(responseBody, responseBody.length);
michael@0 354 do_execute_soon(function() {
michael@0 355 httpServer.stop(run_next_test);
michael@0 356 });
michael@0 357 });
michael@0 358 httpServer.start(CALLBACK_PORT);
michael@0 359
michael@0 360 let serverBin = _getBinaryUtil(serverBinName);
michael@0 361 let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
michael@0 362 process.init(serverBin);
michael@0 363 let certDir = directoryService.get("CurWorkD", Ci.nsILocalFile);
michael@0 364 certDir.append("tlsserver");
michael@0 365 do_check_true(certDir.exists());
michael@0 366 process.run(false, [certDir.path], 1);
michael@0 367
michael@0 368 do_register_cleanup(function() {
michael@0 369 process.kill();
michael@0 370 });
michael@0 371 }
michael@0 372
michael@0 373 // Returns an Array of OCSP responses for a given ocspRespArray and a location
michael@0 374 // for a nssDB where the certs and public keys are prepopulated.
michael@0 375 // ocspRespArray is an array of arrays like:
michael@0 376 // [ [typeOfResponse, certnick, extracertnick]...]
michael@0 377 function generateOCSPResponses(ocspRespArray, nssDBlocation)
michael@0 378 {
michael@0 379 let utilBinName = "GenerateOCSPResponse";
michael@0 380 let ocspGenBin = _getBinaryUtil(utilBinName);
michael@0 381 let retArray = new Array();
michael@0 382
michael@0 383 for (let i = 0; i < ocspRespArray.length; i++) {
michael@0 384 let argArray = new Array();
michael@0 385 let ocspFilepre = do_get_file(i.toString() + ".ocsp", true);
michael@0 386 let filename = ocspFilepre.path;
michael@0 387 argArray.push(nssDBlocation);
michael@0 388 argArray.push(ocspRespArray[i][0]); // ocsRespType;
michael@0 389 argArray.push(ocspRespArray[i][1]); // nick;
michael@0 390 argArray.push(ocspRespArray[i][2]); // extranickname
michael@0 391 argArray.push(filename);
michael@0 392 do_print("arg_array ="+argArray);
michael@0 393
michael@0 394 let process = Cc["@mozilla.org/process/util;1"]
michael@0 395 .createInstance(Ci.nsIProcess);
michael@0 396 process.init(ocspGenBin);
michael@0 397 process.run(true, argArray, 5);
michael@0 398 do_check_eq(0, process.exitValue);
michael@0 399 let ocspFile = do_get_file(i.toString() + ".ocsp", false);
michael@0 400 retArray.push(readFile(ocspFile));
michael@0 401 ocspFile.remove(false);
michael@0 402 }
michael@0 403 return retArray;
michael@0 404 }
michael@0 405
michael@0 406 // Starts and returns an http responder that will cause a test failure if it is
michael@0 407 // queried. The server identities are given by a non-empty array
michael@0 408 // serverIdentities.
michael@0 409 function getFailingHttpServer(serverPort, serverIdentities) {
michael@0 410 let httpServer = new HttpServer();
michael@0 411 httpServer.registerPrefixHandler("/", function(request, response) {
michael@0 412 do_check_true(false);
michael@0 413 });
michael@0 414 httpServer.identity.setPrimary("http", serverIdentities.shift(), serverPort);
michael@0 415 serverIdentities.forEach(function(identity) {
michael@0 416 httpServer.identity.add("http", identity, serverPort);
michael@0 417 });
michael@0 418 httpServer.start(serverPort);
michael@0 419 return httpServer;
michael@0 420 }
michael@0 421
michael@0 422 // Starts an http OCSP responder that serves good OCSP responses and
michael@0 423 // returns an object with a method stop that should be called to stop
michael@0 424 // the http server.
michael@0 425 // NB: Because generating OCSP responses inside the HTTP request
michael@0 426 // handler can cause timeouts, the expected responses are pre-generated
michael@0 427 // all at once before starting the server. This means that their producedAt
michael@0 428 // times will all be the same. If a test depends on this not being the case,
michael@0 429 // perhaps calling startOCSPResponder twice (at different times) will be
michael@0 430 // necessary.
michael@0 431 //
michael@0 432 // serverPort is the port of the http OCSP responder
michael@0 433 // identity is the http hostname that will answer the OCSP requests
michael@0 434 // invalidIdentities is an array of identities that if used an
michael@0 435 // will cause a test failure
michael@0 436 // nssDBlocaion is the location of the NSS database from where the OCSP
michael@0 437 // responses will be generated (assumes appropiate keys are present)
michael@0 438 // expectedCertNames is an array of nicks of the certs to be responsed
michael@0 439 // expectedBasePaths is an optional array that is used to indicate
michael@0 440 // what is the expected base path of the OCSP request.
michael@0 441 function startOCSPResponder(serverPort, identity, invalidIdentities,
michael@0 442 nssDBLocation, expectedCertNames,
michael@0 443 expectedBasePaths, expectedMethods,
michael@0 444 expectedResponseTypes) {
michael@0 445 let ocspResponseGenerationArgs = expectedCertNames.map(
michael@0 446 function(expectedNick) {
michael@0 447 let responseType = "good";
michael@0 448 if (expectedResponseTypes && expectedResponseTypes.length >= 1) {
michael@0 449 responseType = expectedResponseTypes.shift();
michael@0 450 }
michael@0 451 return [responseType, expectedNick, "unused"];
michael@0 452 }
michael@0 453 );
michael@0 454 let ocspResponses = generateOCSPResponses(ocspResponseGenerationArgs,
michael@0 455 nssDBLocation);
michael@0 456 let httpServer = new HttpServer();
michael@0 457 httpServer.registerPrefixHandler("/",
michael@0 458 function handleServerCallback(aRequest, aResponse) {
michael@0 459 invalidIdentities.forEach(function(identity) {
michael@0 460 do_check_neq(aRequest.host, identity)
michael@0 461 });
michael@0 462 do_print("got request for: " + aRequest.path);
michael@0 463 let basePath = aRequest.path.slice(1).split("/")[0];
michael@0 464 if (expectedBasePaths.length >= 1) {
michael@0 465 do_check_eq(basePath, expectedBasePaths.shift());
michael@0 466 }
michael@0 467 do_check_true(expectedCertNames.length >= 1);
michael@0 468 if (expectedMethods && expectedMethods.length >= 1) {
michael@0 469 do_check_eq(aRequest.method, expectedMethods.shift());
michael@0 470 }
michael@0 471 aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
michael@0 472 aResponse.setHeader("Content-Type", "application/ocsp-response");
michael@0 473 aResponse.write(ocspResponses.shift());
michael@0 474 });
michael@0 475 httpServer.identity.setPrimary("http", identity, serverPort);
michael@0 476 invalidIdentities.forEach(function(identity) {
michael@0 477 httpServer.identity.add("http", identity, serverPort);
michael@0 478 });
michael@0 479 httpServer.start(serverPort);
michael@0 480 return {
michael@0 481 stop: function(callback) {
michael@0 482 // make sure we consumed each expected response
michael@0 483 do_check_eq(ocspResponses.length, 0);
michael@0 484 if (expectedBasePaths) {
michael@0 485 do_check_eq(expectedBasePaths.length, 0);
michael@0 486 }
michael@0 487 if (expectedResponseTypes) {
michael@0 488 do_check_eq(expectedResponseTypes.length, 0);
michael@0 489 }
michael@0 490 httpServer.stop(callback);
michael@0 491 }
michael@0 492 };
michael@0 493 }

mercurial