Added CCM activation support.

This commit is contained in:
Ylian Saint-Hilaire 2020-10-20 15:15:56 -07:00
parent 8df9e727ee
commit 3b355e197f
4 changed files with 105 additions and 9 deletions

Binary file not shown.

Binary file not shown.

View File

@ -71,6 +71,9 @@ module.exports.CreateAmtManager = function(parent) {
var i = devices.indexOf(dev);
if (i == -1) return false;
// Remove from task limiter if needed
if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
// Clean up this device
if (dev.amtstack != null) { dev.amtstack.wsman.comm.FailAllError = 999; delete dev.amtstack; } // Disconnect any active connections.
if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
@ -86,16 +89,17 @@ module.exports.CreateAmtManager = function(parent) {
// Remove all Intel AMT devices for a given nodeid
function removeDevice(nodeid) {
// Remove from task limiter if needed
if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
// Find the devices in the list
var devices = obj.amtDevices[nodeid];
if (devices == null) return false;
for (var i in devices) {
// Clean up this device
var dev = devices[i];
// Remove from task limiter if needed
if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
// Clean up this device
if (dev.amtstack != null) { dev.amtstack.wsman.comm.FailAllError = 999; delete dev.amtstack; } // Disconnect any active connections.
if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
}
@ -230,6 +234,12 @@ module.exports.CreateAmtManager = function(parent) {
function attemptInitialContact(dev) {
parent.debug('amt', "Attempt Initial Contact", dev.name, dev.connType);
if ((dev.connType == 2) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (dev.mpsConnection.tag.meiState.ProvisioningState !== 2)) {
// This Intel AMT device is not activated, we need to work on activating it.
activateIntelAmt(dev);
return;
}
if ((dev.acctry == null) && ((typeof dev.intelamt.user != 'string') || (typeof dev.intelamt.pass != 'string'))) {
if ((obj.amtAdminAccounts[dev.domainid] != null) && (obj.amtAdminAccounts[dev.domainid].length > 0)) { dev.acctry = 0; } else { removeAmtDevice(dev); return; }
}
@ -435,6 +445,7 @@ module.exports.CreateAmtManager = function(parent) {
if (dev.aquired.pass && (typeof dev.aquired.pass == 'string') && (dev.aquired.pass != device.intelamt.pass)) { change = 1; log = 1; device.intelamt.pass = dev.aquired.pass; changes.push('AMT pass'); }
if (dev.aquired.realm && (typeof dev.aquired.realm == 'string') && (dev.aquired.realm != device.intelamt.realm)) { change = 1; log = 1; device.intelamt.realm = dev.aquired.realm; changes.push('AMT realm'); }
if (dev.aquired.hash && (typeof dev.aquired.hash == 'string') && (dev.aquired.hash != device.intelamt.hash)) { change = 1; log = 1; device.intelamt.hash = dev.aquired.hash; changes.push('AMT hash'); }
if (dev.aquired.tls && (typeof dev.aquired.tls == 'number') && (dev.aquired.tls != device.intelamt.tls)) { change = 1; log = 1; device.intelamt.tls = dev.aquired.tls; changes.push('AMT TLS'); }
if (device.intelamt.state != 2) { change = 1; log = 1; device.intelamt.state = 2; changes.push('AMT state'); }
// Update Intel AMT flags if needed
@ -672,6 +683,11 @@ module.exports.CreateAmtManager = function(parent) {
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
if (status != 200) { dev.consoleMsg("Failed to generate a key pair (" + status + ")."); removeAmtDevice(dev); return; }
// Check that we get a key pair reference
var x = null;
try { x = responses.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']; } catch (ex) { }
if (x == null) { dev.consoleMsg("Unable to get key pair reference."); removeAmtDevice(dev); return; }
// Get the new key pair
dev.amtstack.Enum('AMT_PublicPrivateKeyPair', function (stack, name, responses, status, tag) {
const dev = stack.dev;
@ -700,6 +716,12 @@ module.exports.CreateAmtManager = function(parent) {
// Place the resulting signed certificate back into AMT
var pem = obj.parent.certificateOperations.forge.pki.certificateToPem(cert).replace(/(\r\n|\n|\r)/gm, '');
// Set the certificate finderprint (SHA1)
var md = obj.parent.certificateOperations.forge.md.sha1.create();
md.update(obj.parent.certificateOperations.forge.asn1.toDer(obj.parent.certificateOperations.forge.pki.certificateToAsn1(cert)).getBytes());
dev.aquired.xhash = md.digest().toHex();
dev.amtstack.AMT_PublicKeyManagementService_AddCertificate(pem.substring(27, pem.length - 25), function (stack, name, responses, status) {
const dev = stack.dev;
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
@ -760,6 +782,13 @@ module.exports.CreateAmtManager = function(parent) {
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
if (status != 200) { dev.consoleMsg("Failed perform commit (" + status + ")."); removeAmtDevice(dev); return; }
dev.consoleMsg("Enabled TLS");
// Update device in the database
dev.aquired.tls = 1;
dev.aquired.hash = dev.aquired.xhash;
delete dev.aquired.xhash;
UpdateDevice(dev);
// TODO: Switch our communications to TLS (Restart our management of this node)
devTaskCompleted(dev);
});
@ -1159,6 +1188,70 @@ module.exports.CreateAmtManager = function(parent) {
devTaskCompleted(dev);
}
//
// Intel AMT Activation
//
function activateIntelAmt(dev) {
// Find the Intel AMT policy
const mesh = parent.webserver.meshes[dev.meshid];
if (mesh == null) { dev.consoleMsg("Unable to find device group."); removeAmtDevice(dev); return; }
var amtPolicy = 0; // 0 = Do nothing, 1 = Deactivate CCM, 2 = CCM, 3 = ACM
if (mesh.amt != null) { if (mesh.amt.type) { amtPolicy = mesh.amt.type; } }
if ((typeof dev.mpsConnection.tag.meiState.OsAdmin != 'object') || (typeof dev.mpsConnection.tag.meiState.OsAdmin.user != 'string') || (typeof dev.mpsConnection.tag.meiState.OsAdmin.pass != 'string')) { amtPolicy = 0; }
if (amtPolicy == 0) { removeAmtDevice(dev); return; } // Do nothing, we should not have gotten this CIRA-LMS connection.
if (amtPolicy == 2) { activateIntelAmtCcm(dev, mesh.amt.password); }
}
function activateIntelAmtCcm(dev, password) {
console.log('Intel AMT CCM Activation Required: ' + dev.name, dev.nodeid);
if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
dev.temp = { pass: password };
// Setup the WSMAN stack, no TLS
var comm = CreateWsmanComm(dev.nodeid, 16992, dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass, 0, null, dev.mpsConnection); // No TLS
var wsstack = WsmanStackCreateService(comm);
dev.amtstack = AmtStackCreateService(wsstack);
dev.amtstack.dev = dev;
dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtCcmEx1);
}
function activateIntelAmtCcmEx1(stack, name, responses, status) {
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; }
if (responses['IPS_HostBasedSetupService'].response['AllowedControlModes'].length != 2) { dev.consoleMsg("Client control mode activation not allowed."); removeAmtDevice(dev); return; }
dev.amtstack.IPS_HostBasedSetupService_Setup(2, hex_md5('admin:' + responses['AMT_GeneralSettings'].response['DigestRealm'] + ':' + dev.temp.pass).substring(0, 32), null, null, null, null, activateIntelAmtCcmEx2);
}
function activateIntelAmtCcmEx2(stack, name, responses, status) {
const dev = stack.dev;
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
if (status != 200) { dev.consoleMsg("Failed to activate Intel AMT to CCM."); removeAmtDevice(dev); return; }
obj.parent.mpsserver.SendJsonControl(dev.mpsConnection, { action: 'mestate' }); // Request an MEI state refresh
// Update the device
dev.aquired = {};
dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM
var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
if (verSplit.length >= 3) { dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); }
dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm;
dev.aquired.user = 'admin';
dev.aquired.pass = dev.temp.pass;
dev.aquired.lastContact = Date.now();
dev.aquired.tls = 0;
UpdateDevice(dev);
// Success, switch to managing this device
dev.consoleMsg("Succesfully activated Intel AMT in CCM mode.");
// Wait 8 seconds before attempting to manage this device in CCM
var f = function doManage() { if (isAmtDeviceValid(dev)) { attemptInitialContact(doManage.dev); } }
f.dev = dev;
setTimeout(f, 8000);
}
//
// General Methods
//
@ -1190,6 +1283,13 @@ module.exports.CreateAmtManager = function(parent) {
}
}
// Generate a random Intel AMT password
function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
function getRandomAmtPassword() { var p; do { p = Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
function getRandomLowerCase(len) { var r = '', random = obj.crypto.randomBytes(len); for (var i = 0; i < len; i++) { r += String.fromCharCode(97 + (random[i] % 26)); } return r; }
function hex_md5(str) { return obj.parent.crypto.createHash('md5').update(str).digest('hex'); }
function Clone(v) { return JSON.parse(JSON.stringify(v)); }
function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }

View File

@ -9571,11 +9571,7 @@
if (xxdialogMode) return;
var x = '', acmoption = '';
if ((features & 0x100000) != 0) { acmoption = '<option value=3>' + "Simple Admin Control Mode (ACM)" + '</option>'; }
if (currentMesh.mtype == 1) {
x += addHtmlValue("Type", '<select id=dp20amtpolicy style=width:230px onchange=p20editMeshAmtChange()><option value=0>' + "No Policy" + '</option><option value=2>' + "Simple Client Control Mode (CCM)" + '</option>' + acmoption + '</select>');
} else {
x += addHtmlValue("Type", '<select id=dp20amtpolicy style=width:230px onchange=p20editMeshAmtChange()><option value=0>' + "No Policy" + '</option><option value=1>' + "Deactivate Client Control Mode (CCM)" + '</option><option value=2>' + "Simple Client Control Mode (CCM)" + '</option>' + acmoption + '</select>');
}
x += addHtmlValue("Type", '<select id=dp20amtpolicy style=width:230px onchange=p20editMeshAmtChange()><option value=0>' + "No Policy" + '</option><option value=1>' + "Deactivate Client Control Mode (CCM)" + '</option><option value=2>' + "Simple Client Control Mode (CCM)" + '</option>' + acmoption + '</select>');
x += '<div id=dp20amtpolicydiv></div>';
setDialogMode(2, "Intel&reg; AMT Policy", 3, p20editMeshAmtEx, x);
if (currentMesh.amt) { Q('dp20amtpolicy').value = currentMesh.amt.type; }