Started work on server inner auth support in meshcmd.

Ylian Saint-Hilaire committed Apr 1, 2021 at 21:51 UTC e163bff7e3c185b31c37d62f893bbf6a954a9b18
3 files changed +43 -5
agents/meshcmd.js
+19
@@ -68,6 +68,7 @@ var FullSite_IntelAmtLocalWebApp = "H4sIAAAAAAAEAMQ5h3ajvNKvwu/9SnI2JICNa7zn4JLu
68 // Check the server certificate fingerprint
69 function onVerifyServer(clientName, certs) {
70 if (certs == null) { certs = clientName; } // Temporary thing until we fix duktape
71 + settings.meshServerTlsHash = certs[certs.length - 1].fingerprint.split(':').join(''); // This is used to delayed server authentication
72 try { for (var i in certs) { if (certs[i].fingerprint.replace(/:/g, '') == settings.serverhttpshash) { return; } } } catch (e) { }
73 if (settings.serverhttpshash != null) {
74 console.log('Error: Failed to verify server certificate.');
@@ -2038,10 +2039,28 @@ function OnServerWebSocket(msg, s, head) {
2039 }
2040 break;
2041 }
2042 + case 'serverAuth': {
2043 + // Check that the server certificate matches the serverid we have
2044 + var hasher = require('SHA384Stream').create();
2045 + var certDer = Buffer.from(command.cert, 'base64');
2046 + var cert = require('tls').loadCertificate({ der: certDer });
2047 + if (cert.getKeyHash().toString('hex') != settings.serverid) { console.log("Unable to authenticate the server, invalid server identifier."); process.exit(1); return; }
2048 +
2049 + // Hash the signed data and verify the server signature
2050 + var signDataHash = hasher.syncHash(Buffer.concat([Buffer.from(settings.serverAuthClientNonce, 'base64'), Buffer.from(settings.meshServerTlsHash, 'hex'), Buffer.from(command.nonce, 'base64')]));
2051 + 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; }
2052 +
2053 + console.log('Server is authenticated'); // TODO: Send username/password to server.
2054 + break;
2055 + }
2056 }
2057 });
2058 s.on('error', function () { console.log("Server connection error."); process.exit(1); return; });
2059 s.on('close', function () { console.log("Server closed the connection."); process.exit(1); return; });
2060 +
2061 + // Perform inner server authentication
2062 + //settings.serverAuthClientNonce = require('EncryptionStream').GenerateRandom(48).toString('base64');
2063 + //s.write("{\"action\":\"serverAuth\",\"cnonce\":\"" + settings.serverAuthClientNonce + "\",\"tlshash\":\"" + settings.meshServerTlsHash + "\"}"); // Ask for server authentication
2064 }
2065
2066 function startRouterEx() {
agents/meshcore.js
+6 -5
@@ -1344,7 +1344,8 @@ function getSystemInformation(func) {
1344 } catch (e) { }
1345 }
1346 results.hardware.agentvers = process.versions;
1347 - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1347 + var hasher = require('SHA384Stream').create();
1348 + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1349 func(results);
1350
1351 /*
@@ -1359,25 +1360,25 @@ function getSystemInformation(func) {
1360 p.then(function (res)
1361 {
1362 results.volumes = res;
1362 - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1363 + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1364 func(results);
1365 });
1366 }
1367 else if (require('identifiers').volumes != null)
1368 {
1369 results.volumes = require('identifiers').volumes();
1369 - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1370 + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1371 func(results);
1372 }
1373 else
1374 {
1374 - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1375 + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1376 func(results);
1377 }
1378 }
1379 else
1380 {
1380 - results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
1381 + results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1382 func(results);
1383 }
1384 */
meshuser.js
+18
@@ -5544,6 +5544,24 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5544 //console.log(command, file);
5545 break;
5546 }
5547 + case 'serverAuth': { // This command is used to perform server "inner" authentication.
5548 + if (common.validateString(command.cnonce, 1, 256) == false) break; // Check the client nonce
5549 + if (common.validateString(command.tlshash, 1, 512) == false) break; // Check the TLS hash
5550 +
5551 + // Check that the TLS hash is an acceptable one.
5552 + var h = Buffer.from(command.tlshash, 'hex').toString('binary');
5553 + if ((parent.webCertificateHashs[domain.id] != h) && (parent.webCertificateFullHashs[domain.id] != h) && (parent.defaultWebCertificateHash != h) && (parent.defaultWebCertificateFullHash != h)) { obj.close(); return; }
5554 +
5555 + // TLS hash check is a success, sign the request.
5556 + // Perform the hash signature using the server agent certificate
5557 + var nonce = parent.crypto.randomBytes(48);
5558 + var signData = Buffer.from(command.cnonce, 'base64').toString('binary') + h + nonce.toString('binary'); // Client Nonce + TLS Hash + Server Nonce
5559 + parent.parent.certificateOperations.acceleratorPerformSignature(0, signData, null, function (tag, signature) {
5560 + // Send back our certificate + nonce + signature
5561 + 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') }));
5562 + });
5563 + break;
5564 + }
5565 default: {
5566 // Unknown user action
5567 console.log('Unknown action from user ' + user.name + ': ' + command.action + '.');