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