Skip to content

Commit 8537892

Browse files
committed
Introduced TRUST_ALL_CERTIFICATES
This option requires encryption but does no checks on the server's certificate. It is just required to be present.
1 parent 3a7caad commit 8537892

File tree

8 files changed

+146
-44
lines changed

8 files changed

+146
-44
lines changed

src/v1/index.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ let USER_AGENT = "neo4j-javascript/" + VERSION;
6666
* // this is that if you don't know who you are talking to, it is easy for an
6767
* // attacker to hijack your encrypted connection, rendering encryption pointless.
6868
* //
69-
* // TRUST_ON_FIRST_USE is the default for modern NodeJS deployments, and works
69+
* // TRUST_ALL_CERTIFICATES is the default choice for NodeJS deployments. It only requires
70+
* // new host to provide a certificate and does no verification of the provided certificate.
71+
* //
72+
* // TRUST_ON_FIRST_USE is available for modern NodeJS deployments, and works
7073
* // similarly to how `ssl` works - the first time we connect to a new host,
7174
* // we remember the certificate they use. If the certificate ever changes, we
7275
* // assume it is an attempt to hijack the connection and require manual intervention.
@@ -81,8 +84,8 @@ let USER_AGENT = "neo4j-javascript/" + VERSION;
8184
* //
8285
* // TRUST_SYSTEM_CA_SIGNED_CERTIFICATES meand that you trust whatever certificates
8386
* // are in the default certificate chain of th
84-
* trust: "TRUST_ON_FIRST_USE" | "TRUST_SIGNED_CERTIFICATES" | TRUST_CUSTOM_CA_SIGNED_CERTIFICATES |
85-
* TRUST_SYSTEM_CA_SIGNED_CERTIFICATES,
87+
* trust: "TRUST_ALL_CERTIFICATES" | "TRUST_ON_FIRST_USE" | "TRUST_SIGNED_CERTIFICATES" |
88+
* "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES" | "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES",
8689
*
8790
* // List of one or more paths to trusted encryption certificates. This only
8891
* // works in the NodeJS bundle, and only matters if you use "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES".

src/v1/internal/ch-node.js

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@
1616
* See the License for the specific language governing permissions and
1717
* limitations under the License.
1818
*/
19-
20-
import net from 'net';
21-
import tls from 'tls';
22-
import fs from 'fs';
23-
import path from 'path';
24-
import {EOL} from 'os';
25-
import {NodeBuffer} from './buf';
26-
import {ENCRYPTION_OFF} from './util';
27-
import {newError, SESSION_EXPIRED} from './../error';
19+
import net from "net";
20+
import tls from "tls";
21+
import fs from "fs";
22+
import path from "path";
23+
import {EOL} from "os";
24+
import {NodeBuffer} from "./buf";
25+
import {ENCRYPTION_OFF, isEmptyObjectOrNull} from "./util";
26+
import {newError, SESSION_EXPIRED} from "./../error";
2827

2928
let _CONNECTION_IDGEN = 0;
3029

@@ -119,7 +118,7 @@ const TrustStrategy = {
119118
"to verify trust for encrypted connections, but have not configured any " +
120119
"trustedCertificates. You must specify the path to at least one trusted " +
121120
"X.509 certificate for this to work. Two other alternatives is to use " +
122-
"TRUST_ON_FIRST_USE or to disable encryption by setting encrypted=\"" + ENCRYPTION_OFF + "\"" +
121+
"TRUST_ALL_CERTIFICATES or to disable encryption by setting encrypted=\"" + ENCRYPTION_OFF + "\"" +
123122
"in your driver configuration."));
124123
return;
125124
}
@@ -227,6 +226,26 @@ const TrustStrategy = {
227226
});
228227
socket.on('error', onFailure);
229228
return socket;
229+
},
230+
231+
TRUST_ALL_CERTIFICATES: function (opts, onSuccess, onFailure) {
232+
const tlsOpts = {
233+
rejectUnauthorized: false
234+
};
235+
const socket = tls.connect(opts.port, opts.host, tlsOpts, function () {
236+
const certificate = socket.getPeerCertificate();
237+
if (isEmptyObjectOrNull(certificate)) {
238+
onFailure(newError("Secure connection was successful but server did not return any valid " +
239+
"certificates. Such connection can not be trusted. If you are just trying " +
240+
" Neo4j out and are not concerned about encryption, simply disable it using " +
241+
"`encrypted=\"" + ENCRYPTION_OFF + "\"` in the driver options. " +
242+
"Socket responded with: " + socket.authorizationError));
243+
} else {
244+
onSuccess();
245+
}
246+
});
247+
socket.on('error', onFailure);
248+
return socket;
230249
}
231250
};
232251

