Added swarm server IP filtering.

This commit is contained in:
Ylian Saint-Hilaire 2019-01-11 10:02:54 -08:00
parent b22be096d7
commit 8d21e843a6
20 changed files with 55 additions and 11 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -266,7 +266,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Decode the certificate
var certlen = obj.common.ReadShort(msg, 2);
obj.unauth = {};
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; }
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; }
obj.unauth.nodeCertPem = '-----BEGIN CERTIFICATE-----\r\n' + Buffer.from(msg.substring(4, 4 + certlen), 'binary').toString('base64') + '\r\n-----END CERTIFICATE-----';
// Check the agent signature if we can
@ -462,13 +462,43 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Verify the agent signature
function processAgentSignature(msg) {
if (obj.args.ignoreagenthashcheck !== true) {
// Verify the signature. This is the fast way, without using forge.
const verify = obj.parent.crypto.createVerify('SHA384');
verify.end(Buffer.from(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the private key hash
if (verify.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) {
const verify2 = obj.parent.crypto.createVerify('SHA384');
verify2.end(Buffer.from(getWebCertFullHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the full cert hash
if (verify2.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) { return false; }
var verified = false;
if (msg.length != 384) {
// Verify a PKCS7 signature.
var msgDer = null;
try { msgDer = obj.forge.asn1.fromDer(obj.forge.util.createBuffer(msg, 'binary')); } catch (ex) { }
if (msgDer != null) {
try {
var p7 = obj.forge.pkcs7.messageFromAsn1(msgDer);
var sig = p7.rawCapture.signature;
// Verify with key hash
var buf = Buffer.from(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary');
var verifier = obj.parent.crypto.createVerify('RSA-SHA384');
verifier.update(buf);
verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
if (verified == false) {
// Verify with full hash
buf = Buffer.from(getWebCertFullHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary');
verifier = obj.parent.crypto.createVerify('RSA-SHA384');
verifier.update(buf);
verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
}
if (verified == false) { return false; } // Not a valid signature
} catch (ex) { };
}
}
if (verified == false) {
// Verify the RSA signature. This is the fast way, without using forge.
const verify = obj.parent.crypto.createVerify('SHA384');
verify.end(Buffer.from(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the private key hash
if (verify.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) {
const verify2 = obj.parent.crypto.createVerify('SHA384');
verify2.end(Buffer.from(getWebCertFullHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the full cert hash
if (verify2.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) { return false; }
}
}
}

View File

@ -90,7 +90,7 @@ function CreateMeshCentralServer(config, args) {
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.
// Check for invalid arguments
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'];
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'];
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; } }
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; }
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) {
if (obj.args.notls == null && obj.args.redirport == null) obj.args.redirport = 80;
if (obj.args.minifycore === 0) obj.args.minifycore = false;
if (typeof obj.args.userallowedip == 'string') { if (obj.args.userallowedip == '') { obj.args.userallowedip = null; } else { obj.args.userallowedip = obj.args.userallowedip.split(','); } }
if (typeof obj.args.swarmallowedip == 'string') { if (obj.args.swarmallowedip == '') { obj.args.swarmallowedip = null; } else { obj.args.swarmallowedip = obj.args.swarmallowedip.split(','); } }
if (typeof obj.args.debug == 'number') obj.debugLevel = obj.args.debug;
if (obj.args.debug == true) obj.debugLevel = 1;
obj.db = require('./db.js').CreateDB(obj);

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.2.5-y",
"version": "0.2.6-d",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -122,7 +122,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
GUESTWEBRTCMESH: 2002 // Guest usage: WebRTC Mesh
};
obj.server = tls.createServer({ key: certificates.swarmserver.key, cert: certificates.swarmserver.cert, requestCert: true }, onConnection);
obj.server = tls.createServer({ key: certificates.swarmserver.key, cert: certificates.swarmserver.cert, requestCert: true, rejectUnauthorized: false }, onConnection);
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(); } });
loadMigrationAgents();
@ -147,6 +147,9 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
// Called when a legacy agent connects to this server
function onConnection(socket) {
// Check for blocked IP address
if (checkSwarmIpAddress(socket, obj.args.swarmallowedip) == false) { Debug(1, "SWARM:New blocked agent connection"); return; }
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", socket: socket };
socket.setEncoding('binary');
socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000);
@ -349,6 +352,16 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
}
}
// Check if the source IP address is allowed for a given allowed list, return false if not
function checkSwarmIpAddress(socket, allowedIpList) {
if (allowedIpList == null) { return true; }
try {
var ip = socket.remoteAddress;
if (ip) { for (var i = 0; i < allowedIpList.length; i++) { if (require('ipcheck').match(ip, allowedIpList[i])) { return true; } } }
} catch (e) { console.log(e); }
return false;
}
// Debug
function Debug(lvl) {
if (lvl > obj.parent.debugLevel) return;