Server peering fixes.

Ylian Saint-Hilaire committed Nov 12, 2020 at 15:21 UTC f36866b8fd6f0d278513a136b2f814d48d3e0952
2 files changed +22 -13
multiserver.js
+21 -12
@@ -60,7 +60,7 @@ module.exports.CreateMultiServer = function (parent, args) {
60 obj.connectionState = 1;
61
62 // Get the web socket setup
63 - obj.ws = new WebSocket(obj.url + 'meshserver.ashx', { rejectUnauthorized: false, cert: obj.certificates.agent.cert, key: obj.certificates.agent.key });
63 + obj.ws = new WebSocket(obj.url + 'meshserver.ashx', { rejectUnauthorized: false, servername: obj.certificates.CommonName, cert: obj.certificates.agent.cert, key: obj.certificates.agent.key });
64 obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Connecting to: ' + url + 'meshserver.ashx');
65
66 // Register the connection failed event
@@ -75,8 +75,14 @@ module.exports.CreateMultiServer = function (parent, args) {
75
76 // Get the peer server's certificate and compute the server public key hash
77 if (obj.ws._socket == null) return;
78 - var serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(obj.ws._socket.getPeerCertificate().raw.toString('binary')));
79 - obj.serverCertHash = obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
78 + if (obj.url.toLowerCase().startsWith('wss://')) {
79 + // We are using TLS, use the certificate hash
80 + var serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(obj.ws._socket.getPeerCertificate().raw.toString('binary')));
81 + obj.serverCertHash = obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
82 + } else {
83 + // We are not using TLS, blank out the TLS certificate hash
84 + obj.serverCertHash = Buffer.alloc(48).toString('binary');
85 + }
86
87 // Start authenticate the peer server by sending a auth nonce & server TLS cert hash.
88 // Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce
@@ -98,13 +104,13 @@ module.exports.CreateMultiServer = function (parent, args) {
104 if (msg.length != 98) { obj.parent.parent.debug('peer', 'OutPeer: BAD MESSAGE(A1)'); return; }
105
106 // Check that the server hash matches the TLS server certificate public key hash
101 - if (obj.serverCertHash != msg.substring(2, 50)) { obj.parent.parent.debug('peer', 'OutPeer: Server hash mismatch.'); disconnect(); return; }
107 + if (obj.url.toLowerCase().startsWith('wss://') && (obj.serverCertHash != msg.substring(2, 50))) { obj.parent.parent.debug('peer', 'OutPeer: Server hash mismatch.'); disconnect(); return; }
108 obj.servernonce = msg.substring(50);
109
110 // Perform the hash signature using the server agent certificate
111 obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, null, function (tag, signature) {
112 // Send back our certificate + signature
107 - obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); // Command 2, certificate + signature
113 + if (obj.ws != null) { obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); } // Command 2, certificate + signature
114 });
115
116 break;
@@ -196,7 +202,7 @@ module.exports.CreateMultiServer = function (parent, args) {
202 if ((command.serverid != null) && (command.dbid != null)) {
203 if (command.serverid == obj.parent.serverid) { console.log('ERROR: Same server ID, trying to peer with self. (' + obj.url + ', ' + command.serverid + ').'); return; }
204 if (command.dbid != obj.parent.parent.db.identifier) { console.log('ERROR: Database ID mismatch. Trying to peer to a server with the wrong database. (' + obj.url + ', ' + command.serverid + ').'); return; }
199 - if (obj.serverCertHash != command.serverCertHash) { console.log('ERROR: Outer certificate hash mismatch (2). (' + obj.url + ', ' + command.serverid + ').'); return; }
205 + if (obj.url.toLowerCase().startsWith('wss://') && (obj.serverCertHash != command.serverCertHash)) { console.log('ERROR: Outer certificate hash mismatch (2). (' + obj.url + ', ' + command.serverid + ').'); return; }
206 obj.peerServerId = command.serverid;
207 obj.peerServerKey = Buffer.from(command.key, 'hex');
208 obj.authenticated = 3;
@@ -215,9 +221,10 @@ module.exports.CreateMultiServer = function (parent, args) {
221 };
222
223 // Create a mesh server module that received a connection to another server
218 - obj.CreatePeerInServer = function (parent, ws, req) {
224 + obj.CreatePeerInServer = function (parent, ws, req, tls) {
225 var obj = {};
226 obj.ws = ws;
227 + obj.tls = tls;
228 obj.parent = parent;
229 obj.common = require('./common.js');
230 obj.forge = require('node-forge');
@@ -267,7 +274,7 @@ module.exports.CreateMultiServer = function (parent, args) {
274 obj.receivedCommands += 1; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
275
276 // Check that the server hash matches out own web certificate hash
270 - if (obj.webCertificateHash != msg.substring(2, 50)) { obj.close(); return; }
277 + if ((obj.tls == true) && (obj.webCertificateHash != msg.substring(2, 50))) { obj.close(); return; }
278 obj.peernonce = msg.substring(50);
279
280 // Perform the hash signature using the server agent certificate
@@ -424,7 +431,8 @@ module.exports.CreateMultiServer = function (parent, args) {
431
432 // We connected to a peer server, setup everything
433 obj.SetupPeerServer = function (server, peerServerId) {
427 - console.log('Connected to peer server ' + peerServerId + '.');
434 + obj.parent.debug('peer', 'Connected to peer server ' + peerServerId + '.');
435 + //console.log('Connected to peer server ' + peerServerId + '.');
436 obj.peerServers[peerServerId] = server;
437
438 // Send the list of connections to the peer
@@ -436,7 +444,8 @@ module.exports.CreateMultiServer = function (parent, args) {
444
445 // We disconnected to a peer server, clean up everything
446 obj.ClearPeerServer = function (server, peerServerId) {
439 - console.log('Disconnected from peer server ' + peerServerId + '.');
447 + obj.parent.debug('peer', 'Disconnected from peer server ' + peerServerId + '.');
448 + //console.log('Disconnected from peer server ' + peerServerId + '.');
449
450 // Clean up the connectivity state
451 delete obj.peerServers[peerServerId];
@@ -600,7 +609,7 @@ module.exports.CreateMultiServer = function (parent, args) {
609 peerTunnel.connect = function () {
610 // Get the web socket setup
611 peerTunnel.parent.parent.debug('peer', 'FTunnel ' + peerTunnel.serverid + ': Start connect to ' + peerTunnel.url);
603 - peerTunnel.ws2 = new WebSocket(peerTunnel.url, { rejectUnauthorized: false });
612 + peerTunnel.ws2 = new WebSocket(peerTunnel.url, { rejectUnauthorized: false, servername: this.parent.parent.certificates.CommonName, cert: this.parent.parent.certificates.agent.cert, key: this.parent.parent.certificates.agent.key });
613
614 // Register the connection failed event
615 peerTunnel.ws2.on('error', function (error) { peerTunnel.parent.parent.debug('peer', 'FTunnel ' + obj.serverid + ': Connection error'); peerTunnel.close(); });
@@ -620,7 +629,7 @@ module.exports.CreateMultiServer = function (parent, args) {
629 var serverCertHashHex = Buffer.from(obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
630
631 // Check if the peer certificate is the expected one for this serverid
623 - if (obj.peerServers[serverid] == null || obj.peerServers[serverid].serverCertHash != serverCertHashHex) { console.log('ERROR: Outer certificate hash mismatch (1). (' + peerTunnel.url + ', ' + peerTunnel.serverid + ').'); peerTunnel.close(); return; }
632 + if ((obj.peerServers[serverid] == null) || (obj.peerServers[serverid].serverCertHash != serverCertHashHex)) { console.log('ERROR: Outer certificate hash mismatch (1). (' + peerTunnel.url + ', ' + peerTunnel.serverid + ').'); peerTunnel.close(); return; }
633
634 // Connection accepted, resume the web socket to start the data flow
635 peerTunnel.ws1._socket.resume();
webserver.js
+1 -1
@@ -4875,7 +4875,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4875 }
4876
4877 // Setup all HTTP handlers
4878 - if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req); }); }
4878 + if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req, obj.args.tlsoffload == null); }); }
4879 for (var i in parent.config.domains) {
4880 if (parent.config.domains[i].dns != null) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed.
4881 var domain = parent.config.domains[i];