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;