Server peering fixes.

This commit is contained in:
Ylian Saint-Hilaire 2020-11-12 15:21:38 -08:00
parent e0977eac22
commit f36866b8fd
2 changed files with 22 additions and 13 deletions

View File

@ -60,7 +60,7 @@ module.exports.CreateMultiServer = function (parent, args) {
obj.connectionState = 1; obj.connectionState = 1;
// Get the web socket setup // Get the web socket setup
obj.ws = new WebSocket(obj.url + 'meshserver.ashx', { rejectUnauthorized: false, cert: obj.certificates.agent.cert, key: obj.certificates.agent.key }); obj.ws = new WebSocket(obj.url + 'meshserver.ashx', { rejectUnauthorized: false, servername: obj.certificates.CommonName, cert: obj.certificates.agent.cert, key: obj.certificates.agent.key });
obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Connecting to: ' + url + 'meshserver.ashx'); obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Connecting to: ' + url + 'meshserver.ashx');
// Register the connection failed event // Register the connection failed event
@ -75,8 +75,14 @@ module.exports.CreateMultiServer = function (parent, args) {
// Get the peer server's certificate and compute the server public key hash // Get the peer server's certificate and compute the server public key hash
if (obj.ws._socket == null) return; if (obj.ws._socket == null) return;
var serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(obj.ws._socket.getPeerCertificate().raw.toString('binary'))); if (obj.url.toLowerCase().startsWith('wss://')) {
obj.serverCertHash = obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() }); // We are using TLS, use the certificate hash
var serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(obj.ws._socket.getPeerCertificate().raw.toString('binary')));
obj.serverCertHash = obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
} else {
// We are not using TLS, blank out the TLS certificate hash
obj.serverCertHash = Buffer.alloc(48).toString('binary');
}
// Start authenticate the peer server by sending a auth nonce & server TLS cert hash. // Start authenticate the peer server by sending a auth nonce & server TLS cert hash.
// Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce // Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce
@ -98,13 +104,13 @@ module.exports.CreateMultiServer = function (parent, args) {
if (msg.length != 98) { obj.parent.parent.debug('peer', 'OutPeer: BAD MESSAGE(A1)'); return; } if (msg.length != 98) { obj.parent.parent.debug('peer', 'OutPeer: BAD MESSAGE(A1)'); return; }
// Check that the server hash matches the TLS server certificate public key hash // Check that the server hash matches the TLS server certificate public key hash
if (obj.serverCertHash != msg.substring(2, 50)) { obj.parent.parent.debug('peer', 'OutPeer: Server hash mismatch.'); disconnect(); return; } if (obj.url.toLowerCase().startsWith('wss://') && (obj.serverCertHash != msg.substring(2, 50))) { obj.parent.parent.debug('peer', 'OutPeer: Server hash mismatch.'); disconnect(); return; }
obj.servernonce = msg.substring(50); obj.servernonce = msg.substring(50);
// Perform the hash signature using the server agent certificate // Perform the hash signature using the server agent certificate
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, null, function (tag, signature) { obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, null, function (tag, signature) {
// Send back our certificate + signature // Send back our certificate + signature
obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); // Command 2, certificate + signature if (obj.ws != null) { obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); } // Command 2, certificate + signature
}); });
break; break;
@ -196,7 +202,7 @@ module.exports.CreateMultiServer = function (parent, args) {
if ((command.serverid != null) && (command.dbid != null)) { if ((command.serverid != null) && (command.dbid != null)) {
if (command.serverid == obj.parent.serverid) { console.log('ERROR: Same server ID, trying to peer with self. (' + obj.url + ', ' + command.serverid + ').'); return; } if (command.serverid == obj.parent.serverid) { console.log('ERROR: Same server ID, trying to peer with self. (' + obj.url + ', ' + command.serverid + ').'); return; }
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; } 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; }
if (obj.serverCertHash != command.serverCertHash) { console.log('ERROR: Outer certificate hash mismatch (2). (' + obj.url + ', ' + command.serverid + ').'); return; } if (obj.url.toLowerCase().startsWith('wss://') && (obj.serverCertHash != command.serverCertHash)) { console.log('ERROR: Outer certificate hash mismatch (2). (' + obj.url + ', ' + command.serverid + ').'); return; }
obj.peerServerId = command.serverid; obj.peerServerId = command.serverid;
obj.peerServerKey = Buffer.from(command.key, 'hex'); obj.peerServerKey = Buffer.from(command.key, 'hex');
obj.authenticated = 3; obj.authenticated = 3;
@ -215,9 +221,10 @@ module.exports.CreateMultiServer = function (parent, args) {
}; };
// Create a mesh server module that received a connection to another server // Create a mesh server module that received a connection to another server
obj.CreatePeerInServer = function (parent, ws, req) { obj.CreatePeerInServer = function (parent, ws, req, tls) {
var obj = {}; var obj = {};
obj.ws = ws; obj.ws = ws;
obj.tls = tls;
obj.parent = parent; obj.parent = parent;
obj.common = require('./common.js'); obj.common = require('./common.js');
obj.forge = require('node-forge'); obj.forge = require('node-forge');
@ -267,7 +274,7 @@ module.exports.CreateMultiServer = function (parent, args) {
obj.receivedCommands += 1; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path. obj.receivedCommands += 1; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
// Check that the server hash matches out own web certificate hash // Check that the server hash matches out own web certificate hash
if (obj.webCertificateHash != msg.substring(2, 50)) { obj.close(); return; } if ((obj.tls == true) && (obj.webCertificateHash != msg.substring(2, 50))) { obj.close(); return; }
obj.peernonce = msg.substring(50); obj.peernonce = msg.substring(50);
// Perform the hash signature using the server agent certificate // Perform the hash signature using the server agent certificate
@ -424,7 +431,8 @@ module.exports.CreateMultiServer = function (parent, args) {
// We connected to a peer server, setup everything // We connected to a peer server, setup everything
obj.SetupPeerServer = function (server, peerServerId) { obj.SetupPeerServer = function (server, peerServerId) {
console.log('Connected to peer server ' + peerServerId + '.'); obj.parent.debug('peer', 'Connected to peer server ' + peerServerId + '.');
//console.log('Connected to peer server ' + peerServerId + '.');
obj.peerServers[peerServerId] = server; obj.peerServers[peerServerId] = server;
// Send the list of connections to the peer // Send the list of connections to the peer
@ -436,7 +444,8 @@ module.exports.CreateMultiServer = function (parent, args) {
// We disconnected to a peer server, clean up everything // We disconnected to a peer server, clean up everything
obj.ClearPeerServer = function (server, peerServerId) { obj.ClearPeerServer = function (server, peerServerId) {
console.log('Disconnected from peer server ' + peerServerId + '.'); obj.parent.debug('peer', 'Disconnected from peer server ' + peerServerId + '.');
//console.log('Disconnected from peer server ' + peerServerId + '.');
// Clean up the connectivity state // Clean up the connectivity state
delete obj.peerServers[peerServerId]; delete obj.peerServers[peerServerId];
@ -600,7 +609,7 @@ module.exports.CreateMultiServer = function (parent, args) {
peerTunnel.connect = function () { peerTunnel.connect = function () {
// Get the web socket setup // Get the web socket setup
peerTunnel.parent.parent.debug('peer', 'FTunnel ' + peerTunnel.serverid + ': Start connect to ' + peerTunnel.url); peerTunnel.parent.parent.debug('peer', 'FTunnel ' + peerTunnel.serverid + ': Start connect to ' + peerTunnel.url);
peerTunnel.ws2 = new WebSocket(peerTunnel.url, { rejectUnauthorized: false }); 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 });
// Register the connection failed event // Register the connection failed event
peerTunnel.ws2.on('error', function (error) { peerTunnel.parent.parent.debug('peer', 'FTunnel ' + obj.serverid + ': Connection error'); peerTunnel.close(); }); 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) {
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, '$'); 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, '$');
// Check if the peer certificate is the expected one for this serverid // Check if the peer certificate is the expected one for this serverid
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; } 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; }
// Connection accepted, resume the web socket to start the data flow // Connection accepted, resume the web socket to start the data flow
peerTunnel.ws1._socket.resume(); peerTunnel.ws1._socket.resume();

View File

@ -4875,7 +4875,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
} }
// Setup all HTTP handlers // Setup all HTTP handlers
if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req); }); } if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req, obj.args.tlsoffload == null); }); }
for (var i in parent.config.domains) { for (var i in parent.config.domains) {
if (parent.config.domains[i].dns != null) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed. if (parent.config.domains[i].dns != null) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed.
var domain = parent.config.domains[i]; var domain = parent.config.domains[i];