From dc11a44a1900483c8f3feab9f0ac852c5acc4017 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 4 Mar 2021 01:54:04 -0800 Subject: [PATCH] More work on AMT TLS ACM activation. --- agents/modules_meshcmd/amt-mei.js | 90 +++++++++++++----------------- agents/modules_meshcore/amt-mei.js | 90 +++++++++++++----------------- amt/amt-wsman-comm.js | 6 +- amtmanager.js | 35 ++++++++++-- certoperations.js | 5 +- 5 files changed, 116 insertions(+), 110 deletions(-) diff --git a/agents/modules_meshcmd/amt-mei.js b/agents/modules_meshcmd/amt-mei.js index 3c9986cb..af35af68 100644 --- a/agents/modules_meshcmd/amt-mei.js +++ b/agents/modules_meshcmd/amt-mei.js @@ -24,22 +24,18 @@ function amt_heci() { this._ObjectID = "pthi"; this._rq = new Q(); - this._setupPTHI = function _setupPTHI() - { + this._setupPTHI = function _setupPTHI() { this._amt = heci.create(); this._amt.descriptorMetadata = "amt-pthi"; this._amt.BiosVersionLen = 65; this._amt.UnicodeStringLen = 20; this._amt.Parent = this; - this._amt.on('error', function _amtOnError(e) - { - if(this.Parent._rq.isEmpty()) - { + this._amt.on('error', function _amtOnError(e) { + if (this.Parent._rq.isEmpty()) { this.Parent.emit('error', e); // No pending requests, so propagate the error up } - else - { + else { // There is a pending request, so fail the pending request var user = this.Parent._rq.deQueue(); var params = user.optional; @@ -47,17 +43,14 @@ function amt_heci() { params.unshift({ Status: -1 }); // Relay an error callback.apply(this.Parent, params); - if(!this.Parent._rq.isEmpty()) - { + if (!this.Parent._rq.isEmpty()) { // There are still more pending requests, so try to re-helpconnect MEI this.connect(heci.GUIDS.AMT, { noPipeline: 1 }); } } }); - this._amt.on('connect', function _amtOnConnect() - { - this.on('data', function _amtOnData(chunk) - { + this._amt.on('connect', function _amtOnConnect() { + this.on('data', function _amtOnData(chunk) { //console.log("Received: " + chunk.length + " bytes"); var header = this.Parent.getCommand(chunk); //console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse); @@ -69,14 +62,12 @@ function amt_heci() { params.unshift(header); callback.apply(this.Parent, params); - if(this.Parent._rq.isEmpty()) - { + if (this.Parent._rq.isEmpty()) { // No More Requests, we can close PTHI this.Parent._amt.disconnect(); this.Parent._amt = null; } - else - { + else { // Send the next request this.write(this.Parent._rq.peekQueue().send); } @@ -93,8 +84,7 @@ function amt_heci() { return (ret); }; - this.sendCommand = function sendCommand() - { + this.sendCommand = function sendCommand() { if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); } var args = []; for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); } @@ -102,10 +92,9 @@ function amt_heci() { var header = Buffer.from('010100000000000000000000', 'hex'); header.writeUInt32LE(arguments[0] | 0x04000000, 4); header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8); - this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args , send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]]))}); + this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args, send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]])) }); - if(!this._amt) - { + if (!this._amt) { this._setupPTHI(); this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 }); } @@ -117,7 +106,7 @@ function amt_heci() { this.sendCommand(26, null, function (header, fn, opt) { if (header.Status == 0) { var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen).toString(), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4); - for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) { + for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen); ++i) { val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() }; v = v.slice(4 + (2 * this._amt.UnicodeStringLen)); } @@ -302,34 +291,27 @@ function amt_heci() { this.getLocalSystemAccount = function getLocalSystemAccount(callback) { var optional = []; for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } - this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) - { - if (header.Status == 0 && header.Data.length == 68) - { + this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) { + if (header.Status == 0 && header.Data.length == 68) { opt.unshift({ user: trim(header.Data.slice(0, 33).toString()), pass: trim(header.Data.slice(33, 67).toString()), raw: header.Data }); } - else - { + else { opt.unshift(null); } fn.apply(this, opt); }, callback, optional); } - this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback) - { + this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback) { var optional = []; for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); } var ifx = Buffer.alloc(4); ifx.writeUInt32LE(index); - this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt) - { - if(header.Status == 0) - { + this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt) { + if (header.Status == 0) { var info = {}; info.enabled = header.Data.readUInt32LE(0); info.dhcpEnabled = header.Data.readUInt32LE(8); - switch(header.Data[12]) - { + switch (header.Data[12]) { case 1: info.dhcpMode = 'ACTIVE' break; @@ -341,14 +323,13 @@ function amt_heci() { break; } info.mac = header.Data.slice(14).toString('hex:'); - + var addr = header.Data.readUInt32LE(4); info.address = ((addr >> 24) & 255) + '.' + ((addr >> 16) & 255) + '.' + ((addr >> 8) & 255) + '.' + (addr & 255); opt.unshift(info); fn.apply(this, opt); } - else - { + else { opt.unshift(null); fn.apply(this, opt); } @@ -398,21 +379,18 @@ function amt_heci() { fn.apply(this, opt); }, callback, optional); } - this.getProtocolVersion = function getProtocolVersion(callback) - { + this.getProtocolVersion = function getProtocolVersion(callback) { var optional = []; for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); } - if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this;} - this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) - { + if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this; } + this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) { if (status == 0) { var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString(); opt.unshift(result); fn.apply(self, opt); } - else - { + else { opt.unshift(null); fn.apply(self, opt); } @@ -421,7 +399,19 @@ function amt_heci() { } this.startConfigurationHBased = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) { if ((certHash == null) || ((certHash.length != 32) && (certHash.length != 48))) { func({ status: -101 }); } - + this.stopConfiguration(function (status) { + if (status == 0) { + // We stopped the configuration, wait 20 seconds before starting up again. + var f = function tf() { delete tf.parent.xtimeout; tf.parent.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); } + f.parent = this; + this.xtimeout = setTimeout(f, 20000); + } else { + // We are not in the connect mode, this is good, start configuration right away. + this.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); + } + }) + } + this.startConfigurationHBasedEx = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) { var optional = []; for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); } @@ -442,7 +432,7 @@ function amt_heci() { var amtHash = null; if (header.Data[0] == 2) { amtHash = header.Data.slice(1, 33); } // SHA256 if (header.Data[0] == 3) { amtHash = header.Data.slice(1, 49); } // SHA384 - opt.unshift({ status: header.Status, hash: amtHash }); + opt.unshift({ status: header.Status, hash: amtHash.toString('hex') }); } else { opt.unshift({ status: header.Status }); } diff --git a/agents/modules_meshcore/amt-mei.js b/agents/modules_meshcore/amt-mei.js index 3c9986cb..af35af68 100644 --- a/agents/modules_meshcore/amt-mei.js +++ b/agents/modules_meshcore/amt-mei.js @@ -24,22 +24,18 @@ function amt_heci() { this._ObjectID = "pthi"; this._rq = new Q(); - this._setupPTHI = function _setupPTHI() - { + this._setupPTHI = function _setupPTHI() { this._amt = heci.create(); this._amt.descriptorMetadata = "amt-pthi"; this._amt.BiosVersionLen = 65; this._amt.UnicodeStringLen = 20; this._amt.Parent = this; - this._amt.on('error', function _amtOnError(e) - { - if(this.Parent._rq.isEmpty()) - { + this._amt.on('error', function _amtOnError(e) { + if (this.Parent._rq.isEmpty()) { this.Parent.emit('error', e); // No pending requests, so propagate the error up } - else - { + else { // There is a pending request, so fail the pending request var user = this.Parent._rq.deQueue(); var params = user.optional; @@ -47,17 +43,14 @@ function amt_heci() { params.unshift({ Status: -1 }); // Relay an error callback.apply(this.Parent, params); - if(!this.Parent._rq.isEmpty()) - { + if (!this.Parent._rq.isEmpty()) { // There are still more pending requests, so try to re-helpconnect MEI this.connect(heci.GUIDS.AMT, { noPipeline: 1 }); } } }); - this._amt.on('connect', function _amtOnConnect() - { - this.on('data', function _amtOnData(chunk) - { + this._amt.on('connect', function _amtOnConnect() { + this.on('data', function _amtOnData(chunk) { //console.log("Received: " + chunk.length + " bytes"); var header = this.Parent.getCommand(chunk); //console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse); @@ -69,14 +62,12 @@ function amt_heci() { params.unshift(header); callback.apply(this.Parent, params); - if(this.Parent._rq.isEmpty()) - { + if (this.Parent._rq.isEmpty()) { // No More Requests, we can close PTHI this.Parent._amt.disconnect(); this.Parent._amt = null; } - else - { + else { // Send the next request this.write(this.Parent._rq.peekQueue().send); } @@ -93,8 +84,7 @@ function amt_heci() { return (ret); }; - this.sendCommand = function sendCommand() - { + this.sendCommand = function sendCommand() { if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); } var args = []; for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); } @@ -102,10 +92,9 @@ function amt_heci() { var header = Buffer.from('010100000000000000000000', 'hex'); header.writeUInt32LE(arguments[0] | 0x04000000, 4); header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8); - this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args , send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]]))}); + this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args, send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]])) }); - if(!this._amt) - { + if (!this._amt) { this._setupPTHI(); this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 }); } @@ -117,7 +106,7 @@ function amt_heci() { this.sendCommand(26, null, function (header, fn, opt) { if (header.Status == 0) { var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen).toString(), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4); - for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) { + for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen); ++i) { val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() }; v = v.slice(4 + (2 * this._amt.UnicodeStringLen)); } @@ -302,34 +291,27 @@ function amt_heci() { this.getLocalSystemAccount = function getLocalSystemAccount(callback) { var optional = []; for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } - this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) - { - if (header.Status == 0 && header.Data.length == 68) - { + this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) { + if (header.Status == 0 && header.Data.length == 68) { opt.unshift({ user: trim(header.Data.slice(0, 33).toString()), pass: trim(header.Data.slice(33, 67).toString()), raw: header.Data }); } - else - { + else { opt.unshift(null); } fn.apply(this, opt); }, callback, optional); } - this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback) - { + this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback) { var optional = []; for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); } var ifx = Buffer.alloc(4); ifx.writeUInt32LE(index); - this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt) - { - if(header.Status == 0) - { + this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt) { + if (header.Status == 0) { var info = {}; info.enabled = header.Data.readUInt32LE(0); info.dhcpEnabled = header.Data.readUInt32LE(8); - switch(header.Data[12]) - { + switch (header.Data[12]) { case 1: info.dhcpMode = 'ACTIVE' break; @@ -341,14 +323,13 @@ function amt_heci() { break; } info.mac = header.Data.slice(14).toString('hex:'); - + var addr = header.Data.readUInt32LE(4); info.address = ((addr >> 24) & 255) + '.' + ((addr >> 16) & 255) + '.' + ((addr >> 8) & 255) + '.' + (addr & 255); opt.unshift(info); fn.apply(this, opt); } - else - { + else { opt.unshift(null); fn.apply(this, opt); } @@ -398,21 +379,18 @@ function amt_heci() { fn.apply(this, opt); }, callback, optional); } - this.getProtocolVersion = function getProtocolVersion(callback) - { + this.getProtocolVersion = function getProtocolVersion(callback) { var optional = []; for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); } - if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this;} - this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) - { + if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this; } + this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) { if (status == 0) { var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString(); opt.unshift(result); fn.apply(self, opt); } - else - { + else { opt.unshift(null); fn.apply(self, opt); } @@ -421,7 +399,19 @@ function amt_heci() { } this.startConfigurationHBased = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) { if ((certHash == null) || ((certHash.length != 32) && (certHash.length != 48))) { func({ status: -101 }); } - + this.stopConfiguration(function (status) { + if (status == 0) { + // We stopped the configuration, wait 20 seconds before starting up again. + var f = function tf() { delete tf.parent.xtimeout; tf.parent.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); } + f.parent = this; + this.xtimeout = setTimeout(f, 20000); + } else { + // We are not in the connect mode, this is good, start configuration right away. + this.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); + } + }) + } + this.startConfigurationHBasedEx = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) { var optional = []; for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); } @@ -442,7 +432,7 @@ function amt_heci() { var amtHash = null; if (header.Data[0] == 2) { amtHash = header.Data.slice(1, 33); } // SHA256 if (header.Data[0] == 3) { amtHash = header.Data.slice(1, 49); } // SHA384 - opt.unshift({ status: header.Status, hash: amtHash }); + opt.unshift({ status: header.Status, hash: amtHash.toString('hex') }); } else { opt.unshift({ status: header.Status }); } diff --git a/amt/amt-wsman-comm.js b/amt/amt-wsman-comm.js index 94b991e7..c6abf9e3 100644 --- a/amt/amt-wsman-comm.js +++ b/amt/amt-wsman-comm.js @@ -242,9 +242,9 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn var options = { socket: ser, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; if (obj.xtlsMethod == 1) { options.secureProtocol = 'TLSv1_method'; } if (obj.xtlsoptions) { - if (obj.xtlsoptions.ca) options.ca = obj.xtlsoptions.ca; - if (obj.xtlsoptions.cert) options.cert = obj.xtlsoptions.cert; - if (obj.xtlsoptions.key) options.key = obj.xtlsoptions.key; + if (obj.xtlsoptions.ca) { options.ca = obj.xtlsoptions.ca; } + if (obj.xtlsoptions.cert) { options.cert = obj.xtlsoptions.cert; } + if (obj.xtlsoptions.key) { options.key = obj.xtlsoptions.key; } } obj.socket = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected); diff --git a/amtmanager.js b/amtmanager.js index be06ebf6..a8818c26 100644 --- a/amtmanager.js +++ b/amtmanager.js @@ -248,7 +248,11 @@ module.exports.CreateAmtManager = function (parent) { break; case 'startTlsHostConfig': if (dev.acmTlsInfo == null) break; - console.log(jsondata); // TODO: Start TLS activation. + if ((typeof jsondata.value != 'object') || (typeof jsondata.value.status != 'number') || (jsondata.value.status != 0)) { + removeAmtDevice(dev); // Failed to start TLS configuration + } else { + activateIntelAmtTlsAcmEx(dev, jsondata.value); // Start TLS activation. + } break; } } @@ -1678,13 +1682,13 @@ module.exports.CreateAmtManager = function (parent) { // We are not activated now, go to ACM directly. // If this is Intel AMT 14 or better, we are going to attempt a host-based end-to-end TLS activation. if (typeof dev.intelamt.ver == 'string') { var verSplit = dev.intelamt.ver.split('.'); if (verSplit.length >= 3) { dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); } } - if (dev.aquired.majorver >= 14) { + //if (dev.aquired.majorver >= 14) { // Perform host-based TLS ACM activation - activateIntelAmtTlsAcm(dev, mesh.amt.password, acminfo); - } else { + //activateIntelAmtTlsAcm(dev, mesh.amt.password, acminfo); + //} else { // Perform host-based ACM activation activateIntelAmtAcm(dev, mesh.amt.password, acminfo); - } + //} } } } @@ -1803,6 +1807,27 @@ module.exports.CreateAmtManager = function (parent) { dev.controlMsg({ action: 'startTlsHostConfig', hash: acmTlsInfo.hash, hostVpn: false, dnsSuffixList: null }); } + // Attempt Intel AMT TLS ACM activation after startConfiguration() is called on remote device + function activateIntelAmtTlsAcmEx(dev, startConfigData) { + console.log('activateIntelAmtTlsAcmEx'); + // Setup the WSMAN stack, no TLS + var comm = CreateWsmanComm(dev.nodeid, 16993, 'admin', '', 1, { cert: dev.acmTlsInfo.certs, 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); + } + + function activateIntelAmtTlsAcmEx1(stack, name, responses, status) { + console.log('activateIntelAmtTlsAcmEx1', status, responses); + const dev = stack.dev; + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request. + if (status != 200) { dev.consoleMsg("Failed to get Intel AMT state."); removeAmtDevice(dev); return; } + + // TODO!!! + } + // Attempt Intel AMT ACM activation function activateIntelAmtAcm(dev, password, acminfo) { // Generate a random Intel AMT password if needed diff --git a/certoperations.js b/certoperations.js index 2ba9c21d..fec570be 100644 --- a/certoperations.js +++ b/certoperations.js @@ -51,7 +51,8 @@ module.exports.CertificateOperations = function (parent) { var leafcert = obj.IssueWebServerCertificate(rootcert, false, fqdn, 'mc', 'Intel(R) Client Setup Certificate', { serverAuth: true, '2.16.840.1.113741.1.2.3': true }, false); // Setup the certificate chain and key - certChain = [obj.pki.certificateToPem(leafcert.cert), obj.pki.certificateToPem(domain.amtacmactivation.certs[certIndex].rootcert)]; + //certChain = [ obj.pki.certificateToPem(leafcert.cert), obj.pki.certificateToPem(domain.amtacmactivation.certs[certIndex].rootcert) ]; + certChain = [ obj.pki.certificateToPem(domain.amtacmactivation.certs[certIndex].rootcert), obj.pki.certificateToPem(leafcert.cert) ]; signkey = obj.pki.privateKeyToPem(leafcert.key); } else { // Make sure the cert chain is in PEM format @@ -61,7 +62,7 @@ module.exports.CertificateOperations = function (parent) { } // Hash the leaf certificate and return the certificate chain and signing key - return { action: 'acmactivate', certs: certChain, signkey: signkey, hash: obj.getCertHash(certChain[0]) }; + return { action: 'acmactivate', certs: certChain, signkey: signkey, hash: obj.getCertHash(certChain[certChain.length - 1]) }; } // Sign a Intel AMT ACM activation request