Fixed many TLS-SNI problems, updated agents
This commit is contained in:
parent
d30b5f348e
commit
7f76495d72
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.
Binary file not shown.
|
@ -413,7 +413,7 @@ function createMeshCore(agent) {
|
|||
if (xurl != null) {
|
||||
var woptions = http.parseUri(xurl);
|
||||
woptions.rejectUnauthorized = 0;
|
||||
//sendConsoleText(JSON.stringify(woptions));
|
||||
sendConsoleText(JSON.stringify(woptions));
|
||||
var tunnel = http.request(woptions);
|
||||
tunnel.upgrade = onTunnelUpgrade;
|
||||
tunnel.onerror = function (e) { sendConsoleText('ERROR: ' + JSON.stringify(e)); }
|
||||
|
|
|
@ -28,14 +28,26 @@ module.exports.CertificateOperations = function () {
|
|||
|
||||
// Return the certificate of the remote HTTPS server
|
||||
obj.loadCertificate = function (url, tag, func) {
|
||||
var u = require('url').parse(url);
|
||||
const u = require('url').parse(url);
|
||||
if (u.protocol == 'https:') {
|
||||
var tlssocket = obj.tls.connect((u.port ? u.port : 443), u.hostname, { rejectUnauthorized: false }, function () { this.xxcert = this.getPeerCertificate(); this.end(); });
|
||||
// Read the certificate from HTTPS
|
||||
const tlssocket = obj.tls.connect((u.port ? u.port : 443), u.hostname, { servername: u.hostname, rejectUnauthorized: false }, function () { this.xxcert = this.getPeerCertificate(); this.end(); });
|
||||
tlssocket.xxurl = url;
|
||||
tlssocket.xxfunc = func;
|
||||
tlssocket.xxtag = tag;
|
||||
tlssocket.on('end', function () { this.xxfunc(this.xxurl, this.xxcert, this.xxtag); });
|
||||
tlssocket.on('end', function () { this.xxfunc(this.xxurl, this.xxcert.raw.toString('binary'), this.xxtag); });
|
||||
tlssocket.on('error', function () { this.xxfunc(this.xxurl, null, this.xxtag); });
|
||||
} else if (u.protocol == 'file:') {
|
||||
// Read the certificate from a file
|
||||
obj.fs.readFile(url.substring(7), 'utf8', function (err, data) {
|
||||
if (err) { func(url, null, tag); return; }
|
||||
var x1 = data.indexOf('-----BEGIN CERTIFICATE-----'), x2 = data.indexOf('-----END CERTIFICATE-----');
|
||||
if ((x1 >= 0) && (x2 > x1)) {
|
||||
func(url, new Buffer(data.substring(x1 + 27, x2), 'base64').toString('binary'), tag);
|
||||
} else {
|
||||
func(url, data, tag);
|
||||
}
|
||||
});
|
||||
} else { func(url, null, tag); }
|
||||
};
|
||||
|
||||
|
@ -45,6 +57,43 @@ module.exports.CertificateOperations = function () {
|
|||
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: "hex", md: obj.forge.md.sha384.create() });
|
||||
};
|
||||
|
||||
// Return the SHA384 hash of the certificate, return hex
|
||||
obj.getCertHash = function (cert) {
|
||||
try {
|
||||
var md = obj.forge.md.sha384.create();
|
||||
md.update(obj.forge.asn1.toDer(obj.pki.certificateToAsn1(obj.pki.certificateFromPem(cert))).getBytes());
|
||||
return md.digest().toHex();
|
||||
} catch (ex) {
|
||||
// If this is not an RSA certificate, hash the raw PKCS7 out of the PEM file
|
||||
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
||||
if ((x1 >= 0) && (x2 > x1)) {
|
||||
return obj.crypto.createHash('sha384').update(new Buffer(cert.substring(x1 + 27, x2), 'base64')).digest('hex');
|
||||
} else { console.log('ERROR: Unable to decode certificate.'); return null; }
|
||||
}
|
||||
};
|
||||
|
||||
// Return the SHA384 hash of the certificate public key
|
||||
obj.getPublicKeyHashBinary = function (cert) {
|
||||
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
||||
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: "binary", md: obj.forge.md.sha384.create() });
|
||||
};
|
||||
|
||||
// Return the SHA384 hash of the certificate, return binary
|
||||
obj.getCertHashBinary = function (cert) {
|
||||
try {
|
||||
// If this is a RSA certificate, we can use Forge to hash the ASN1
|
||||
var md = obj.forge.md.sha384.create();
|
||||
md.update(obj.forge.asn1.toDer(obj.pki.certificateToAsn1(obj.pki.certificateFromPem(cert))).getBytes());
|
||||
return md.digest().getBytes();
|
||||
} catch (ex) {
|
||||
// If this is not an RSA certificate, hash the raw PKCS7 out of the PEM file
|
||||
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
||||
if ((x1 >= 0) && (x2 > x1)) {
|
||||
return obj.crypto.createHash('sha384').update(new Buffer(cert.substring(x1 + 27, x2), 'base64')).digest('binary');
|
||||
} else { console.log('ERROR: Unable to decode certificate.'); return null; }
|
||||
}
|
||||
};
|
||||
|
||||
// Create a self-signed certificate
|
||||
obj.GenerateRootCertificate = function (addThumbPrintToName, commonName, country, organization, strong) {
|
||||
var keys = obj.pki.rsa.generateKeyPair((strong == true) ? 3072 : 2048);
|
||||
|
|
19
meshagent.js
19
meshagent.js
|
@ -198,7 +198,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||
obj.receivedCommands += 1; // Agent can't send the same command twice on the same connection ever. Block DOS attack path.
|
||||
|
||||
// Check that the server hash matches our own web certificate hash (SHA384)
|
||||
if (getWebCertHash(obj.domain) != msg.substring(2, 50)) { console.log('Agent connected with bad web certificate hash (' + (new Buffer(getWebCertHash(obj.domain), 'binary').toString('hex').substring(0, 10)) + ' != ' + (new Buffer(msg.substring(2, 50), 'binary').toString('hex').substring(0, 10)) + '), holding connection (' + obj.remoteaddrport + ').'); return; }
|
||||
if ((getWebCertHash(obj.domain) != msg.substring(2, 50)) && (getWebCertFullHash(obj.domain) != msg.substring(2, 50))) { console.log('Agent connected with bad web certificate hash (Agent:' + (new Buffer(msg.substring(2, 50), 'binary').toString('hex').substring(0, 10)) + ' != Server:' + (new Buffer(getWebCertHash(obj.domain), 'binary').toString('hex').substring(0, 10)) + ' or ' + (new Buffer(getWebCertFullHash(obj.domain), 'binary').toString('hex').substring(0, 10)) + '), holding connection (' + obj.remoteaddrport + ').'); return; }
|
||||
|
||||
// Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
|
||||
obj.agentnonce = msg.substring(50, 98);
|
||||
|
@ -411,19 +411,30 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||
});
|
||||
}
|
||||
|
||||
// Get the web certificate hash for the speficied domain
|
||||
// Get the web certificate private key hash for the specified domain
|
||||
function getWebCertHash(domain) {
|
||||
var hash = obj.parent.webCertificateHashs[domain.id];
|
||||
if (hash != null) return hash;
|
||||
return obj.parent.webCertificateHash;
|
||||
}
|
||||
|
||||
// Get the web certificate hash for the specified domain
|
||||
function getWebCertFullHash(domain) {
|
||||
var hash = obj.parent.webCertificateFullHashs[domain.id];
|
||||
if (hash != null) return hash;
|
||||
return obj.parent.webCertificateFullHash;
|
||||
}
|
||||
|
||||
// Verify the agent signature
|
||||
function processAgentSignature(msg) {
|
||||
// Verify the signature. This is the fast way, without using forge.
|
||||
const verify = obj.parent.crypto.createVerify('SHA384');
|
||||
verify.end(new Buffer(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary'));
|
||||
if (verify.verify(obj.unauth.nodeCertPem, new Buffer(msg, 'binary')) !== true) { return false; }
|
||||
verify.end(new Buffer(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the private key hash
|
||||
if (verify.verify(obj.unauth.nodeCertPem, new Buffer(msg, 'binary')) !== true) {
|
||||
const verify2 = obj.parent.crypto.createVerify('SHA384');
|
||||
verify2.end(new Buffer(getWebCertFullHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary')); // Test using the full cert hash
|
||||
if (verify2.verify(obj.unauth.nodeCertPem, new Buffer(msg, 'binary')) !== true) { return false; }
|
||||
}
|
||||
|
||||
// Connection is a success, clean up
|
||||
obj.nodeid = obj.unauth.nodeid;
|
||||
|
|
|
@ -417,22 +417,23 @@ function CreateMeshCentralServer(config, args) {
|
|||
webCertLoadCount++;
|
||||
obj.certificateOperations.loadCertificate(obj.config.domains[i].certurl, obj.config.domains[i], function (url, cert, xdomain) {
|
||||
if (cert != null) {
|
||||
// Hash the entire cert
|
||||
var hash = obj.crypto.createHash('sha384').update(cert).digest('hex');
|
||||
if (xdomain.certhash != hash) {
|
||||
xdomain.certkeyhash = hash;
|
||||
xdomain.certhash = hash;
|
||||
}
|
||||
|
||||
try {
|
||||
// Decode a RSA certificate and hash the public key
|
||||
var forgeCert = obj.certificateOperations.forge.pki.certificateFromAsn1(obj.certificateOperations.forge.asn1.fromDer(cert.raw.toString('binary')));
|
||||
var hash = obj.certificateOperations.forge.pki.getPublicKeyFingerprint(forgeCert.publicKey, { md: obj.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
|
||||
if (xdomain.certhash != hash) {
|
||||
xdomain.certhash = hash;
|
||||
console.log('Loaded RSA web certificate at ' + url + ', SHA384: ' + xdomain.certhash + '.');
|
||||
}
|
||||
} catch (ex) {
|
||||
// This may be a ECDSA certificate, hash the entire cert
|
||||
var hash = obj.crypto.createHash('sha384').update(cert.raw).digest('hex');
|
||||
if (xdomain.certhash != hash) {
|
||||
xdomain.certhash = hash;
|
||||
console.log('Loaded non-RSA web certificate at ' + url + ', SHA384: ' + xdomain.certhash + '.');
|
||||
}
|
||||
}
|
||||
// Decode a RSA certificate and hash the public key, if this is not RSA, skip this.
|
||||
var forgeCert = obj.certificateOperations.forge.pki.certificateFromAsn1(obj.certificateOperations.forge.asn1.fromDer(cert));
|
||||
xdomain.certkeyhash = obj.certificateOperations.forge.pki.getPublicKeyFingerprint(forgeCert.publicKey, { md: obj.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
|
||||
console.log('V1: ' + xdomain.certkeyhash);
|
||||
} catch (ex) { }
|
||||
|
||||
console.log('Loaded web certificate from ' + url);
|
||||
console.log(' SHA384 cert hash: ' + xdomain.certhash);
|
||||
if (xdomain.certhash != xdomain.certkeyhash) { console.log(' SHA384 key hash: ' + xdomain.certkeyhash); }
|
||||
} else {
|
||||
console.log('Failed to load web certificate at: ' + url);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.2.3-r",
|
||||
"version": "0.2.3-v",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
|
30
webserver.js
30
webserver.js
|
@ -102,33 +102,39 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
|||
}
|
||||
|
||||
// Perform hash on web certificate and agent certificate
|
||||
obj.webCertificateHash = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.web.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' });
|
||||
obj.webCertificateHash = parent.certificateOperations.getPublicKeyHashBinary(obj.certificates.web.cert);
|
||||
obj.webCertificateHashs = { '': obj.webCertificateHash };
|
||||
obj.webCertificateHashBase64 = new Buffer(parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.web.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.agentCertificateHashHex = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.agent.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
|
||||
obj.agentCertificateHashBase64 = new Buffer(parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.agent.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.webCertificateHashBase64 = new Buffer(obj.webCertificateHash, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.webCertificateFullHash = parent.certificateOperations.getCertHashBinary(obj.certificates.web.cert);
|
||||
obj.webCertificateFullHashs = { '': obj.webCertificateFullHash };
|
||||
obj.webCertificateFullHashBase64 = new Buffer(obj.webCertificateFullHash, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.agentCertificateHashHex = parent.certificateOperations.getPublicKeyHash(obj.certificates.agent.cert);
|
||||
obj.agentCertificateHashBase64 = new Buffer(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();
|
||||
|
||||
// Compute the hash of all of the web certificates for each domain
|
||||
for (var i in obj.parent.config.domains) {
|
||||
if (obj.parent.config.domains[i].certhash != null) {
|
||||
// If the web certificate hash is provided, use it.
|
||||
obj.webCertificateHashs[i] = new Buffer(obj.parent.config.domains[i].certhash, 'hex').toString('binary');
|
||||
obj.webCertificateHashs[i] = obj.webCertificateFullHashs[i] = new Buffer(obj.parent.config.domains[i].certhash, 'hex').toString('binary');
|
||||
if (obj.parent.config.domains[i].certkeyhash != null) { obj.webCertificateHashs[i] = new Buffer(obj.parent.config.domains[i].certkeyhash, 'hex').toString('binary'); }
|
||||
} else if ((obj.parent.config.domains[i].dns != null) && (obj.parent.config.domains[i].certs != null)) {
|
||||
// If the domain has a different DNS name, use a different certificate hash.
|
||||
// Hash the full certificate
|
||||
obj.webCertificateFullHashs[i] = parent.certificateOperations.getCertHashBinary(obj.parent.config.domains[i].certs.cert);
|
||||
try {
|
||||
// Decode a RSA certificate and hash the public key
|
||||
obj.webCertificateHashs[i] = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.parent.config.domains[i].certs.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' });
|
||||
// Decode a RSA certificate and hash the public key.
|
||||
obj.webCertificateHashs[i] = parent.certificateOperations.getPublicKeyHashBinary(obj.parent.config.domains[i].certs.cert);
|
||||
} catch (ex) {
|
||||
// This may be a ECDSA certificate, hash the entire cert
|
||||
var x1 = obj.parent.config.domains[i].certs.cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = obj.parent.config.domains[i].certs.cert.indexOf('-----END CERTIFICATE-----');
|
||||
if ((x1 >= 0) && (x2 > x1)) {
|
||||
obj.webCertificateHashs[i] = obj.crypto.createHash('sha384').update(new Buffer(obj.parent.config.domains[i].certs.cert.substring(x1 + 27, x2), 'base64')).digest('binary');
|
||||
} else { console.log('ERROR: Unable to decode certificate for domain "' + i + '".'); }
|
||||
// This may be a ECDSA certificate, hash the entire cert.
|
||||
obj.webCertificateHashs[i] = obj.webCertificateFullHashs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//console.log(new Buffer(obj.webCertificateHashs['devtest'], 'binary').toString('hex'));
|
||||
//console.log(new Buffer(obj.webCertificateFullHashs['devtest'], 'binary').toString('hex'));
|
||||
|
||||
// If we are running the legacy swarm server, compute the hash for that certificate
|
||||
if (parent.certificates.swarmserver != null) {
|
||||
obj.swarmCertificateAsn1 = parent.certificateOperations.forge.asn1.toDer(parent.certificateOperations.forge.pki.certificateToAsn1(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.swarmserver.cert))).getBytes();
|
||||
|
|
Loading…
Reference in New Issue