Added swarm server IP filtering.

Ylian Saint-Hilaire committed Jan 11, 2019 at 10:02 UTC 8d21e843a687abd7dbdd79ea194f9e75cf8c57fa
20 files changed +55 -11
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshagent_arm
Binary files a/agents/meshagent_arm and b/agents/meshagent_arm differ
agents/meshagent_arm-linaro
Binary files a/agents/meshagent_arm-linaro and b/agents/meshagent_arm-linaro differ
agents/meshagent_armhf
Binary files a/agents/meshagent_armhf and b/agents/meshagent_armhf differ
agents/meshagent_pogo
Binary files a/agents/meshagent_pogo and b/agents/meshagent_pogo differ
agents/meshagent_poky
Binary files a/agents/meshagent_poky and b/agents/meshagent_poky differ
agents/meshagent_poky64
Binary files a/agents/meshagent_poky64 and b/agents/meshagent_poky64 differ
agents/meshagent_x86
Binary files a/agents/meshagent_x86 and b/agents/meshagent_x86 differ
agents/meshagent_x86-64
Binary files a/agents/meshagent_x86-64 and b/agents/meshagent_x86-64 differ
agents/meshagent_x86-64_nokvm
Binary files a/agents/meshagent_x86-64_nokvm and b/agents/meshagent_x86-64_nokvm differ
agents/meshagent_x86_nokvm
Binary files a/agents/meshagent_x86_nokvm and b/agents/meshagent_x86_nokvm differ
meshagent.js
+38 -8
@@ -266,7 +266,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
266 // Decode the certificate
267 var certlen = obj.common.ReadShort(msg, 2);
268 obj.unauth = {};
269 - try { obj.unauth.nodeid = Buffer.from(obj.forge.pki.getPublicKeyFingerprint(obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))).publicKey, { md: obj.forge.md.sha384.create() }).data, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); } catch (e) { return; }
269 + try { obj.unauth.nodeid = Buffer.from(obj.forge.pki.getPublicKeyFingerprint(obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))).publicKey, { md: obj.forge.md.sha384.create() }).data, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); } catch (ex) { console.log(ex); return; }
270 obj.unauth.nodeCertPem = '-----BEGIN CERTIFICATE-----\r\n' + Buffer.from(msg.substring(4, 4 + certlen), 'binary').toString('base64') + '\r\n-----END CERTIFICATE-----';
271
272 // Check the agent signature if we can
@@ -462,13 +462,43 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
462 // Verify the agent signature
463 function processAgentSignature(msg) {
464 if (obj.args.ignoreagenthashcheck !== true) {
465 - // Verify the signature. This is the fast way, without using forge.
466 - const verify = obj.parent.crypto.createVerify('SHA384');
467 - verify.end(Buffer.from(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the private key hash
468 - if (verify.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) {
469 - const verify2 = obj.parent.crypto.createVerify('SHA384');
470 - verify2.end(Buffer.from(getWebCertFullHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the full cert hash
471 - if (verify2.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) { return false; }
465 + var verified = false;
466 +
467 + if (msg.length != 384) {
468 + // Verify a PKCS7 signature.
469 + var msgDer = null;
470 + try { msgDer = obj.forge.asn1.fromDer(obj.forge.util.createBuffer(msg, 'binary')); } catch (ex) { }
471 + if (msgDer != null) {
472 + try {
473 + var p7 = obj.forge.pkcs7.messageFromAsn1(msgDer);
474 + var sig = p7.rawCapture.signature;
475 +
476 + // Verify with key hash
477 + var buf = Buffer.from(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary');
478 + var verifier = obj.parent.crypto.createVerify('RSA-SHA384');
479 + verifier.update(buf);
480 + verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
481 + if (verified == false) {
482 + // Verify with full hash
483 + buf = Buffer.from(getWebCertFullHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary');
484 + verifier = obj.parent.crypto.createVerify('RSA-SHA384');
485 + verifier.update(buf);
486 + verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
487 + }
488 + if (verified == false) { return false; } // Not a valid signature
489 + } catch (ex) { };
490 + }
491 + }
492 +
493 + if (verified == false) {
494 + // Verify the RSA signature. This is the fast way, without using forge.
495 + const verify = obj.parent.crypto.createVerify('SHA384');
496 + verify.end(Buffer.from(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the private key hash
497 + if (verify.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) {
498 + const verify2 = obj.parent.crypto.createVerify('SHA384');
499 + verify2.end(Buffer.from(getWebCertFullHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the full cert hash
500 + if (verify2.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) { return false; }
501 + }
502 }
503 }
504
meshcentral.js
+2 -1
@@ -90,7 +90,7 @@ function CreateMeshCentralServer(config, args) {
90 try { require('./pass').hash('test', function () { }); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
91
92 // Check for invalid arguments
93 - var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore'];
93 + var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'swarmallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore'];
94 for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
95 if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
96 for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence.
@@ -252,6 +252,7 @@ function CreateMeshCentralServer(config, args) {
252 if (obj.args.notls == null && obj.args.redirport == null) obj.args.redirport = 80;
253 if (obj.args.minifycore === 0) obj.args.minifycore = false;
254 if (typeof obj.args.userallowedip == 'string') { if (obj.args.userallowedip == '') { obj.args.userallowedip = null; } else { obj.args.userallowedip = obj.args.userallowedip.split(','); } }
255 + if (typeof obj.args.swarmallowedip == 'string') { if (obj.args.swarmallowedip == '') { obj.args.swarmallowedip = null; } else { obj.args.swarmallowedip = obj.args.swarmallowedip.split(','); } }
256 if (typeof obj.args.debug == 'number') obj.debugLevel = obj.args.debug;
257 if (obj.args.debug == true) obj.debugLevel = 1;
258 obj.db = require('./db.js').CreateDB(obj);
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.2.5-y",
3 + "version": "0.2.6-d",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
swarmserver.js
+14 -1
@@ -122,7 +122,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
122 GUESTWEBRTCMESH: 2002 // Guest usage: WebRTC Mesh
123 };
124
125 - obj.server = tls.createServer({ key: certificates.swarmserver.key, cert: certificates.swarmserver.cert, requestCert: true }, onConnection);
125 + obj.server = tls.createServer({ key: certificates.swarmserver.key, cert: certificates.swarmserver.cert, requestCert: true, rejectUnauthorized: false }, onConnection);
126 obj.server.listen(args.swarmport, function () { console.log('MeshCentral Legacy Swarm Server running on ' + certificates.CommonName + ':' + args.swarmport + '.'); obj.parent.updateServerState('swarm-port', args.swarmport); }).on('error', function (err) { console.error('ERROR: MeshCentral Swarm Server server port ' + args.swarmport + ' is not available.'); if (args.exactports) { process.exit(); } });
127 loadMigrationAgents();
128
@@ -147,6 +147,9 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
147
148 // Called when a legacy agent connects to this server
149 function onConnection(socket) {
150 + // Check for blocked IP address
151 + if (checkSwarmIpAddress(socket, obj.args.swarmallowedip) == false) { Debug(1, "SWARM:New blocked agent connection"); return; }
152 +
153 socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", socket: socket };
154 socket.setEncoding('binary');
155 socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000);
@@ -349,6 +352,16 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
352 }
353 }
354
355 + // Check if the source IP address is allowed for a given allowed list, return false if not
356 + function checkSwarmIpAddress(socket, allowedIpList) {
357 + if (allowedIpList == null) { return true; }
358 + try {
359 + var ip = socket.remoteAddress;
360 + if (ip) { for (var i = 0; i < allowedIpList.length; i++) { if (require('ipcheck').match(ip, allowedIpList[i])) { return true; } } }
361 + } catch (e) { console.log(e); }
362 + return false;
363 + }
364 +
365 // Debug
366 function Debug(lvl) {
367 if (lvl > obj.parent.debugLevel) return;