forked from mongodb/mongo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssl_with_system_ca.js
164 lines (141 loc) · 6.73 KB
/
ssl_with_system_ca.js
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
// On OSX this test assumes that jstests/libs/trusted-ca.pem has been added as a trusted
// certificate to the login keychain of the evergreen user. See,
// https://github.com/10gen/buildhost-configuration/blob/f60ba13f506ef035d14e46fb5935f26ba3ca6bed/roles/macos/tasks/keychains.yml#L39-L100
// for details.
// To install trusted-ca.pem for local testing on OSX, invoke the following at a console:
// security add-trusted-cert -d jstests/libs/trusted-ca.pem
import {getPython3Binary} from "jstests/libs/python.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {copyCertificateFile} from "jstests/ssl/libs/ssl_helpers.js";
const HOST_TYPE = getBuildInfo().buildEnvironment.target_os;
jsTest.log("HOST_TYPE = " + HOST_TYPE);
if (HOST_TYPE == "macOS") {
// Ensure trusted-ca.pem is properly installed on MacOS hosts.
// (MacOS is the only OS where it is installed outside of this test)
let exitCode = runProgram("security", "verify-cert", "-c", "./jstests/libs/trusted-client.pem");
assert.eq(0, exitCode, 'Check for proper installation of Trusted CA on MacOS host');
}
if (HOST_TYPE == "windows") {
assert.eq(0, runProgram(getPython3Binary(), "jstests/ssl_linear/windows_castore_cleanup.py"));
// OpenSSL backed imports Root CA and intermediate CA
runProgram("certutil.exe", "-addstore", "-user", "-f", "CA", "jstests\\libs\\trusted-ca.pem");
// SChannel backed follows Windows rules and only trusts the Root store in Local Machine and
// Current User.
runProgram("certutil.exe", "-addstore", "-f", "Root", "jstests\\libs\\trusted-ca.pem");
}
const certDir = MongoRunner.toRealDir("$dataDir/ssl_with_system_ca_test/");
if (HOST_TYPE == "linux") {
mkdir(certDir);
clearRawMongoProgramOutput();
assert.eq(
0, runProgram("openssl", "x509", "-hash", "-noout", "-in", "jstests/libs/trusted-ca.pem"));
let hash = rawMongoProgramOutput(".*");
jsTestLog(hash); // has form: "|sh<pid> <hash>\n"
hash = hash.trim().split(" ")[1];
copyCertificateFile("jstests/libs/trusted-ca.pem", `${certDir}/${hash}.0`);
}
// Tests server ingress validation works if the server is configured to use system CA.
function testServerIngress() {
jsTestLog("Running testServerIngress");
// Start a mongod configured with sslPEMKeyFile = trusted-server.pem,
// and a system CA store containing trusted-ca.pem.
const serverOpts = {
tlsMode: 'preferTLS',
tlsCertificateKeyFile: 'jstests/libs/trusted-server.pem',
tlsAllowInvalidHostnames: "",
waitForConnect: true,
setParameter: {tlsUseSystemCA: true},
env: {"SSL_CERT_DIR": certDir},
};
const conn = MongoRunner.runMongod(serverOpts);
// Using trusted keys, the client should be able to connect.
jsTestLog("Testing server ingress validates trusted client certificate");
let clientOpts = {
tls: {
certificateKeyFile: "jstests/libs/trusted-client.pem",
CAFile: "jstests/libs/trusted-ca.pem",
allowInvalidHostnames: true,
}
};
assert.doesNotThrow(() => {
let newConn = new Mongo(conn.host, undefined, clientOpts);
assert.commandWorked(newConn.getDB('admin').runCommand({buildinfo: 1}));
});
// Using untrusted keys, verify the server rejects the client.
jsTestLog("Testing server ingress rejects untrusted client certificate");
clientOpts.tls.certificateKeyFile = "jstests/libs/client.pem";
assert.commandWorked(conn.adminCommand({clearLog: 'global'}));
let error = assert.throwsWithCode(
() => {
new Mongo(conn.host, undefined, clientOpts);
},
[
ErrorCodes.SocketException,
ErrorCodes.HostUnreachable
]); // Different error depending on OS
assert(error.reason.includes("handshake failed"), error.reason);
checkLog.containsRelaxedJson(conn, 22988, {error: {code: ErrorCodes.SSLHandshakeFailed}});
jsTestLog("Stopping mongod...");
MongoRunner.stopMongod(conn);
}
// Tests server egress validation works if the server is configured to use system CA.
function testServerEgress() {
jsTest.log("Running testServerEgress");
// Start a replica set with one mongod configured with sslPEMKeyFile = trusted-server.pem,
// and a system CA store containing trusted-ca.pem.
const rst = new ReplSetTest({nodes: 1});
rst.startSet({
tlsMode: 'preferTLS',
tlsCertificateKeyFile: 'jstests/libs/trusted-server.pem', // used on ingress
tlsClusterFile: 'jstests/libs/trusted-client.pem', // used on egress to node2
tlsAllowInvalidHostnames: "",
waitForConnect: true,
setParameter: {tlsUseSystemCA: true},
env: {"SSL_CERT_DIR": certDir},
});
rst.initiate();
rst.awaitReplication();
let conn = rst.getPrimary();
// Add new node that uses a key not trusted by the first node.
let badNode = rst.add({
tlsMode: 'preferTLS',
tlsCertificateKeyFile: "jstests/libs/server.pem", // used on ingress, untrusted
tlsClusterFile: "jstests/libs/trusted-client.pem", // used on egress to node1
tlsCAFile: "jstests/libs/trusted-ca.pem",
tlsAllowInvalidHostnames: "",
waitForConnect: true,
});
assert.commandWorked(conn.adminCommand({clearLog: 'global'}));
jsTestLog("Reinitiating replica set with one additional node using untrusted key file");
rst.reInitiate();
// Verify node 1 can't connect to node 2
checkLog.containsRelaxedJson(conn, 23722, {responseStatus: {code: ErrorCodes.HostUnreachable}});
rst.remove(rst.getNodeId(badNode));
// Add new node that uses a key trusted by the first node.
let goodNode = rst.add({
tlsMode: 'preferTLS',
tlsCertificateKeyFile: "jstests/libs/trusted-server.pem", // used on ingress, trusted
tlsClusterFile: "jstests/libs/trusted-client.pem", // used on egress to node1
tlsCAFile: "jstests/libs/trusted-ca.pem",
tlsAllowInvalidHostnames: "",
waitForConnect: true,
});
assert.commandWorked(conn.adminCommand({clearLog: 'global'}));
jsTestLog("Reinitiating replica set with one additional node using trusted key file");
rst.reInitiate();
rst.awaitSecondaryNodes();
// Verify node 1 can now connect to node 2
assert.commandWorked(conn.adminCommand({replSetTestEgress: 1}));
jsTestLog("Stopping the replica set...");
rst.stopSet();
}
try {
testServerIngress();
testServerEgress();
} finally {
if (HOST_TYPE == "windows") {
const trusted_ca_thumbprint = cat('jstests/libs/trusted-ca.pem.digest.sha1');
runProgram("certutil.exe", "-delstore", "-f", "Root", trusted_ca_thumbprint);
runProgram("certutil.exe", "-delstore", "-user", "-f", "CA", trusted_ca_thumbprint);
}
}