Added web cert loading, useful for TLS offload.
This commit is contained in:
parent
7141e7f3b8
commit
829d2e9c83
|
@ -20,11 +20,25 @@ module.exports.CertificateOperations = function () {
|
||||||
obj.fs = require("fs");
|
obj.fs = require("fs");
|
||||||
obj.forge = require("node-forge");
|
obj.forge = require("node-forge");
|
||||||
obj.crypto = require("crypto");
|
obj.crypto = require("crypto");
|
||||||
|
obj.tls = require('tls');
|
||||||
obj.pki = obj.forge.pki;
|
obj.pki = obj.forge.pki;
|
||||||
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } };
|
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } };
|
||||||
obj.getFilesizeInBytes = function (filename) { try { return obj.fs.statSync(filename).size; } catch (err) { return -1; } };
|
obj.getFilesizeInBytes = function (filename) { try { return obj.fs.statSync(filename).size; } catch (err) { return -1; } };
|
||||||
obj.fileExists = function (filePath) { try { return obj.fs.statSync(filePath).isFile(); } catch (err) { return false; } };
|
obj.fileExists = function (filePath) { try { return obj.fs.statSync(filePath).isFile(); } catch (err) { return false; } };
|
||||||
|
|
||||||
|
// Return the certificate of the remote HTTPS server
|
||||||
|
obj.loadCertificate = function (url, tag, func) {
|
||||||
|
var 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(); });
|
||||||
|
tlssocket.xxurl = url;
|
||||||
|
tlssocket.xxfunc = func;
|
||||||
|
tlssocket.xxtag = tag;
|
||||||
|
tlssocket.on('end', function () { this.xxfunc(this.xxurl, this.xxcert, this.xxtag); });
|
||||||
|
tlssocket.on('error', function () { this.xxfunc(this.xxurl, null, this.xxtag); });
|
||||||
|
} else { func(url, null, tag); }
|
||||||
|
};
|
||||||
|
|
||||||
// Return the SHA386 hash of the certificate public key
|
// Return the SHA386 hash of the certificate public key
|
||||||
obj.getPublicKeyHash = function (cert) {
|
obj.getPublicKeyHash = function (cert) {
|
||||||
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
||||||
|
|
|
@ -198,10 +198,10 @@ 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.
|
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 (SHA386)
|
// Check that the server hash matches our own web certificate hash (SHA386)
|
||||||
if (getWebCertHash(obj.domain) != msg.substring(2, 50)) { console.log('Agent connected with bad web certificate hash, holding connection (' + obj.remoteaddr + ').'); return; }
|
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.remoteaddr + ').'); return; }
|
||||||
|
|
||||||
// Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
|
// Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
|
||||||
obj.agentnonce = msg.substring(50);
|
obj.agentnonce = msg.substring(50, 98);
|
||||||
|
|
||||||
// Check if we got the agent auth confirmation
|
// Check if we got the agent auth confirmation
|
||||||
if ((obj.receivedCommands & 8) == 0) {
|
if ((obj.receivedCommands & 8) == 0) {
|
||||||
|
|
|
@ -398,12 +398,45 @@ function CreateMeshCentralServer(config, args) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start the server with the given certificates
|
// Start the server with the given certificates, but check if we have web certificates to load
|
||||||
obj.StartEx3 = function (certs) {
|
obj.StartEx3 = function (certs) {
|
||||||
var i;
|
var i, webCertLoadCount = 0;
|
||||||
obj.certificates = certs;
|
obj.certificates = certs;
|
||||||
obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
|
obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
|
||||||
|
|
||||||
|
// Load any domain web certificates
|
||||||
|
for (i in obj.config.domains) {
|
||||||
|
if (obj.config.domains[i].certurl != null) {
|
||||||
|
// Load web certs
|
||||||
|
webCertLoadCount++;
|
||||||
|
obj.certificateOperations.loadCertificate(obj.config.domains[i].certurl, obj.config.domains[i], function (url, cert, xdomain) {
|
||||||
|
if (cert != null) {
|
||||||
|
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' });
|
||||||
|
xdomain.certhash = hash;
|
||||||
|
} catch (ex) {
|
||||||
|
// This may be a ECDSA certificate, hash the entire cert
|
||||||
|
xdomain.certhash = obj.crypto.createHash('sha384').update(cert.raw).digest('hex');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Failed to load web certificate at: ' + url);
|
||||||
|
}
|
||||||
|
webCertLoadCount--;
|
||||||
|
if (webCertLoadCount == 0) { obj.StartEx4(); } // Done loading all certificates
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No certificate to load, start the server
|
||||||
|
if (webCertLoadCount == 0) { obj.StartEx4(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the server with the given certificates
|
||||||
|
obj.StartEx4 = function () {
|
||||||
|
var i;
|
||||||
|
|
||||||
// If the certificate is un-configured, force LAN-only mode
|
// If the certificate is un-configured, force LAN-only mode
|
||||||
if (obj.certificates.CommonName == 'un-configured') { console.log('Server name not configured, running in LAN-only mode.'); obj.args.lanonly = true; }
|
if (obj.certificates.CommonName == 'un-configured') { console.log('Server name not configured, running in LAN-only mode.'); obj.args.lanonly = true; }
|
||||||
|
|
||||||
|
@ -435,7 +468,7 @@ function CreateMeshCentralServer(config, args) {
|
||||||
if ((obj.args.sessiontime != null) && ((typeof obj.args.sessiontime != 'number') || (obj.args.sessiontime < 1))) { delete obj.args.sessiontime; }
|
if ((obj.args.sessiontime != null) && ((typeof obj.args.sessiontime != 'number') || (obj.args.sessiontime < 1))) { delete obj.args.sessiontime; }
|
||||||
if (!obj.args.sessionkey) { obj.args.sessionkey = buf.toString('hex').toUpperCase(); }
|
if (!obj.args.sessionkey) { obj.args.sessionkey = buf.toString('hex').toUpperCase(); }
|
||||||
|
|
||||||
// Start eh web server and if needed, the redirection web server.
|
// Start the web server and if needed, the redirection web server.
|
||||||
obj.webserver = require('./webserver.js').CreateWebServer(obj, obj.db, obj.args, obj.certificates);
|
obj.webserver = require('./webserver.js').CreateWebServer(obj, obj.db, obj.args, obj.certificates);
|
||||||
if (obj.redirserver != null) { obj.redirserver.hookMainWebServer(obj.certificates); }
|
if (obj.redirserver != null) { obj.redirserver.hookMainWebServer(obj.certificates); }
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.2.2-n",
|
"version": "0.2.2-o",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
"userQuota": 1048576,
|
"userQuota": 1048576,
|
||||||
"meshQuota": 248576,
|
"meshQuota": 248576,
|
||||||
"newAccounts": 1,
|
"newAccounts": 1,
|
||||||
"footer": "<a href='https://twitter.com/mytwitter'>Twitter</a>"
|
"footer": "<a href='https://twitter.com/mytwitter'>Twitter</a>",
|
||||||
|
"_certUrl": "https://192.168.2.106:443/"
|
||||||
},
|
},
|
||||||
"customer1": {
|
"customer1": {
|
||||||
"dns": "customer1.myserver.com",
|
"dns": "customer1.myserver.com",
|
||||||
|
@ -33,7 +34,8 @@
|
||||||
"title2": "TestServer",
|
"title2": "TestServer",
|
||||||
"newAccounts": 1,
|
"newAccounts": 1,
|
||||||
"auth": "sspi",
|
"auth": "sspi",
|
||||||
"footer": "Test"
|
"footer": "Test",
|
||||||
|
"_certUrl": "https://192.168.2.106:443/"
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"share": "C:\\ExtraWebSite"
|
"share": "C:\\ExtraWebSite"
|
||||||
|
|
23
webserver.js
23
webserver.js
|
@ -104,11 +104,32 @@ 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 = 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.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.web.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' });
|
||||||
obj.webCertificateHashs = { '': obj.webCertificateHash };
|
obj.webCertificateHashs = { '': obj.webCertificateHash };
|
||||||
for (var i in obj.parent.config.domains) { if (obj.parent.config.domains[i].dns != null) { 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' }); } }
|
|
||||||
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.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.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.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.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();
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
} 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.
|
||||||
|
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' });
|
||||||
|
} 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 + '".'); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are running the legacy swarm server, compute the hash for that certificate
|
||||||
if (parent.certificates.swarmserver != null) {
|
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();
|
obj.swarmCertificateAsn1 = parent.certificateOperations.forge.asn1.toDer(parent.certificateOperations.forge.pki.certificateToAsn1(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.swarmserver.cert))).getBytes();
|
||||||
obj.swarmCertificateHash384 = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.swarmserver.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' });
|
obj.swarmCertificateHash384 = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(obj.certificates.swarmserver.cert).publicKey, { md: parent.certificateOperations.forge.md.sha384.create(), encoding: 'binary' });
|
||||||
|
|
Loading…
Reference in New Issue