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 + '.');