From 286342bb1b132399b3aff4ea135e6c8909f66cff Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Tue, 16 Mar 2021 13:56:14 -0700 Subject: [PATCH] More work on Intel AMT ACM host-based TLS activation. --- agents/meshcmd.js | 20 ++++++++-- agents/modules_meshcore/amt-apfclient.js | 5 ++- agents/modules_meshcore/amt-mei.js | 15 +++---- amt/amt-wsman-comm.js | 31 +++++++++------ amtmanager.js | 50 ++++++++++++++++++------ 5 files changed, 86 insertions(+), 35 deletions(-) diff --git a/agents/meshcmd.js b/agents/meshcmd.js index e8dec629..b47d5702 100644 --- a/agents/meshcmd.js +++ b/agents/meshcmd.js @@ -113,7 +113,7 @@ function run(argv) { //console.log('addedModules = ' + JSON.stringify(addedModules)); var actionpath = 'meshaction.txt'; 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 var actionfile = null; @@ -428,7 +428,21 @@ function run(argv) { 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 var amtMeiModule, amtMei; 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."); } else if (state == 1) { console.log("Intel AMT internal error."); } else if (state == 0) { console.log("Success."); } - else { console.log("Unknown state: " + state); } + else { console.log("Unknown status: " + state); } exit(1); }); } else if (settings.action == 'smbios') { diff --git a/agents/modules_meshcore/amt-apfclient.js b/agents/modules_meshcore/amt-apfclient.js index f96eb1a3..13ab0898 100644 --- a/agents/modules_meshcore/amt-apfclient.js +++ b/agents/modules_meshcore/amt-apfclient.js @@ -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 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 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 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; } diff --git a/agents/modules_meshcore/amt-mei.js b/agents/modules_meshcore/amt-mei.js index af35af68..8f558448 100644 --- a/agents/modules_meshcore/amt-mei.js +++ b/agents/modules_meshcore/amt-mei.js @@ -416,13 +416,15 @@ function amt_heci() { for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); } // Format the command - var data = Buffer.alloc(4 + 64 + 4 + 4 + 320); - data.writeUInt32LE((certHash.length == 48) ? 3 : 2, 0); // Write certificate hash type: SHA256 = 2, SHA384 = 3 - certHash.copy(data, 4); // Write the hash - data.writeUInt32LE(hostVpn ? 1 : 0, 68); // Write is HostVPN is enabled + var len = 1 + 64 + 4 + 4; + if (dnsSuffixList != null) { len += 320; } + var data = Buffer.alloc(len); + 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) { - data.writeUInt32LE(dnsSuffixList.length, 72); // Write the number of DNS Suffix, from 0 to 4 - var ptr = 76; + data.writeUInt32LE(dnsSuffixList.length, 69); // Write the number of DNS Suffix, from 0 to 4 + 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. } @@ -443,7 +445,6 @@ function amt_heci() { module.exports = amt_heci; - /* AMT_STATUS_SUCCESS = 0, AMT_STATUS_INTERNAL_ERROR = 1, diff --git a/amt/amt-wsman-comm.js b/amt/amt-wsman-comm.js index e919fff7..82160349 100644 --- a/amt/amt-wsman-comm.js +++ b/amt/amt-wsman-comm.js @@ -290,7 +290,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn obj.socket.on('data', obj.xxOnSocketData); obj.socket.on('close', obj.xxOnSocketClosed); 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? } @@ -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.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 obj.xxOnSocketConnected = function () { if (obj.socket == null) return; @@ -307,7 +324,6 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn if (obj.xtls == 1) { obj.xtlsCertificate = obj.socket.getPeerCertificate(); - // ###BEGIN###{Certificates} // Setup the forge certificate check var camatch = 0; 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 ((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.CancelAllQueries(998); return; } 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; } obj.socketState = 2; obj.socketParseState = 0; diff --git a/amtmanager.js b/amtmanager.js index 8b3bf906..9bb4065c 100644 --- a/amtmanager.js +++ b/amtmanager.js @@ -1842,7 +1842,7 @@ module.exports.CreateAmtManager = function (parent) { // Send the MEI command to enable TLS connections 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 { // MeshCore or MeshCMD is to old 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 function activateIntelAmtTlsAcmEx(dev, startConfigData) { - //console.log('activateIntelAmtTlsAcmEx', dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass); - - // Setup the WSMAN stack, no TLS - 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. - // TODO: Intel AMT leaf TLS cert need to SHA256 hash to "startConfigData.hash" - var wsstack = WsmanStackCreateService(comm); - dev.amtstack = AmtStackCreateService(wsstack); - dev.amtstack.dev = dev; - dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtTlsAcmEx1); + if ((startConfigData == null) || (startConfigData.status != 0) || (typeof startConfigData.hash != 'string')) { + // Unable to call startTlsHostConfig on remote host. + dev.consoleMsg("Failed to startConfigurationHBased(), status = " + startConfigData.status); + removeAmtDevice(dev); + } else { + // Setup the WSMAN stack, no TLS + 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. + comm.xtlsFingerprint = startConfigData.hash.toLowerCase(); // Intel AMT leaf TLS cert need to match this hash (SHA256 or SHA384) + 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) { @@ -1868,14 +1872,36 @@ module.exports.CreateAmtManager = function (parent) { const dev = stack.dev; if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request. + // Check if we succesfully connected if (status != 200) { - dev.consoleMsg("Failed to perform ACM TLS connection, falling back to legacy host-based activation."); - activateIntelAmtAcm(dev); // Falling back to legacy WSMAN ACM activation, start by refreshing $$OsAdmin username and password. + dev.consoleMsg("Failed to perform ACM TLS connection."); + //activateIntelAmtAcm(dev); // It's possible to fallback to legacy WSMAN ACM activation here if we needed to.. + removeAmtDevice(dev); } else { // TODO!!! console.log('TODO!!!!!'); } } + + + + + + + + + + + + + + + + + + + + // Attempt Intel AMT ACM activation function activateIntelAmtAcm(dev, password, acminfo) {