@@ -240,7 +259,7 @@ function connect( opts, onSuccess, onFailure=(()=>null) ) {
240259
return TrustStrategy[opts.trust](opts, onSuccess, onFailure);
241260
} else {
242261
onFailure(newError("Unknown trust strategy: " + opts.trust + ". Please use either " +
243-
"trust:'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' or trust:'TRUST_ON_FIRST_USE' in your driver " +
262+
"trust:'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' or trust:'TRUST_ALL_CERTIFICATES' in your driver " +
244263
"configuration. Alternatively, you can disable encryption by setting " +
245264
"`encrypted:\"" + ENCRYPTION_OFF + "\"`. There is no mechanism to use encryption without trust verification, " +
246265
"because this incurs the overhead of encryption without improving security. If " +

src/v1/internal/connector.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,9 @@ function connect( url, config = {}) {
468468
host: parseHost(url),
469469
port: parsePort(url) || 7687,
470470
// Default to using encryption if trust-on-first-use is available
471-
encrypted : (config.encrypted == null) ? hasFeature("trust_on_first_use") : config.encrypted,
472-
// Default to using TRUST_ON_FIRST_USE if it is available
473-
trust : config.trust || (hasFeature("trust_on_first_use") ? "TRUST_ON_FIRST_USE" : "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES"),
471+
encrypted : (config.encrypted == null) ? hasFeature("trust_all_certificates") : config.encrypted,
472+
// Default to using TRUST_ALL_CERTIFICATES if it is available
473+
trust : config.trust || (hasFeature("trust_all_certificates") ? "TRUST_ALL_CERTIFICATES" : "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES"),
474474
trustedCertificates : config.trustedCertificates || [],
475475
knownHosts : config.knownHosts
476476
}), url);

src/v1/internal/features.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,20 @@ const FEATURES = {
2626
// This is insane. We are verifying that we have a version of getPeerCertificate
2727
// that supports reading the whole certificate, eg this commit:
2828
// https://github.com/nodejs/node/commit/345c40b6
29-
let desc = require('tls').TLSSocket.prototype.getPeerCertificate;
30-
return desc.length >= 1;
29+
const getPeerCertificateFunction = require('tls').TLSSocket.prototype.getPeerCertificate;
30+
const numberOfParameters = getPeerCertificateFunction.length;
31+
return numberOfParameters >= 1;
3132
} catch( e ) {
3233
return false;
3334
}
35+
},
36+
trust_all_certificates: () => {
37+
try {
38+
const getPeerCertificateFunction = require('tls').TLSSocket.prototype.getPeerCertificate;
39+
return true;
40+
} catch (e) {
41+
return false;
42+
}
3443
}
3544
};
3645

src/v1/internal/util.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,22 @@
2020
const ENCRYPTION_ON = "ENCRYPTION_ON";
2121
const ENCRYPTION_OFF = "ENCRYPTION_OFF";
2222

23+
function isEmptyObjectOrNull(object) {
24+
if (!object) {
25+
return true;
26+
}
27+
28+
for (let prop in object) {
29+
if (object.hasOwnProperty(prop)) {
30+
return false;
31+
}
32+
}
33+
34+
return true;
35+
}
36+
2337
export {
38+
isEmptyObjectOrNull,
2439
ENCRYPTION_ON,
2540
ENCRYPTION_OFF
2641
}

test/internal/tls.test.js

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* See the License for the specific language governing permissions and
1717
* limitations under the License.
1818
*/
19-
var NodeChannel = require('../../lib/v1/internal/ch-node.js');
19+
var NodeChannel = require('../../lib/v1/internal/ch-node.js').default;
2020
var neo4j = require("../../lib/v1");
2121
var fs = require("fs");
2222
var path = require('path');
@@ -25,9 +25,9 @@ var hasFeature = require("../../lib/v1/internal/features").default;
2525
describe('trust-signed-certificates', function() {
2626

2727
var driver;
28-
var log = console.log;
28+
var log;
2929
beforeEach(function() {
30-
console.log = function () {}; // To mute deprecation message in test output
30+
log = muteConsoleLog();
3131
});
3232
it('should reject unknown certificates', function(done) {
3333
// Assuming we only run this test on NodeJS
@@ -90,7 +90,37 @@ describe('trust-signed-certificates', function() {
9090
if( driver ) {
9191
driver.close();
9292
}
93-
console.log = log;
93+
unMuteConsoleLog(log);
94+
});
95+
});
96+
97+
describe('trust-all-certificates', function () {
98+
99+
var driver;
100+
it('should work with default certificate', function (done) {
101+
// Assuming we only run this test on NodeJS with TAC support
102+
if (!hasFeature("trust_all_certificates")) {
103+
done();
104+
return;
105+
}
106+
107+
// Given
108+
driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {
109+
encrypted: "ENCRYPTION_ON",
110+
trust: "TRUST_ALL_CERTIFICATES"
111+
});
112+
113+
// When
114+
driver.session().run("RETURN 1").then(function (result) {
115+
expect(result.records[0].get(0).toNumber()).toBe(1);
116+
done();
117+
});
118+
});
119+
120+
afterEach(function () {
121+
if (driver) {
122+
driver.close();
123+
}
94124
});
95125
});
96126

@@ -171,7 +201,12 @@ describe('trust-system-ca-signed-certificates', function() {
171201
describe('trust-on-first-use', function() {
172202

173203
var driver;
204+
var log;
205+
beforeEach(function() {
206+
log = muteConsoleLog();
207+
});
174208
afterEach(function(){
209+
unMuteConsoleLog(log);
175210
if( driver ) {
176211
driver.close();
177212
}
@@ -364,3 +399,14 @@ describe('trust-on-first-use', function() {
364399
}
365400
});
366401
});
402+
403+
// To mute deprecation message in test output
404+
function muteConsoleLog() {
405+
const originalLog = console.log;
406+
console.log = () => {};
407+
return originalLog;
408+
}
409+
410+
function unMuteConsoleLog(originalLog) {
411+
console.log = originalLog;
412+
}

test/v1/direct.driver.boltkit.it.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ describe('direct driver', function() {
3333
var server = kit.start('./test/resources/boltkit/return_x.script', 9001);
3434

3535
kit.run(function () {
36-
var driver = neo4j.driver("bolt://localhost:9001", neo4j.auth.basic("neo4j", "neo4j"));
36+
// BoltKit currently does not support encryption, create driver with encryption turned off
37+
var driver = neo4j.driver("bolt://localhost:9001", neo4j.auth.basic("neo4j", "neo4j"), {
38+
encrypted: "ENCRYPTION_OFF"
39+
});
3740
// When
3841
var session = driver.session();
3942
// Then

0 commit comments

Comments
 (0)