mongo/jstests/ssl/x509_extended_key_usage.js

121 lines
4.3 KiB
JavaScript

// Test server's adherence to serverAuth and clientAuth EKUs on X.509 certs.
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {isMacOS} from "jstests/ssl/libs/ssl_helpers.js";
const kServerAuthClientCert = "jstests/libs/client_with_serverAuth_eku.pem";
const kBothEKUsClientCert = "jstests/libs/client_with_serverAuth_and_clientAuth_eku.pem";
const kNoEKUsClientCert = "jstests/libs/client_without_eku.pem";
const kClientAuthClientCert = "jstests/libs/client.pem";
const kClientAuthServerCert = "jstests/libs/server_with_clientAuth_eku.pem";
const kBothEKUsServerCert = "jstests/libs/server.pem";
const kNoEKUsServerCert = "jstests/libs/server_without_eku.pem";
const kServerAuthServerCert = "jstests/libs/server_with_serverAuth_eku.pem";
const kCACert = "jstests/libs/ca.pem";
function testClientAuthEKU(conn, clientCert, shouldFail) {
clearRawMongoProgramOutput();
const exitCode = runMongoProgram(
"mongo",
"--tls",
"--tlsAllowInvalidHostnames",
"--tlsCertificateKeyFile",
clientCert,
"--tlsCAFile",
"jstests/libs/ca.pem",
"--port",
conn.port,
"--eval",
";",
);
let expectedFailureRegex = /unsuitable|unsupported certificate purpose/;
if (isMacOS()) {
expectedFailureRegex = /Certificate trust failure: Invalid Extended Key Usage for policy/;
} else if (_isWindows()) {
expectedFailureRegex = /The certificate is not valid for the requested usage./;
}
assert.soon(function () {
const output = rawMongoProgramOutput(".*");
clearRawMongoProgramOutput();
const isRegexPresent = expectedFailureRegex.test(output);
return (shouldFail && isRegexPresent) || (!shouldFail && !isRegexPresent);
});
}
function testServerAuthEKU(serverCert, shouldFail) {
const origSkipCheck = TestData.skipCheckDBHashes;
const rst = new ReplSetTest({
nodes: 2,
});
rst.startSet({
tlsMode: "requireTLS",
tlsCertificateKeyFile: serverCert,
tlsCAFile: kCACert,
tlsClusterFile: kBothEKUsServerCert,
tlsAllowInvalidHostnames: "",
});
if (shouldFail) {
const oldTimeout = ReplSetTest.kDefaultTimeoutMS;
const shortTimeout = 5 * 1000;
ReplSetTest.kDefaultTimeoutMS = shortTimeout;
rst.timeoutMS = shortTimeout;
MongoRunner.runHangAnalyzer.disable();
try {
assert.throws(function () {
rst.initiate();
});
} finally {
ReplSetTest.kDefaultTimeoutMS = oldTimeout;
MongoRunner.runHangAnalyzer.enable();
}
TestData.skipCheckDBHashes = true;
} else {
rst.initiate();
assert.commandWorked(rst.getPrimary().getDB("admin").runCommand({hello: 1}));
}
rst.stopSet();
TestData.skipCheckDBHashes = origSkipCheck;
}
// clientAuth tests against standalone.
{
const mongod = MongoRunner.runMongod({
auth: "",
tlsMode: "requireTLS",
// Server PEM file is server.pem to match the shell's ca.pem.
tlsCertificateKeyFile: "jstests/libs/server.pem",
tlsCAFile: "jstests/libs/ca.pem",
tlsAllowInvalidCertificates: "",
});
testClientAuthEKU(mongod, kClientAuthClientCert, false /* shouldFail */);
testClientAuthEKU(mongod, kNoEKUsClientCert, false /* shouldFail */);
testClientAuthEKU(mongod, kBothEKUsClientCert, false /* shouldFail */);
testClientAuthEKU(mongod, kServerAuthClientCert, true /* shouldFail */);
MongoRunner.stopMongod(mongod);
}
// serverAuth tests via replica set setup.
{
testServerAuthEKU(kServerAuthServerCert, false /* shouldFail */);
testServerAuthEKU(kBothEKUsServerCert, false /* shouldFail */);
testServerAuthEKU(kClientAuthServerCert, true /* shouldFail */);
// MacOS/Secure Transport's standard SSL cert verification policy is stricter than
// Windows and OpenSSL in that it requires server certificates to include the serverAuth
// EKU extension. Windows and OpenSSL accept server certificates that omit the EKU extension
// entirely and only care that serverAuth is specified if any EKU exists.
let shouldFailNoEKUsServerCert = false;
if (isMacOS()) {
shouldFailNoEKUsServerCert = true;
}
testServerAuthEKU(kNoEKUsServerCert, shouldFailNoEKUsServerCert /* shouldFail */);
}