Added CCM activation support.

Ylian Saint-Hilaire committed Oct 20, 2020 at 15:15 UTC 3b355e197f8ee0c756efcb024324b0de32916ec6
4 files changed +105 -9
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
amtmanager.js
+104 -4
@@ -71,6 +71,9 @@ module.exports.CreateAmtManager = function(parent) {
71 var i = devices.indexOf(dev);
72 if (i == -1) return false;
73
74 + // Remove from task limiter if needed
75 + if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
76 +
77 // Clean up this device
78 if (dev.amtstack != null) { dev.amtstack.wsman.comm.FailAllError = 999; delete dev.amtstack; } // Disconnect any active connections.
79 if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
@@ -86,16 +89,17 @@ module.exports.CreateAmtManager = function(parent) {
89
90 // Remove all Intel AMT devices for a given nodeid
91 function removeDevice(nodeid) {
89 - // Remove from task limiter if needed
90 - if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
91 -
92 // Find the devices in the list
93 var devices = obj.amtDevices[nodeid];
94 if (devices == null) return false;
95
96 for (var i in devices) {
97 - // Clean up this device
97 var dev = devices[i];
98 +
99 + // Remove from task limiter if needed
100 + if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
101 +
102 + // Clean up this device
103 if (dev.amtstack != null) { dev.amtstack.wsman.comm.FailAllError = 999; delete dev.amtstack; } // Disconnect any active connections.
104 if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
105 }
@@ -230,6 +234,12 @@ module.exports.CreateAmtManager = function(parent) {
234 function attemptInitialContact(dev) {
235 parent.debug('amt', "Attempt Initial Contact", dev.name, dev.connType);
236
237 + if ((dev.connType == 2) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (dev.mpsConnection.tag.meiState.ProvisioningState !== 2)) {
238 + // This Intel AMT device is not activated, we need to work on activating it.
239 + activateIntelAmt(dev);
240 + return;
241 + }
242 +
243 if ((dev.acctry == null) && ((typeof dev.intelamt.user != 'string') || (typeof dev.intelamt.pass != 'string'))) {
244 if ((obj.amtAdminAccounts[dev.domainid] != null) && (obj.amtAdminAccounts[dev.domainid].length > 0)) { dev.acctry = 0; } else { removeAmtDevice(dev); return; }
245 }
@@ -435,6 +445,7 @@ module.exports.CreateAmtManager = function(parent) {
445 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'); }
446 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'); }
447 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'); }
448 + 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'); }
449 if (device.intelamt.state != 2) { change = 1; log = 1; device.intelamt.state = 2; changes.push('AMT state'); }
450
451 // Update Intel AMT flags if needed
@@ -672,6 +683,11 @@ module.exports.CreateAmtManager = function(parent) {
683 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
684 if (status != 200) { dev.consoleMsg("Failed to generate a key pair (" + status + ")."); removeAmtDevice(dev); return; }
685
686 + // Check that we get a key pair reference
687 + var x = null;
688 + try { x = responses.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']; } catch (ex) { }
689 + if (x == null) { dev.consoleMsg("Unable to get key pair reference."); removeAmtDevice(dev); return; }
690 +
691 // Get the new key pair
692 dev.amtstack.Enum('AMT_PublicPrivateKeyPair', function (stack, name, responses, status, tag) {
693 const dev = stack.dev;
@@ -700,6 +716,12 @@ module.exports.CreateAmtManager = function(parent) {
716
717 // Place the resulting signed certificate back into AMT
718 var pem = obj.parent.certificateOperations.forge.pki.certificateToPem(cert).replace(/(\r\n|\n|\r)/gm, '');
719 +
720 + // Set the certificate finderprint (SHA1)
721 + var md = obj.parent.certificateOperations.forge.md.sha1.create();
722 + md.update(obj.parent.certificateOperations.forge.asn1.toDer(obj.parent.certificateOperations.forge.pki.certificateToAsn1(cert)).getBytes());
723 + dev.aquired.xhash = md.digest().toHex();
724 +
725 dev.amtstack.AMT_PublicKeyManagementService_AddCertificate(pem.substring(27, pem.length - 25), function (stack, name, responses, status) {
726 const dev = stack.dev;
727 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
@@ -760,6 +782,13 @@ module.exports.CreateAmtManager = function(parent) {
782 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
783 if (status != 200) { dev.consoleMsg("Failed perform commit (" + status + ")."); removeAmtDevice(dev); return; }
784 dev.consoleMsg("Enabled TLS");
785 +
786 + // Update device in the database
787 + dev.aquired.tls = 1;
788 + dev.aquired.hash = dev.aquired.xhash;
789 + delete dev.aquired.xhash;
790 + UpdateDevice(dev);
791 +
792 // TODO: Switch our communications to TLS (Restart our management of this node)
793 devTaskCompleted(dev);
794 });
@@ -1159,6 +1188,70 @@ module.exports.CreateAmtManager = function(parent) {
1188 devTaskCompleted(dev);
1189 }
1190
1191 +
1192 + //
1193 + // Intel AMT Activation
1194 + //
1195 +
1196 + function activateIntelAmt(dev) {
1197 + // Find the Intel AMT policy
1198 + const mesh = parent.webserver.meshes[dev.meshid];
1199 + if (mesh == null) { dev.consoleMsg("Unable to find device group."); removeAmtDevice(dev); return; }
1200 + var amtPolicy = 0; // 0 = Do nothing, 1 = Deactivate CCM, 2 = CCM, 3 = ACM
1201 + if (mesh.amt != null) { if (mesh.amt.type) { amtPolicy = mesh.amt.type; } }
1202 + 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; }
1203 + if (amtPolicy == 0) { removeAmtDevice(dev); return; } // Do nothing, we should not have gotten this CIRA-LMS connection.
1204 + if (amtPolicy == 2) { activateIntelAmtCcm(dev, mesh.amt.password); }
1205 + }
1206 +
1207 + function activateIntelAmtCcm(dev, password) {
1208 + console.log('Intel AMT CCM Activation Required: ' + dev.name, dev.nodeid);
1209 + if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
1210 + dev.temp = { pass: password };
1211 +
1212 + // Setup the WSMAN stack, no TLS
1213 + var comm = CreateWsmanComm(dev.nodeid, 16992, dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass, 0, null, dev.mpsConnection); // No TLS
1214 + var wsstack = WsmanStackCreateService(comm);
1215 + dev.amtstack = AmtStackCreateService(wsstack);
1216 + dev.amtstack.dev = dev;
1217 + dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtCcmEx1);
1218 + }
1219 +
1220 + function activateIntelAmtCcmEx1(stack, name, responses, status) {
1221 + const dev = stack.dev;
1222 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1223 + if (status != 200) { dev.consoleMsg("Failed to get Intel AMT state."); removeAmtDevice(dev); return; }
1224 + if (responses['IPS_HostBasedSetupService'].response['AllowedControlModes'].length != 2) { dev.consoleMsg("Client control mode activation not allowed."); removeAmtDevice(dev); return; }
1225 + 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);
1226 + }
1227 +
1228 + function activateIntelAmtCcmEx2(stack, name, responses, status) {
1229 + const dev = stack.dev;
1230 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1231 + if (status != 200) { dev.consoleMsg("Failed to activate Intel AMT to CCM."); removeAmtDevice(dev); return; }
1232 + obj.parent.mpsserver.SendJsonControl(dev.mpsConnection, { action: 'mestate' }); // Request an MEI state refresh
1233 +
1234 + // Update the device
1235 + dev.aquired = {};
1236 + dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM
1237 + var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
1238 + 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]); }
1239 + dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm;
1240 + dev.aquired.user = 'admin';
1241 + dev.aquired.pass = dev.temp.pass;
1242 + dev.aquired.lastContact = Date.now();
1243 + dev.aquired.tls = 0;
1244 + UpdateDevice(dev);
1245 +
1246 + // Success, switch to managing this device
1247 + dev.consoleMsg("Succesfully activated Intel AMT in CCM mode.");
1248 +
1249 + // Wait 8 seconds before attempting to manage this device in CCM
1250 + var f = function doManage() { if (isAmtDeviceValid(dev)) { attemptInitialContact(doManage.dev); } }
1251 + f.dev = dev;
1252 + setTimeout(f, 8000);
1253 + }
1254 +
1255 //
1256 // General Methods
1257 //
@@ -1190,6 +1283,13 @@ module.exports.CreateAmtManager = function(parent) {
1283 }
1284 }
1285
1286 + // Generate a random Intel AMT password
1287 + function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
1288 + function getRandomAmtPassword() { var p; do { p = Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
1289 + function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
1290 + 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; }
1291 +
1292 + function hex_md5(str) { return obj.parent.crypto.createHash('md5').update(str).digest('hex'); }
1293 function Clone(v) { return JSON.parse(JSON.stringify(v)); }
1294 function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
1295 function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
views/default.handlebars
+1 -5
@@ -9571,11 +9571,7 @@
9571 if (xxdialogMode) return;
9572 var x = '', acmoption = '';
9573 if ((features & 0x100000) != 0) { acmoption = '<option value=3>' + "Simple Admin Control Mode (ACM)" + '</option>'; }
9574 - if (currentMesh.mtype == 1) {
9575 - 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>');
9576 - } else {
9577 - 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>');
9578 - }
9574 + 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>');
9575 x += '<div id=dp20amtpolicydiv></div>';
9576 setDialogMode(2, "Intel&reg; AMT Policy", 3, p20editMeshAmtEx, x);
9577 if (currentMesh.amt) { Q('dp20amtpolicy').value = currentMesh.amt.type; }