Fixed agent update hash issue, connection hash issue, 2FA issue.
This commit is contained in:
parent
310e1b01f9
commit
2b2d25a0b6
45
meshagent.js
45
meshagent.js
|
@ -426,8 +426,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
obj.sendBinary(common.ShortToStr(1) + msg.substring(2, 50) + obj.nonce); // Command 1, hash + nonce. Use the web hash given by the agent.
|
obj.sendBinary(common.ShortToStr(1) + msg.substring(2, 50) + obj.nonce); // Command 1, hash + nonce. Use the web hash given by the agent.
|
||||||
} else {
|
} else {
|
||||||
// Check that the server hash matches our own web certificate hash (SHA384)
|
// Check that the server hash matches our own web certificate hash (SHA384)
|
||||||
const agentSeenCerthash = msg.substring(2, 50);
|
obj.agentSeenCerthash = msg.substring(2, 50);
|
||||||
if ((getWebCertHash(domain) != agentSeenCerthash) && (getWebCertFullHash(domain) != agentSeenCerthash) && (parent.defaultWebCertificateHash != agentSeenCerthash) && (parent.defaultWebCertificateFullHash != agentSeenCerthash)) {
|
if ((getWebCertHash(domain) != obj.agentSeenCerthash) && (getWebCertFullHash(domain) != obj.agentSeenCerthash) && (parent.defaultWebCertificateHash != obj.agentSeenCerthash) && (parent.defaultWebCertificateFullHash != obj.agentSeenCerthash)) {
|
||||||
if (parent.parent.supportsProxyCertificatesRequest !== false) {
|
if (parent.parent.supportsProxyCertificatesRequest !== false) {
|
||||||
obj.badWebCert = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64');
|
obj.badWebCert = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64');
|
||||||
parent.wsagentsWithBadWebCerts[obj.badWebCert] = obj; // Add this agent to the list of of agents with bad web certificates.
|
parent.wsagentsWithBadWebCerts[obj.badWebCert] = obj; // Add this agent to the list of of agents with bad web certificates.
|
||||||
|
@ -444,7 +444,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
// The hash matched one of the acceptable values, send the agent web hash back to the agent
|
// The hash matched one of the acceptable values, send the agent web hash back to the agent
|
||||||
// Send 384 bits SHA384 hash of TLS cert + 384 bits nonce
|
// Send 384 bits SHA384 hash of TLS cert + 384 bits nonce
|
||||||
// Command 1, hash + nonce. Use the web hash given by the agent.
|
// Command 1, hash + nonce. Use the web hash given by the agent.
|
||||||
obj.sendBinary(common.ShortToStr(1) + agentSeenCerthash + obj.nonce);
|
obj.sendBinary(common.ShortToStr(1) + obj.agentSeenCerthash + obj.nonce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1078,7 +1078,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
if (isIgnoreHashCheck() == false) {
|
if (isIgnoreHashCheck() == false) {
|
||||||
var verified = false;
|
var verified = false;
|
||||||
|
|
||||||
if (msg.length != 384) {
|
// Raw RSA signatures have an exact length of 256 or 384. PKCS7 is larger.
|
||||||
|
if ((msg.length != 384) && (msg.length != 256)) {
|
||||||
// Verify a PKCS7 signature.
|
// Verify a PKCS7 signature.
|
||||||
var msgDer = null;
|
var msgDer = null;
|
||||||
try { msgDer = forge.asn1.fromDer(forge.util.createBuffer(msg, 'binary')); } catch (ex) { }
|
try { msgDer = forge.asn1.fromDer(forge.util.createBuffer(msg, 'binary')); } catch (ex) { }
|
||||||
|
@ -1088,31 +1089,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
const sig = p7.rawCapture.signature;
|
const sig = p7.rawCapture.signature;
|
||||||
|
|
||||||
// Verify with key hash
|
// Verify with key hash
|
||||||
var buf = Buffer.from(getWebCertHash(domain) + obj.nonce + obj.agentnonce, 'binary');
|
var buf = Buffer.from(obj.agentSeenCerthash + obj.nonce + obj.agentnonce, 'binary');
|
||||||
var verifier = parent.crypto.createVerify('RSA-SHA384');
|
var verifier = parent.crypto.createVerify('RSA-SHA384');
|
||||||
verifier.update(buf);
|
verifier.update(buf);
|
||||||
verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
|
verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
|
||||||
if (verified !== true) {
|
|
||||||
// Verify with full hash
|
|
||||||
buf = Buffer.from(getWebCertFullHash(domain) + obj.nonce + obj.agentnonce, 'binary');
|
|
||||||
verifier = parent.crypto.createVerify('RSA-SHA384');
|
|
||||||
verifier.update(buf);
|
|
||||||
verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
|
|
||||||
}
|
|
||||||
if (verified !== true) {
|
|
||||||
// Verify with default key hash
|
|
||||||
buf = Buffer.from(parent.defaultWebCertificateHash + obj.nonce + obj.agentnonce, 'binary');
|
|
||||||
verifier = parent.crypto.createVerify('RSA-SHA384');
|
|
||||||
verifier.update(buf);
|
|
||||||
verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
|
|
||||||
}
|
|
||||||
if (verified !== true) {
|
|
||||||
// Verify with default full hash
|
|
||||||
buf = Buffer.from(parent.defaultWebCertificateFullHash + obj.nonce + obj.agentnonce, 'binary');
|
|
||||||
verifier = parent.crypto.createVerify('RSA-SHA384');
|
|
||||||
verifier.update(buf);
|
|
||||||
verified = verifier.verify(obj.unauth.nodeCertPem, sig, 'binary');
|
|
||||||
}
|
|
||||||
if (verified !== true) {
|
if (verified !== true) {
|
||||||
// Not a valid signature
|
// Not a valid signature
|
||||||
parent.agentStats.invalidPkcsSignatureCount++;
|
parent.agentStats.invalidPkcsSignatureCount++;
|
||||||
|
@ -1126,15 +1106,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
if (verified == false) {
|
if (verified == false) {
|
||||||
// Verify the RSA signature. This is the fast way, without using forge.
|
// Verify the RSA signature. This is the fast way, without using forge.
|
||||||
const verify = parent.crypto.createVerify('SHA384');
|
const verify = parent.crypto.createVerify('SHA384');
|
||||||
verify.end(Buffer.from(getWebCertHash(domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the private key hash
|
verify.end(Buffer.from(obj.agentSeenCerthash + obj.nonce + obj.agentnonce, 'binary')); // Test using the private key hash
|
||||||
if (verify.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) {
|
if (verify.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) {
|
||||||
const verify2 = parent.crypto.createVerify('SHA384');
|
parent.agentStats.invalidRsaSignatureCount++;
|
||||||
verify2.end(Buffer.from(getWebCertFullHash(domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the full cert hash
|
parent.setAgentIssue(obj, "invalidRsaSignature");
|
||||||
if (verify2.verify(obj.unauth.nodeCertPem, Buffer.from(msg, 'binary')) !== true) {
|
return false;
|
||||||
parent.agentStats.invalidRsaSignatureCount++;
|
|
||||||
parent.setAgentIssue(obj, "invalidRsaSignature");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1146,6 +1122,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
delete obj.agentnonce;
|
delete obj.agentnonce;
|
||||||
delete obj.unauth;
|
delete obj.unauth;
|
||||||
delete obj.receivedCommands;
|
delete obj.receivedCommands;
|
||||||
|
delete obj.agentSeenCerthash;
|
||||||
if (obj.unauthsign) delete obj.unauthsign;
|
if (obj.unauthsign) delete obj.unauthsign;
|
||||||
parent.agentStats.verifiedAgentConnectionCount++;
|
parent.agentStats.verifiedAgentConnectionCount++;
|
||||||
parent.parent.debug('agent', 'Verified agent connection to ' + obj.nodeid + ' (' + obj.remoteaddrport + ').');
|
parent.parent.debug('agent', 'Verified agent connection to ' + obj.nodeid + ' (' + obj.remoteaddrport + ').');
|
||||||
|
|
|
@ -2572,7 +2572,7 @@ function CreateMeshCentralServer(config, args) {
|
||||||
onZipData.x.zdata = concatData;
|
onZipData.x.zdata = concatData;
|
||||||
onZipData.x.zsize = concatData.length;
|
onZipData.x.zsize = concatData.length;
|
||||||
|
|
||||||
console.log('Packed', onZipData.x.size, onZipData.x.zsize);
|
//console.log('Packed', onZipData.x.size, onZipData.x.zsize);
|
||||||
}
|
}
|
||||||
const onZipError = function onZipError() { delete onZipData.x.zacc; }
|
const onZipError = function onZipError() { delete onZipData.x.zacc; }
|
||||||
obj.meshAgentBinaries[archid].zacc = [];
|
obj.meshAgentBinaries[archid].zacc = [];
|
||||||
|
@ -2598,6 +2598,13 @@ function CreateMeshCentralServer(config, args) {
|
||||||
var options = { sourcePath: agentpath, targetStream: hashStream, platform: obj.meshAgentsArchitectureNumbers[archid].platform };
|
var options = { sourcePath: agentpath, targetStream: hashStream, platform: obj.meshAgentsArchitectureNumbers[archid].platform };
|
||||||
if (obj.meshAgentBinaries[archid].pe != null) { options.peinfo = obj.meshAgentBinaries[archid].pe; }
|
if (obj.meshAgentBinaries[archid].pe != null) { options.peinfo = obj.meshAgentBinaries[archid].pe; }
|
||||||
obj.exeHandler.hashExecutableFile(options);
|
obj.exeHandler.hashExecutableFile(options);
|
||||||
|
|
||||||
|
// If we are not loading Windows binaries to RAM, compute the RAW file hash of the signed binaries here.
|
||||||
|
if ((obj.args.agentsinram === false) && ((archid == 3) || (archid == 4))) {
|
||||||
|
var hash = obj.crypto.createHash('sha384').update(obj.fs.readFileSync(agentpath));
|
||||||
|
obj.meshAgentBinaries[archid].fileHash = hash.digest('binary');
|
||||||
|
obj.meshAgentBinaries[archid].fileHashHex = Buffer.from(obj.meshAgentBinaries[archid].fileHash, 'binary').toString('hex');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((obj.meshAgentBinaries[3] == null) && (obj.meshAgentBinaries[10003] != null)) { obj.meshAgentBinaries[3] = obj.meshAgentBinaries[10003]; } // If only the unsigned windows binaries are present, use them.
|
if ((obj.meshAgentBinaries[3] == null) && (obj.meshAgentBinaries[10003] != null)) { obj.meshAgentBinaries[3] = obj.meshAgentBinaries[10003]; } // If only the unsigned windows binaries are present, use them.
|
||||||
|
|
|
@ -931,6 +931,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
r += 'AgentCertHash: ' + parent.agentCertificateHashHex;
|
r += 'AgentCertHash: ' + parent.agentCertificateHashHex;
|
||||||
for (var i in parent.webCertificateHashs) { r += '\r\nwebCertificateHash (' + i + '): ' + common.rstr2hex(parent.webCertificateHashs[i]); }
|
for (var i in parent.webCertificateHashs) { r += '\r\nwebCertificateHash (' + i + '): ' + common.rstr2hex(parent.webCertificateHashs[i]); }
|
||||||
for (var i in parent.webCertificateFullHashs) { r += '\r\nwebCertificateFullHash (' + i + '): ' + common.rstr2hex(parent.webCertificateFullHashs[i]); }
|
for (var i in parent.webCertificateFullHashs) { r += '\r\nwebCertificateFullHash (' + i + '): ' + common.rstr2hex(parent.webCertificateFullHashs[i]); }
|
||||||
|
r += '\r\ndefaultWebCertificateHash: ' + common.rstr2hex(parent.defaultWebCertificateHash);
|
||||||
|
r += '\r\ndefaultWebCertificateFullHash: ' + common.rstr2hex(parent.defaultWebCertificateFullHash);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'amtacm': {
|
case 'amtacm': {
|
||||||
|
|
|
@ -1945,14 +1945,13 @@
|
||||||
|
|
||||||
// Return the number of 2nd factor for this account
|
// Return the number of 2nd factor for this account
|
||||||
function count2factoraAuths() {
|
function count2factoraAuths() {
|
||||||
|
if (userinfo == null) return 0;
|
||||||
var authFactorCount = 0;
|
var authFactorCount = 0;
|
||||||
if (userinfo != null) {
|
if (userinfo.otpsecret == 1) { authFactorCount++; } // Authenticator time factor
|
||||||
if (userinfo.otpsecret == 1) { authFactorCount++; } // Authenticator time factor
|
if (userinfo.otphkeys > 0) { authFactorCount += userinfo.otphkeys; } // FIDO hardware factor
|
||||||
if (userinfo.otphkeys != null) { authFactorCount += userinfo.otphkeys; } // FIDO hardware factor
|
|
||||||
}
|
|
||||||
if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor
|
if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor
|
||||||
if ((features & 0x04000000) && (userinfo.phone != null)) { authFactorCount++; } // SMS factor
|
if ((features & 0x02000000) && (features & 0x04000000) && (userinfo.phone != null)) { authFactorCount++; } // SMS factor
|
||||||
if ((authFactorCount > 0) && (userinfo.otpkeys == 1)) { authFactorCount++; } // Backup keys
|
if ((authFactorCount > 0) && (userinfo.otpkeys > 0)) { authFactorCount++; } // Backup keys
|
||||||
return authFactorCount;
|
return authFactorCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9786,7 +9785,7 @@
|
||||||
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access this feature until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return false; }
|
if ((userinfo.emailVerified !== true) && (serverinfo.emailcheck == true) && (userinfo.siteadmin != 0xFFFFFFFF)) { setDialogMode(2, "Account Security", 1, null, "Unable to access this feature until a email address is verified. This is required for password recovery. Go to the \"My Account\" tab to change and verify an email address."); return false; }
|
||||||
|
|
||||||
// Remind the user to add two factor authentication
|
// Remind the user to add two factor authentication
|
||||||
if ((features & 0x00040000) && !((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0) || (userinfo.otpkeys > 0) || ((features & 0x02000000) && (features & 0x04000000) && (userinfo.phone != null)) || ((features & 0x00800000) && (userinfo.otpekey == 1)))) { setDialogMode(2, "Account Security", 1, null, "Unable to access this feature until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return false; }
|
if ((features & 0x00040000) && (count2factoraAuths() == 0)) { setDialogMode(2, "Account Security", 1, null, "Unable to access this feature until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return false; }
|
||||||
|
|
||||||
// We are allowed, let's prompt to information
|
// We are allowed, let's prompt to information
|
||||||
var x = "Create a new device group using the options below." + '<br /><br />';
|
var x = "Create a new device group using the options below." + '<br /><br />';
|
||||||
|
|
|
@ -108,14 +108,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform hash on web certificate and agent certificate
|
// Perform hash on web certificate and agent certificate
|
||||||
obj.webCertificateHash = obj.defaultWebCertificateHash = parent.certificateOperations.getPublicKeyHashBinary(obj.certificates.web.cert);
|
obj.webCertificateHash = parent.certificateOperations.getPublicKeyHashBinary(obj.certificates.web.cert);
|
||||||
obj.webCertificateHashs = { '': obj.webCertificateHash };
|
obj.webCertificateHashs = { '': obj.webCertificateHash };
|
||||||
obj.webCertificateHashBase64 = Buffer.from(obj.webCertificateHash, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
obj.webCertificateHashBase64 = Buffer.from(obj.webCertificateHash, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||||
obj.webCertificateFullHash = obj.defaultWebCertificateFullHash = parent.certificateOperations.getCertHashBinary(obj.certificates.web.cert);
|
obj.webCertificateFullHash = parent.certificateOperations.getCertHashBinary(obj.certificates.web.cert);
|
||||||
obj.webCertificateFullHashs = { '': obj.webCertificateFullHash };
|
obj.webCertificateFullHashs = { '': obj.webCertificateFullHash };
|
||||||
obj.agentCertificateHashHex = parent.certificateOperations.getPublicKeyHash(obj.certificates.agent.cert);
|
obj.agentCertificateHashHex = parent.certificateOperations.getPublicKeyHash(obj.certificates.agent.cert);
|
||||||
obj.agentCertificateHashBase64 = Buffer.from(obj.agentCertificateHashHex, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
obj.agentCertificateHashBase64 = Buffer.from(obj.agentCertificateHashHex, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||||
obj.agentCertificateAsn1 = parent.certificateOperations.forge.asn1.toDer(parent.certificateOperations.forge.pki.certificateToAsn1(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.agent.cert))).getBytes();
|
obj.agentCertificateAsn1 = parent.certificateOperations.forge.asn1.toDer(parent.certificateOperations.forge.pki.certificateToAsn1(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.agent.cert))).getBytes();
|
||||||
|
obj.defaultWebCertificateHash = parent.certificateOperations.getPublicKeyHashBinary(obj.certificates.webdefault.cert);
|
||||||
|
obj.defaultWebCertificateFullHash = parent.certificateOperations.getCertHashBinary(obj.certificates.webdefault.cert);
|
||||||
|
|
||||||
// Compute the hash of all of the web certificates for each domain
|
// Compute the hash of all of the web certificates for each domain
|
||||||
for (var i in obj.parent.config.domains) {
|
for (var i in obj.parent.config.domains) {
|
||||||
|
|
Loading…
Reference in New Issue