summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/unit/test_toolkit_securityreporter.js
blob: d7ffd17bd4c0ca163dca831cc4ab065e4873f6c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* This test is for the TLS error reporting functionality exposed by
 * SecurityReporter.js in /toolkit/components/securityreporter. The test is
 * here because we make use of the tlsserver functionality that lives with the
 * PSM ssl tests.
 *
 * The testing here will be augmented by the existing mochitests for the
 * error reporting functionality in aboutNetError.xhtml and
 * aboutCertError.xhtml once these make use of this component.
 */

"use strict";
const CC = Components.Constructor;
const Cm = Components.manager;

Cu.import("resource://testing-common/AppInfo.jsm");
/*global updateAppInfo:false*/ // Imported via AppInfo.jsm.
updateAppInfo();

// We must get the profile before performing operations on the cert db.
do_get_profile();

const certdb = Cc["@mozilla.org/security/x509certdb;1"]
                 .getService(Ci.nsIX509CertDB);
const reporter = Cc["@mozilla.org/securityreporter;1"]
                   .getService(Ci.nsISecurityReporter);


const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
                             "nsIBinaryInputStream", "setInputStream");

var server;

// this allows us to create a callback which checks that a report is as
// expected.
function getReportCheck(expectReport, expectedError) {
  return function sendReportWithInfo(transportSecurityInfo) {
    // register a path handler on the server
    server.registerPathHandler("/submit/sslreports",
                              function(request, response) {
      if (expectReport) {
        let report = JSON.parse(readDataFromRequest(request));
        do_check_eq(report.errorCode, expectedError);
        response.setStatusLine(null, 201, "Created");
        response.write("Created");
      } else {
        do_throw("No report should have been received");
      }
    });

    reporter.reportTLSError(transportSecurityInfo, "example.com", -1);
  };
}

// read the request body from a request
function readDataFromRequest(aRequest) {
  if (aRequest.method == "POST" || aRequest.method == "PUT") {
    if (aRequest.bodyInputStream) {
      let inputStream = new BinaryInputStream(aRequest.bodyInputStream);
      let bytes = [];
      let available;

      while ((available = inputStream.available()) > 0) {
        Array.prototype.push.apply(bytes, inputStream.readByteArray(available));
      }

      return String.fromCharCode.apply(null, bytes);
    }
  }
  return null;
}

function run_test() {
  // start a report server
  server = new HttpServer();
  server.start(-1);

  let port = server.identity.primaryPort;

  // Set the reporting URL to ensure any reports are sent to the test server
  Services.prefs.setCharPref("security.ssl.errorReporting.url",
                             `http://localhost:${port}/submit/sslreports`);
  // set strict-mode pinning enforcement so we can cause connection failures.
  Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);

  // start a TLS server
  add_tls_server_setup("BadCertServer", "bad_certs");

  // Add a user-specified trust anchor.
  addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");


  // Cause a reportable condition with error reporting disabled. No report
  // should be sent.
  Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", false);
  add_connection_test("expired.example.com",
                      SEC_ERROR_EXPIRED_CERTIFICATE, null,
                      getReportCheck(false));

  // Now enable reporting
  add_test(function () {
    Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
    run_next_test();
  });

  // test calling the component with no transportSecurityInfo. No report should
  // be sent even though reporting is enabled.
  add_test(function() {
    server.registerPathHandler("/submit/sslreports",
                               function(request, response) {
      do_throw("No report should be sent");
    });
    reporter.reportTLSError(null, "example.com", -1);
    run_next_test();
  });

  // Test sending a report with no error. This allows us to check the case
  // where there is no failed cert chain
  add_connection_test("good.include-subdomains.pinning.example.com",
                      PRErrorCodeSuccess, null,
                      getReportCheck(true, PRErrorCodeSuccess));

  // Test sending a report where there is an error and a failed cert chain.
  add_connection_test("expired.example.com",
                      SEC_ERROR_EXPIRED_CERTIFICATE, null,
                      getReportCheck(true, SEC_ERROR_EXPIRED_CERTIFICATE));

  run_next_test();
}