summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/unit/test_keysize_ev.js
blob: 8e0edd7851f5c7639bb2c0f366824da4ac5d0beb (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/publicdomain/zero/1.0/
"use strict";

// Checks that RSA certs with key sizes below 2048 bits when verifying for EV
// are rejected.

do_get_profile(); // Must be called before getting nsIX509CertDB
const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
  Ci.nsIX509CertDB
);

const SERVER_PORT = 8888;

function getOCSPResponder(expectedCertNames) {
  let expectedPaths = expectedCertNames.slice();
  return startOCSPResponder(
    SERVER_PORT,
    "www.example.com",
    "test_keysize_ev/",
    expectedCertNames,
    expectedPaths
  );
}

function loadCert(certName, trustString) {
  let certFilename = "test_keysize_ev/" + certName + ".pem";
  addCertFromFile(certDB, certFilename, trustString);
  return constructCertFromFile(certFilename);
}

/**
 * Asynchronously runs a single EV key size test.
 *
 * @param {Array} expectedNamesForOCSP
 *        An array of nicknames of the certs to be responded to.
 * @param {string} rootCertFileName
 *        The file name of the root cert. Can begin with ".." to reference
 *        certs in folders other than "test_keysize_ev/".
 * @param {Array} intCertFileNames
 *        An array of file names of any intermediate certificates.
 * @param {string} endEntityCertFileName
 *        The file name of the end entity cert.
 * @param {boolean} expectedResult
 *        Whether the chain is expected to validate as EV.
 */
async function keySizeTestForEV(
  expectedNamesForOCSP,
  rootCertFileName,
  intCertFileNames,
  endEntityCertFileName,
  expectedResult
) {
  clearOCSPCache();
  let ocspResponder = getOCSPResponder(expectedNamesForOCSP);

  loadCert(rootCertFileName, "CTu,CTu,CTu");
  for (let intCertFileName of intCertFileNames) {
    loadCert(intCertFileName, ",,");
  }
  await checkEVStatus(
    certDB,
    constructCertFromFile(`test_keysize_ev/${endEntityCertFileName}.pem`),
    certificateUsageSSLServer,
    expectedResult
  );

  await stopOCSPResponder(ocspResponder);
}

/**
 * For debug builds which have the test EV roots compiled in, checks RSA chains
 * which contain certs with key sizes adequate for EV are validated as such,
 * while chains that contain any cert with an inadequate key size fail EV and
 * validate as DV.
 * For opt builds which don't have the test EV roots compiled in, checks that
 * none of the chains validate as EV.
 *
 * Note: This function assumes that the key size requirements for EV are greater
 * than the requirements for DV.
 *
 * @param {number} inadequateKeySize
 *        The inadequate key size of the generated certs.
 * @param {number} adequateKeySize
 *        The adequate key size of the generated certs.
 */
async function checkRSAChains(inadequateKeySize, adequateKeySize) {
  // Reuse the existing test RSA EV root
  let rootOKCertFileName = "../test_ev_certs/evroot";
  let rootOKName = "evroot";
  let rootNotOKName = "ev_root_rsa_" + inadequateKeySize;
  let intOKName = "ev_int_rsa_" + adequateKeySize;
  let intNotOKName = "ev_int_rsa_" + inadequateKeySize;
  let eeOKName = "ev_ee_rsa_" + adequateKeySize;
  let eeNotOKName = "ev_ee_rsa_" + inadequateKeySize;

  // Chain with certs that have adequate sizes for EV and DV
  // In opt builds, this chain is only validated for DV. Hence, an OCSP fetch
  // will for example not be done for the "ev_int_rsa_2048-evroot" intermediate
  // in such a build.
  let intFullName = intOKName + "-" + rootOKName;
  let eeFullName = eeOKName + "-" + intOKName + "-" + rootOKName;
  let expectedNamesForOCSP = [eeFullName];
  await keySizeTestForEV(
    expectedNamesForOCSP,
    rootOKCertFileName,
    [intFullName],
    eeFullName,
    gEVExpected
  );

  // Chain with a root cert that has an inadequate size for EV, but
  // adequate size for DV
  intFullName = intOKName + "-" + rootNotOKName;
  eeFullName = eeOKName + "-" + intOKName + "-" + rootNotOKName;
  expectedNamesForOCSP = [eeFullName];
  await keySizeTestForEV(
    expectedNamesForOCSP,
    rootNotOKName,
    [intFullName],
    eeFullName,
    false
  );

  // Chain with an intermediate cert that has an inadequate size for EV, but
  // adequate size for DV
  intFullName = intNotOKName + "-" + rootOKName;
  eeFullName = eeOKName + "-" + intNotOKName + "-" + rootOKName;
  expectedNamesForOCSP = [eeFullName];
  await keySizeTestForEV(
    expectedNamesForOCSP,
    rootOKCertFileName,
    [intFullName],
    eeFullName,
    false
  );

  // Chain with an end entity cert that has an inadequate size for EV, but
  // adequate size for DV
  intFullName = intOKName + "-" + rootOKName;
  eeFullName = eeNotOKName + "-" + intOKName + "-" + rootOKName;
  expectedNamesForOCSP = [eeFullName];
  await keySizeTestForEV(
    expectedNamesForOCSP,
    rootOKCertFileName,
    [intFullName],
    eeFullName,
    false
  );
}

add_task(async function () {
  Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
  Services.prefs.setIntPref("security.OCSP.enabled", 1);

  let smallKeyEVRoot = constructCertFromFile(
    "test_keysize_ev/ev_root_rsa_2040.pem"
  );
  equal(
    smallKeyEVRoot.sha256Fingerprint,
    "40:AB:5D:A5:89:15:A9:4B:82:87:B8:A6:9A:84:B1:DB:" +
      "7A:9D:DB:B8:4E:E1:23:E3:C6:64:E7:50:DC:35:8C:68",
    "test sanity check: the small-key EV root must have the same " +
      "fingerprint as the corresponding entry in ExtendedValidation.cpp"
  );

  await checkRSAChains(2040, 2048);
});