From e163bff7e3c185b31c37d62f893bbf6a954a9b18 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 1 Apr 2021 21:51:25 -0700 Subject: [PATCH] Started work on server inner auth support in meshcmd. --- agents/meshcmd.js | 19 +++++++++++++++++++ agents/meshcore.js | 11 ++++++----- meshuser.js | 18 ++++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/agents/meshcmd.js b/agents/meshcmd.js index 258ca318..12000f8a 100644 --- a/agents/meshcmd.js +++ b/agents/meshcmd.js @@ -68,6 +68,7 @@ var FullSite_IntelAmtLocalWebApp = "H4sIAAAAAAAEAMQ5h3ajvNKvwu/9SnI2JICNa7zn4JLu // Check the server certificate fingerprint function onVerifyServer(clientName, certs) { if (certs == null) { certs = clientName; } // Temporary thing until we fix duktape + settings.meshServerTlsHash = certs[certs.length - 1].fingerprint.split(':').join(''); // This is used to delayed server authentication try { for (var i in certs) { if (certs[i].fingerprint.replace(/:/g, '') == settings.serverhttpshash) { return; } } } catch (e) { } if (settings.serverhttpshash != null) { console.log('Error: Failed to verify server certificate.'); @@ -2038,10 +2039,28 @@ function OnServerWebSocket(msg, s, head) { } break; } + case 'serverAuth': { + // Check that the server certificate matches the serverid we have + var hasher = require('SHA384Stream').create(); + var certDer = Buffer.from(command.cert, 'base64'); + var cert = require('tls').loadCertificate({ der: certDer }); + if (cert.getKeyHash().toString('hex') != settings.serverid) { console.log("Unable to authenticate the server, invalid server identifier."); process.exit(1); return; } + + // Hash the signed data and verify the server signature + var signDataHash = hasher.syncHash(Buffer.concat([Buffer.from(settings.serverAuthClientNonce, 'base64'), Buffer.from(settings.meshServerTlsHash, 'hex'), Buffer.from(command.nonce, 'base64')])); + if (require('RSA').verify(require('RSA').TYPES.SHA384, cert, signDataHash, Buffer.from(command.signature, 'base64')) == false) { console.log("Unable to authenticate the server, invalid signature."); process.exit(1); return; } + + console.log('Server is authenticated'); // TODO: Send username/password to server. + break; + } } }); s.on('error', function () { console.log("Server connection error."); process.exit(1); return; }); s.on('close', function () { console.log("Server closed the connection."); process.exit(1); return; }); + + // Perform inner server authentication + //settings.serverAuthClientNonce = require('EncryptionStream').GenerateRandom(48).toString('base64'); + //s.write("{\"action\":\"serverAuth\",\"cnonce\":\"" + settings.serverAuthClientNonce + "\",\"tlshash\":\"" + settings.meshServerTlsHash + "\"}"); // Ask for server authentication } function startRouterEx() { diff --git a/agents/meshcore.js b/agents/meshcore.js index 91696200..27e48504 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -1344,7 +1344,8 @@ function getSystemInformation(func) { } catch (e) { } } results.hardware.agentvers = process.versions; - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex'); + var hasher = require('SHA384Stream').create(); + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); /* @@ -1359,25 +1360,25 @@ function getSystemInformation(func) { p.then(function (res) { results.volumes = res; - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex'); + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); }); } else if (require('identifiers').volumes != null) { results.volumes = require('identifiers').volumes(); - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex'); + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); } else { - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex'); + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); } } else { - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex'); + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex'); func(results); } */ diff --git a/meshuser.js b/meshuser.js index ece4bd3a..6172a09a 100644 --- a/meshuser.js +++ b/meshuser.js @@ -5544,6 +5544,24 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use //console.log(command, file); break; } + case 'serverAuth': { // This command is used to perform server "inner" authentication. + if (common.validateString(command.cnonce, 1, 256) == false) break; // Check the client nonce + if (common.validateString(command.tlshash, 1, 512) == false) break; // Check the TLS hash + + // Check that the TLS hash is an acceptable one. + var h = Buffer.from(command.tlshash, 'hex').toString('binary'); + if ((parent.webCertificateHashs[domain.id] != h) && (parent.webCertificateFullHashs[domain.id] != h) && (parent.defaultWebCertificateHash != h) && (parent.defaultWebCertificateFullHash != h)) { obj.close(); return; } + + // TLS hash check is a success, sign the request. + // Perform the hash signature using the server agent certificate + var nonce = parent.crypto.randomBytes(48); + var signData = Buffer.from(command.cnonce, 'base64').toString('binary') + h + nonce.toString('binary'); // Client Nonce + TLS Hash + Server Nonce + parent.parent.certificateOperations.acceleratorPerformSignature(0, signData, null, function (tag, signature) { + // Send back our certificate + nonce + signature + ws.send(JSON.stringify({ 'action': 'serverAuth', 'cert': Buffer.from(parent.agentCertificateAsn1, 'binary').toString('base64'), 'nonce': nonce.toString('base64'), 'signature': Buffer.from(signature,'binary').toString('base64') })); + }); + break; + } default: { // Unknown user action console.log('Unknown action from user ' + user.name + ': ' + command.action + '.');