mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-11-25 10:03:01 +03:00
More work on Intel AMT ACM host-based TLS activation.
This commit is contained in:
parent
3b2ef66dcd
commit
286342bb1b
@ -113,7 +113,7 @@ function run(argv) {
|
|||||||
//console.log('addedModules = ' + JSON.stringify(addedModules));
|
//console.log('addedModules = ' + JSON.stringify(addedModules));
|
||||||
var actionpath = 'meshaction.txt';
|
var actionpath = 'meshaction.txt';
|
||||||
if (args.actionfile != null) { actionpath = args.actionfile; }
|
if (args.actionfile != null) { actionpath = args.actionfile; }
|
||||||
var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTCONFIG', 'AMTSCAN', 'AMTPOWER', 'AMTFEATURES', 'AMTNETWORK', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTUUID', 'AMTCCM', 'AMTDEACTIVATE', 'AMTACMDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTEVENTLOG', 'AMTPRESENCE', 'AMTWIFI', 'AMTWAKE', 'AMTSTOPCONFIGURATION'];
|
var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTCONFIG', 'AMTSCAN', 'AMTPOWER', 'AMTFEATURES', 'AMTNETWORK', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTUUID', 'AMTCCM', 'AMTDEACTIVATE', 'AMTACMDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTEVENTLOG', 'AMTPRESENCE', 'AMTWIFI', 'AMTWAKE', 'AMTSTARTCONFIG', 'AMTSTOPCONFIG'];
|
||||||
|
|
||||||
// Load the action file
|
// Load the action file
|
||||||
var actionfile = null;
|
var actionfile = null;
|
||||||
@ -428,7 +428,21 @@ function run(argv) {
|
|||||||
console.log('Proxy set to ' + proxy[0] + ':' + proxyport);
|
console.log('Proxy set to ' + proxy[0] + ':' + proxyport);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.action == 'amtstopconfiguration') {
|
if (settings.action == 'amtstartconfig') {
|
||||||
|
// Start Intel AMT configuration
|
||||||
|
var amtMeiModule, amtMei;
|
||||||
|
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { console.log(ex); exit(1); return; }
|
||||||
|
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||||
|
amtMei.startConfiguration(function (state) {
|
||||||
|
if (state == 3) { console.log("Intel AMT is not in correct mode."); }
|
||||||
|
else if (state == 1) { console.log("Intel AMT internal error."); }
|
||||||
|
else if (state == 48) { console.log("Random generator not ready."); }
|
||||||
|
else if (state == 49) { console.log("Certificate not ready."); }
|
||||||
|
else if (state == 0) { console.log("Success."); }
|
||||||
|
else { console.log("Unknown status: " + state); }
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
} else if (settings.action == 'amtstopconfig') {
|
||||||
// Stop Intel AMT configuration
|
// Stop Intel AMT configuration
|
||||||
var amtMeiModule, amtMei;
|
var amtMeiModule, amtMei;
|
||||||
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { console.log(ex); exit(1); return; }
|
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { console.log(ex); exit(1); return; }
|
||||||
@ -437,7 +451,7 @@ function run(argv) {
|
|||||||
if (state == 3) { console.log("Intel AMT is not in in-provisionning mode."); }
|
if (state == 3) { console.log("Intel AMT is not in in-provisionning mode."); }
|
||||||
else if (state == 1) { console.log("Intel AMT internal error."); }
|
else if (state == 1) { console.log("Intel AMT internal error."); }
|
||||||
else if (state == 0) { console.log("Success."); }
|
else if (state == 0) { console.log("Success."); }
|
||||||
else { console.log("Unknown state: " + state); }
|
else { console.log("Unknown status: " + state); }
|
||||||
exit(1);
|
exit(1);
|
||||||
});
|
});
|
||||||
} else if (settings.action == 'smbios') {
|
} else if (settings.action == 'smbios') {
|
||||||
|
@ -46,7 +46,10 @@ function CreateAPFClient(parent, args) {
|
|||||||
function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }; // Convert a raw string to a hex string
|
function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }; // Convert a raw string to a hex string
|
||||||
function d2h(d) { return (d / 256 + 1 / 512).toString(16).substring(2, 4); }
|
function d2h(d) { return (d / 256 + 1 / 512).toString(16).substring(2, 4); }
|
||||||
function buf2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += d2h(input[i]); } return r; };
|
function buf2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += d2h(input[i]); } return r; };
|
||||||
function Debug(str) { if (obj.parent.debug) { console.log(str); } }
|
function Debug(str) {
|
||||||
|
//require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: str });
|
||||||
|
if (obj.parent.debug) { console.log(str); }
|
||||||
|
}
|
||||||
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
|
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
|
||||||
function strToGuid(s) { s = s.replace(/-/g, ''); var ret = s.substring(6, 8) + s.substring(4, 6) + s.substring(2, 4) + s.substring(0, 2) + s.substring(10, 12) + s.substring(8, 10) + s.substring(14, 16) + s.substring(12, 14) + s.substring(16, 20) + s.substring(20); return ret; }
|
function strToGuid(s) { s = s.replace(/-/g, ''); var ret = s.substring(6, 8) + s.substring(4, 6) + s.substring(2, 4) + s.substring(0, 2) + s.substring(10, 12) + s.substring(8, 10) + s.substring(14, 16) + s.substring(12, 14) + s.substring(16, 20) + s.substring(20); return ret; }
|
||||||
function binzerostring(len) { var res = ''; for (var l = 0; l < len; l++) { res += String.fromCharCode(0 & 0xFF); } return res; }
|
function binzerostring(len) { var res = ''; for (var l = 0; l < len; l++) { res += String.fromCharCode(0 & 0xFF); } return res; }
|
||||||
|
@ -416,13 +416,15 @@ function amt_heci() {
|
|||||||
for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||||
|
|
||||||
// Format the command
|
// Format the command
|
||||||
var data = Buffer.alloc(4 + 64 + 4 + 4 + 320);
|
var len = 1 + 64 + 4 + 4;
|
||||||
data.writeUInt32LE((certHash.length == 48) ? 3 : 2, 0); // Write certificate hash type: SHA256 = 2, SHA384 = 3
|
if (dnsSuffixList != null) { len += 320; }
|
||||||
certHash.copy(data, 4); // Write the hash
|
var data = Buffer.alloc(len);
|
||||||
data.writeUInt32LE(hostVpn ? 1 : 0, 68); // Write is HostVPN is enabled
|
data[0] = (certHash.length == 48) ? 3 : 2; // Write certificate hash type: SHA256 = 2, SHA384 = 3
|
||||||
|
certHash.copy(data, 1); // Write the hash
|
||||||
|
data.writeUInt32LE(hostVpn ? 1 : 0, 65); // Write is HostVPN is enabled
|
||||||
if (dnsSuffixList != null) {
|
if (dnsSuffixList != null) {
|
||||||
data.writeUInt32LE(dnsSuffixList.length, 72); // Write the number of DNS Suffix, from 0 to 4
|
data.writeUInt32LE(dnsSuffixList.length, 69); // Write the number of DNS Suffix, from 0 to 4
|
||||||
var ptr = 76;
|
var ptr = 73;
|
||||||
for (var i = 0; i < dnsSuffixList.length; i++) { ptr += data.write(dnsSuffixList[i], ptr) + 1; } // Write up to 4 DNS Suffix with null seperation.
|
for (var i = 0; i < dnsSuffixList.length; i++) { ptr += data.write(dnsSuffixList[i], ptr) + 1; } // Write up to 4 DNS Suffix with null seperation.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,7 +445,6 @@ function amt_heci() {
|
|||||||
|
|
||||||
module.exports = amt_heci;
|
module.exports = amt_heci;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AMT_STATUS_SUCCESS = 0,
|
AMT_STATUS_SUCCESS = 0,
|
||||||
AMT_STATUS_INTERNAL_ERROR = 1,
|
AMT_STATUS_INTERNAL_ERROR = 1,
|
||||||
|
@ -290,7 +290,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
|
|||||||
obj.socket.on('data', obj.xxOnSocketData);
|
obj.socket.on('data', obj.xxOnSocketData);
|
||||||
obj.socket.on('close', obj.xxOnSocketClosed);
|
obj.socket.on('close', obj.xxOnSocketClosed);
|
||||||
obj.socket.on('timeout', obj.xxOnSocketTimeout);
|
obj.socket.on('timeout', obj.xxOnSocketTimeout);
|
||||||
obj.socket.on('error', function (e) { if (e.message && e.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
|
obj.socket.on('error', function (ex) { if (ex.message && ex.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
|
||||||
}
|
}
|
||||||
obj.socket.setNoDelay(true); // Disable nagle. We will encode each WSMAN request as a single send block and want to send it at once. This may help Intel AMT handle pipelining?
|
obj.socket.setNoDelay(true); // Disable nagle. We will encode each WSMAN request as a single send block and want to send it at once. This may help Intel AMT handle pipelining?
|
||||||
}
|
}
|
||||||
@ -300,6 +300,23 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
|
|||||||
obj.getPeerCertificate = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate(); } return null; }
|
obj.getPeerCertificate = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate(); } return null; }
|
||||||
obj.getPeerCertificateFingerprint = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate().fingerprint.split(':').join('').toLowerCase(); } return null; }
|
obj.getPeerCertificateFingerprint = function () { if (obj.xtls == 1) { return obj.socket.getPeerCertificate().fingerprint.split(':').join('').toLowerCase(); } return null; }
|
||||||
|
|
||||||
|
// Check if the certificate matched the certificate hash.
|
||||||
|
function checkCertHash(cert, hash) {
|
||||||
|
// Check not required
|
||||||
|
if (hash == 0) return true;
|
||||||
|
|
||||||
|
// SHA1 compare
|
||||||
|
if (cert.fingerprint.split(':').join('').toLowerCase() == hash) return true;
|
||||||
|
|
||||||
|
// SHA256 compare
|
||||||
|
if ((hash.length == 64) && (obj.crypto.createHash('sha256').update(cert.raw).digest('hex') == hash)) { return true; }
|
||||||
|
|
||||||
|
// SHA384 compare
|
||||||
|
if ((hash.length == 96) && (obj.crypto.createHash('sha384').update(cert.raw).digest('hex') == hash)) { return true; }
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// NODE.js specific private method
|
// NODE.js specific private method
|
||||||
obj.xxOnSocketConnected = function () {
|
obj.xxOnSocketConnected = function () {
|
||||||
if (obj.socket == null) return;
|
if (obj.socket == null) return;
|
||||||
@ -307,7 +324,6 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
|
|||||||
if (obj.xtls == 1) {
|
if (obj.xtls == 1) {
|
||||||
obj.xtlsCertificate = obj.socket.getPeerCertificate();
|
obj.xtlsCertificate = obj.socket.getPeerCertificate();
|
||||||
|
|
||||||
// ###BEGIN###{Certificates}
|
|
||||||
// Setup the forge certificate check
|
// Setup the forge certificate check
|
||||||
var camatch = 0;
|
var camatch = 0;
|
||||||
if ((obj.xtlsoptions != null) && (obj.xtlsoptions.ca != null)) {
|
if ((obj.xtlsoptions != null) && (obj.xtlsoptions.ca != null)) {
|
||||||
@ -327,21 +343,12 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
|
|||||||
if (amtcertname.toLowerCase() != obj.host.toLowerCase()) { camatch = 0; }
|
if (amtcertname.toLowerCase() != obj.host.toLowerCase()) { camatch = 0; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((camatch == 0) && (obj.xtlsFingerprint != 0) && (obj.xtlsCertificate.fingerprint.split(':').join('').toLowerCase() != obj.xtlsFingerprint)) {
|
if ((camatch == 0) && (checkCertHash(obj.xtlsCertificate, obj.xtlsFingerprint) == false)) {
|
||||||
obj.FailAllError = 998; // Cause all new responses to be silent. 998 = TLS Certificate check error
|
obj.FailAllError = 998; // Cause all new responses to be silent. 998 = TLS Certificate check error
|
||||||
obj.CancelAllQueries(998);
|
obj.CancelAllQueries(998);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((obj.xtlsFingerprint == 0) && (camatch == 0)) { obj.xtlsCheck = 3; } else { obj.xtlsCheck = (camatch == 0) ? 2 : 1; }
|
if ((obj.xtlsFingerprint == 0) && (camatch == 0)) { obj.xtlsCheck = 3; } else { obj.xtlsCheck = (camatch == 0) ? 2 : 1; }
|
||||||
// ###END###{Certificates}
|
|
||||||
// ###BEGIN###{!Certificates}
|
|
||||||
if ((obj.xtlsFingerprint != 0) && (obj.xtlsCertificate.fingerprint.split(':').join('').toLowerCase() != obj.xtlsFingerprint)) {
|
|
||||||
obj.FailAllError = 998; // Cause all new responses to be silent. 998 = TLS Certificate check error
|
|
||||||
obj.CancelAllQueries(998);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
obj.xtlsCheck = 2;
|
|
||||||
// ###END###{!Certificates}
|
|
||||||
} else { obj.xtlsCheck = 0; }
|
} else { obj.xtlsCheck = 0; }
|
||||||
obj.socketState = 2;
|
obj.socketState = 2;
|
||||||
obj.socketParseState = 0;
|
obj.socketParseState = 0;
|
||||||
|
@ -1842,7 +1842,7 @@ module.exports.CreateAmtManager = function (parent) {
|
|||||||
|
|
||||||
// Send the MEI command to enable TLS connections
|
// Send the MEI command to enable TLS connections
|
||||||
dev.consoleMsg("Performing TLS ACM activation...");
|
dev.consoleMsg("Performing TLS ACM activation...");
|
||||||
dev.controlMsg({ action: 'startTlsHostConfig', hash: acmTlsInfo.hash256, hostVpn: false, dnsSuffixList: null });
|
dev.controlMsg({ action: 'startTlsHostConfig', hash: acmTlsInfo.hash256, hostVpn: false, dnsSuffixList: null }); // TODO: Use SHA384 is possible.
|
||||||
} else {
|
} else {
|
||||||
// MeshCore or MeshCMD is to old
|
// MeshCore or MeshCMD is to old
|
||||||
dev.consoleMsg("This software is to old to support ACM activation, pleasse update and try again.");
|
dev.consoleMsg("This software is to old to support ACM activation, pleasse update and try again.");
|
||||||
@ -1852,15 +1852,19 @@ module.exports.CreateAmtManager = function (parent) {
|
|||||||
|
|
||||||
// Attempt Intel AMT TLS ACM activation after startConfiguration() is called on remote device
|
// Attempt Intel AMT TLS ACM activation after startConfiguration() is called on remote device
|
||||||
function activateIntelAmtTlsAcmEx(dev, startConfigData) {
|
function activateIntelAmtTlsAcmEx(dev, startConfigData) {
|
||||||
//console.log('activateIntelAmtTlsAcmEx', dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass);
|
if ((startConfigData == null) || (startConfigData.status != 0) || (typeof startConfigData.hash != 'string')) {
|
||||||
|
// Unable to call startTlsHostConfig on remote host.
|
||||||
// Setup the WSMAN stack, no TLS
|
dev.consoleMsg("Failed to startConfigurationHBased(), status = " + startConfigData.status);
|
||||||
var comm = CreateWsmanComm(dev.nodeid, 16993, 'admin', '', 1, { cert: dev.acmTlsInfo.certs.join(''), key: dev.acmTlsInfo.signkey }, dev.mpsConnection); // TLS with client certificate chain and key.
|
removeAmtDevice(dev);
|
||||||
// TODO: Intel AMT leaf TLS cert need to SHA256 hash to "startConfigData.hash"
|
} else {
|
||||||
var wsstack = WsmanStackCreateService(comm);
|
// Setup the WSMAN stack, no TLS
|
||||||
dev.amtstack = AmtStackCreateService(wsstack);
|
var comm = CreateWsmanComm(dev.nodeid, 16993, 'admin', '', 1, { cert: dev.acmTlsInfo.certs.join(''), key: dev.acmTlsInfo.signkey }, dev.mpsConnection); // TLS with client certificate chain and key.
|
||||||
dev.amtstack.dev = dev;
|
comm.xtlsFingerprint = startConfigData.hash.toLowerCase(); // Intel AMT leaf TLS cert need to match this hash (SHA256 or SHA384)
|
||||||
dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtTlsAcmEx1);
|
var wsstack = WsmanStackCreateService(comm);
|
||||||
|
dev.amtstack = AmtStackCreateService(wsstack);
|
||||||
|
dev.amtstack.dev = dev;
|
||||||
|
dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtTlsAcmEx1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function activateIntelAmtTlsAcmEx1(stack, name, responses, status) {
|
function activateIntelAmtTlsAcmEx1(stack, name, responses, status) {
|
||||||
@ -1868,14 +1872,36 @@ module.exports.CreateAmtManager = function (parent) {
|
|||||||
const dev = stack.dev;
|
const dev = stack.dev;
|
||||||
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
|
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
|
||||||
|
|
||||||
|
// Check if we succesfully connected
|
||||||
if (status != 200) {
|
if (status != 200) {
|
||||||
dev.consoleMsg("Failed to perform ACM TLS connection, falling back to legacy host-based activation.");
|
dev.consoleMsg("Failed to perform ACM TLS connection.");
|
||||||
activateIntelAmtAcm(dev); // Falling back to legacy WSMAN ACM activation, start by refreshing $$OsAdmin username and password.
|
//activateIntelAmtAcm(dev); // It's possible to fallback to legacy WSMAN ACM activation here if we needed to..
|
||||||
|
removeAmtDevice(dev);
|
||||||
} else {
|
} else {
|
||||||
// TODO!!!
|
// TODO!!!
|
||||||
console.log('TODO!!!!!');
|
console.log('TODO!!!!!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Attempt Intel AMT ACM activation
|
// Attempt Intel AMT ACM activation
|
||||||
function activateIntelAmtAcm(dev, password, acminfo) {
|
function activateIntelAmtAcm(dev, password, acminfo) {
|
||||||
|
Loading…
Reference in New Issue
Block a user