2* @description MeshCentral Intel AMT manager
3* @author Ylian Saint-Hilaire
4* @copyright Intel Corporation 2018-2022
11/*jshint strict:false */
13/*jshint esversion: 6 */
16module.exports.CreateAmtManager = function (parent) {
19 obj.amtDevices = {}; // Nodeid --> [ dev ]
20 obj.activeLocalConnections = {}; // Host --> dev
21 obj.amtAdminAccounts = {}; // DomainId -> [ { user, pass } ]
22 obj.rootCertBase64 = obj.parent.certificates.root.cert.split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('').split('\r').join('').split('\n').join('')
23 obj.rootCertCN = obj.parent.certificateOperations.forge.pki.certificateFromPem(obj.parent.certificates.root.cert).subject.getField('CN').value;
25 // 802.1x authentication protocols
26 const netAuthStrings = ['eap-tls', 'eap-ttls/mschapv2', 'peapv0/eap-mschapv2', 'peapv1/eap-gtc', 'eap-fast/mschapv2', 'eap-fast/gtc', 'eap-md5', 'eap-psk', 'eap-sim', 'eap-aka', 'eap-fast/tls'];
29 const CreateWsmanComm = require('./amt/amt-wsman-comm');
30 const WsmanStackCreateService = require('./amt/amt-wsman');
31 const AmtStackCreateService = require('./amt/amt');
32 const ConnectionTypeStrings = { 0: "CIRA", 1: "Relay", 2: "LMS", 3: "Local" };
34 // Check that each domain configuration is correct because we are not going to be checking this later.
35 if (parent.config == null) parent.config = {};
36 if (parent.config.domains == null) parent.config.domains = {};
37 for (var domainid in parent.config.domains) {
38 var domain = parent.config.domains[domainid];
39 if (typeof domain.amtmanager != 'object') { domain.amtmanager = {}; }
41 // Load administrator accounts
42 if (Array.isArray(domain.amtmanager.adminaccounts) == true) {
43 for (var i = 0; i < domain.amtmanager.adminaccounts.length; i++) {
44 var c = domain.amtmanager.adminaccounts[i], c2 = {};
45 if (typeof c.user == 'string') { c2.user = c.user; } else { c2.user = 'admin'; }
46 if (typeof c.pass == 'string') {
48 if (obj.amtAdminAccounts[domainid] == null) { obj.amtAdminAccounts[domainid] = []; }
49 obj.amtAdminAccounts[domainid].push(c2);
53 delete domain.amtmanager.adminaccounts;
56 // Check environment detection
57 if (Array.isArray(domain.amtmanager.environmentdetection) == true) {
59 for (var i = 0; i < domain.amtmanager.environmentdetection.length; i++) {
60 var x = domain.amtmanager.environmentdetection[i].toLowerCase();
61 if ((typeof x == 'string') && (x != '') && (x.length < 64) && (envDetect.indexOf(x) == -1)) { envDetect.push(x); }
62 if (envDetect.length >= 4) break; // Maximum of 4 DNS suffix
64 if (envDetect.length > 0) { domain.amtmanager.environmentdetection = envDetect; } else { delete domain.amtmanager.environmentdetection; }
66 delete domain.amtmanager.environmentdetection;
69 // Check 802.1x wired profile if present
70 if ((domain.amtmanager['802.1x'] != null) && (typeof domain.amtmanager['802.1x'] == 'object')) {
71 if (domain.amtmanager['802.1x'].satellitecredentials != null) {
72 if (typeof domain.amtmanager['802.1x'].satellitecredentials != 'string') { delete domain.amtmanager['802.1x']; } else {
73 const userSplit = domain.amtmanager['802.1x'].satellitecredentials.split('/');
74 if (userSplit.length > 3) { delete domain.amtmanager['802.1x']; }
75 else if (userSplit.length == 2) { domain.amtmanager['802.1x'].satellitecredentials = 'user/' + domain.id + '/' + userSplit[1]; }
76 else if (userSplit.length == 1) { domain.amtmanager['802.1x'].satellitecredentials = 'user/' + domain.id + '/' + userSplit[0]; }
80 if (typeof domain.amtmanager['802.1x'].servercertificatename != 'string') {
81 delete domain.amtmanager['802.1x'].servercertificatenamecomparison;
83 const serverCertCompareStrings = ['', '', 'fullname', 'domainsuffix'];
84 if (typeof domain.amtmanager['802.1x'].servercertificatenamecomparison == 'string') {
85 domain.amtmanager['802.1x'].servercertificatenamecomparison = serverCertCompareStrings.indexOf(domain.amtmanager['802.1x'].servercertificatenamecomparison.toLowerCase());
86 if (domain.amtmanager['802.1x'].servercertificatenamecomparison == -1) { domain.amtmanager['802.1x'].servercertificatenamecomparison = 2; } // Default to full name compare
90 if (typeof domain.amtmanager['802.1x'].authenticationprotocol == 'string') {
91 domain.amtmanager['802.1x'].authenticationprotocol = netAuthStrings.indexOf(domain.amtmanager['802.1x'].authenticationprotocol.toLowerCase());
92 if (domain.amtmanager['802.1x'].authenticationprotocol == -1) { delete domain.amtmanager['802.1x']; }
96 // Check WIFI profiles
97 //var wifiAuthMethod = { 1: "Other", 2: "Open", 3: "Shared Key", 4: "WPA PSK", 5: "WPA 802.1x", 6: "WPA2 PSK", 7: "WPA2 802.1x", 32768: "WPA3 SAE IEEE 802.1x", 32769: "WPA3 OWE IEEE 802.1x" };
98 //var wifiEncMethod = { 1: "Other", 2: "WEP", 3: "TKIP", 4: "CCMP", 5: "None" }
99 if (Array.isArray(domain.amtmanager.wifiprofiles) == true) {
100 var goodWifiProfiles = [];
101 for (var i = 0; i < domain.amtmanager.wifiprofiles.length; i++) {
102 var wifiProfile = domain.amtmanager.wifiprofiles[i];
103 if ((typeof wifiProfile.ssid == 'string') && (wifiProfile.ssid != '')) {
104 if ((wifiProfile.name == null) || (wifiProfile.name == '')) { wifiProfile.name = wifiProfile.ssid; }
107 if (typeof wifiProfile.authentication == 'string') { wifiProfile.authentication = wifiProfile.authentication.toLowerCase(); }
108 if (wifiProfile.authentication == 'wpa-psk') { wifiProfile.authentication = 4; }
109 if (wifiProfile.authentication == 'wpa2-psk') { wifiProfile.authentication = 6; }
110 if (wifiProfile.authentication == 'wpa-8021x') { wifiProfile.authentication = 5; }
111 if (wifiProfile.authentication == 'wpa2-802.1x') { wifiProfile.authentication = 7; }
112 if (wifiProfile.authentication == 'wpa3-sae-802.1x') { wifiProfile.authentication = 32768; }
113 if (wifiProfile.authentication == 'wpa3-owe-802.1x') { wifiProfile.authentication = 32769; }
114 if (typeof wifiProfile.authentication != 'number') {
115 if (wifiProfile['802.1x']) { wifiProfile.authentication = 7; } // Default to WPA2-802.1x
116 else { wifiProfile.authentication = 6; } // Default to WPA2-PSK
120 if (typeof wifiProfile.encryption == 'string') { wifiProfile.encryption = wifiProfile.encryption.toLowerCase(); }
121 if ((wifiProfile.encryption == 'ccmp-aes') || (wifiProfile.encryption == 'ccmp')) { wifiProfile.encryption = 4; }
122 if ((wifiProfile.encryption == 'tkip-rc4') || (wifiProfile.encryption == 'tkip')) { wifiProfile.encryption = 3; }
123 if (typeof wifiProfile.encryption != 'number') { wifiProfile.encryption = 4; } // Default to CCMP-AES
126 wifiProfile.type = 3; // Infrastructure
128 // Check authentication
129 if ([4, 6].indexOf(wifiProfile.authentication) >= 0) {
130 // Password authentication
131 if ((typeof wifiProfile.password != 'string') || (wifiProfile.password.length < 8) || (wifiProfile.password.length > 63)) continue;
132 } else if ([5, 7, 32768, 32769].indexOf(wifiProfile.authentication) >= 0) {
133 // 802.1x authentication
134 if ((domain.amtmanager['802.1x'] == null) || (typeof domain.amtmanager['802.1x'] != 'object')) continue;
137 goodWifiProfiles.push(wifiProfile);
141 domain.amtmanager.wifiprofiles = goodWifiProfiles;
143 delete domain.amtmanager.wifiprofiles;
147 // Check if an Intel AMT device is being managed
148 function isAmtDeviceValid(dev) {
149 var devices = obj.amtDevices[dev.nodeid];
150 if (devices == null) return false;
151 return (devices.indexOf(dev) >= 0)
154 // Add an Intel AMT managed device
155 function addAmtDevice(dev) {
156 var devices = obj.amtDevices[dev.nodeid];
157 if (devices == null) { obj.amtDevices[dev.nodeid] = [dev]; return true; }
158 if (devices.indexOf(dev) >= 0) return false; // This device is already in the list
159 devices.push(dev); // Add the device to the list
163 // Remove an Intel AMT managed device
164 function removeAmtDevice(dev, tag) {
165 parent.debug('amt', dev.name, "Remove device", dev.nodeid, dev.connType, tag);
167 // Find the device in the list
168 var devices = obj.amtDevices[dev.nodeid];
169 if (devices == null) return false;
170 var i = devices.indexOf(dev);
171 if (i == -1) return false;
173 // Remove from task limiter if needed
174 if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
176 // Clean up this device
177 if (dev.amtstack != null) { dev.amtstack.CancelAllQueries(999); if (dev.amtstack != null) { delete dev.amtstack.dev; delete dev.amtstack; } }
178 if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
180 // Remove the device from the list
181 devices.splice(i, 1);
182 if (devices.length == 0) { delete obj.amtDevices[dev.nodeid]; } else { obj.amtDevices[dev.nodeid] = devices; }
184 // Notify connection closure if this is a LMS connection
185 if (dev.connType == 2) { dev.controlMsg({ action: 'close' }); }
189 // Remove all Intel AMT devices for a given nodeid
190 function removeDevice(nodeid) {
191 parent.debug('amt', "Remove nodeid", nodeid);
193 // Find the devices in the list
194 var devices = obj.amtDevices[nodeid];
195 if (devices == null) return false;
197 for (var i in devices) {
198 var dev = devices[i];
200 // Remove from task limiter if needed
201 if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
203 // Clean up this device
204 if (dev.amtstack != null) { dev.amtstack.wsman.comm.FailAllError = 999; delete dev.amtstack; } // Disconnect any active connections.
205 if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
207 // Notify connection closure if this is a LMS connection
208 if (dev.connType == 2) { dev.controlMsg({ action: 'close' }); }
211 // Remove all Intel AMT management sessions for this nodeid
212 delete obj.amtDevices[nodeid];
214 // If a 802.1x profile is active with MeshCentral Satellite, notify Satellite of the removal
215 if (domain.amtmanager['802.1x'] != null) {
216 var reqId = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64'); // Generate a crypto-secure request id.
217 parent.DispatchEvent([domain.amtmanager['802.1x'].satellitecredentials], obj, { action: 'satellite', subaction: '802.1x-Profile-Remove', satelliteFlags: 2, nodeid: nodeid, domain: nodeid.split('/')[1], nolog: 1, ver: dev.intelamt.ver });
223 // Start Intel AMT management
224 // connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
225 obj.startAmtManagement = function (nodeid, connType, connection) {
226 //if (connType == 3) return; // DEBUG
227 var devices = obj.amtDevices[nodeid], dev = null;
228 if (devices != null) { for (var i in devices) { if ((devices[i].mpsConnection == connection) || (devices[i].host == connection)) { dev = devices[i]; } } }
229 if (dev != null) return false; // We are already managing this device on this connection
230 dev = { nodeid: nodeid, connType: connType, domainid: nodeid.split('/')[1] };
231 if (typeof connection == 'string') { dev.host = connection; }
232 if (typeof connection == 'object') { dev.mpsConnection = connection; }
233 dev.consoleMsg = function deviceConsoleMsg(msg) { parent.debug('amt', deviceConsoleMsg.dev.name, msg); if (typeof deviceConsoleMsg.conn == 'object') { deviceConsoleMsg.conn.ControlMsg({ action: 'console', msg: msg }); } }
234 dev.consoleMsg.conn = connection;
235 dev.consoleMsg.dev = dev;
236 dev.controlMsg = function deviceControlMsg(msg) { if (typeof deviceControlMsg.conn == 'object') { deviceControlMsg.conn.ControlMsg(msg); } }
237 dev.controlMsg.conn = connection;
238 parent.debug('amt', "Start Management", nodeid, connType);
241 // Start the device manager in the task limiter so not to flood the server. Low priority task
242 obj.parent.taskLimiter.launch(function (dev, taskid, taskLimiterQueue) {
243 if (isAmtDeviceValid(dev)) {
244 // Start managing this device
246 fetchIntelAmtInformation(dev);
248 // Device is not valid anymore, do nothing
249 obj.parent.taskLimiter.completed(taskid);
254 // Stop Intel AMT management
255 obj.stopAmtManagement = function (nodeid, connType, connection) {
256 var devices = obj.amtDevices[nodeid], dev = null;
257 if (devices != null) { for (var i in devices) { if ((devices[i].mpsConnection == connection) || (devices[i].host == connection)) { dev = devices[i]; } } }
258 if (dev == null) return false; // We are not managing this device on this connection
259 parent.debug('amt', dev.name, "Stop Management", nodeid, connType);
260 return removeAmtDevice(dev, 1);
263 // Get a string status of the managed devices
264 obj.getStatusString = function () {
266 for (var nodeid in obj.amtDevices) {
267 var devices = obj.amtDevices[nodeid];
268 r += devices[0].nodeid + ', ' + devices[0].name + '\r\n';
269 for (var i in devices) {
270 var dev = devices[i];
272 if (dev.state == 1) { items.push('Connected'); } else { items.push('Trying'); }
273 items.push(ConnectionTypeStrings[dev.connType]);
274 if (dev.connType == 3) { items.push(dev.host); }
275 if (dev.polltimer != null) { items.push('Polling Power'); }
276 r += ' ' + items.join(', ') + '\r\n';
279 if (r == '') { r = "No managed Intel AMT devices"; }
283 // Receive a JSON control message from the MPS server
284 obj.mpsControlMessage = function (nodeid, conn, connType, jsondata) {
285 // Find the devices in the list
287 var devices = obj.amtDevices[nodeid];
288 if (devices == null) return;
289 for (var i in devices) { if (devices[i].mpsConnection === conn) { dev = devices[i]; } }
290 if (dev == null) return;
292 // Process the message
293 switch (jsondata.action) {
295 if ((dev.connType != 2) || (dev.deactivateCcmPending != 1)) break; // Only accept MEI state on CIRA-LMS connection
296 delete dev.deactivateCcmPending;
297 deactivateIntelAmtCCMEx(dev, jsondata.value);
300 if (dev.acmactivate == 1) {
301 // Continue ACM activation
302 dev.consoleMsg("Got new Intel AMT MEI state. Holding 40 seconds prior to ACM activation...");
303 delete dev.acmactivate;
304 var continueAcmFunc = function continueAcm() { if (isAmtDeviceValid(continueAcm.dev)) { activateIntelAmtAcmEx0(continueAcm.dev); } }
305 continueAcmFunc.dev = dev;
306 setTimeout(continueAcmFunc, 40000);
308 if (dev.pendingUpdatedMeiState != 1) break;
309 delete dev.pendingUpdatedMeiState;
310 attemptInitialContact(dev);
313 case 'startTlsHostConfig':
314 if (dev.acmTlsInfo == null) break;
315 if ((typeof jsondata.value != 'object') || (typeof jsondata.value.status != 'number')) {
316 removeAmtDevice(dev, 2); // Invalid startTlsHostConfig response
318 activateIntelAmtTlsAcmEx(dev, jsondata.value); // Start TLS activation.
321 case 'stopConfiguration':
322 if (dev.acmactivate != 1) break;
323 if (jsondata.value == 3) { delete dev.acmactivate; activateIntelAmtAcmEx0(dev); } // Intel AMT was already not in in-provisioning state, keep going right away.
324 else if (jsondata.value == 0) {
325 dev.consoleMsg("Cleared in-provisioning state. Holding 30 seconds prior to getting Intel AMT MEI state...");
326 var askStateFunc = function askState() { if (isAmtDeviceValid(askState.dev)) { askState.dev.controlMsg({ action: 'mestate' }); } }
327 askStateFunc.dev = dev;
328 setTimeout(askStateFunc, 30000);
330 else { dev.consoleMsg("Unknown stopConfiguration() state of " + jsondata.value + ". Continuing with ACM activation..."); delete dev.acmactivate; activateIntelAmtAcmEx0(dev); }
335 // Subscribe to server events
336 parent.AddEventDispatch(['*'], obj);
338 // Handle server events
339 // Make sure to only manage devices with connections to this server. In a multi-server setup, we don't want multiple managers talking to the same device.
340 obj.HandleEvent = function (source, event, ids, id) {
341 switch (event.action) {
342 case 'removenode': { // React to node being removed
343 if (event.noact == 1) return; // Take no action on these events. We are likely in peering mode and need to only act when the database signals the change in state.
344 removeDevice(event.nodeid);
347 case 'wakedevices': { // React to node wakeup command, perform Intel AMT wake if possible
348 if (event.noact == 1) return; // Take no action on these events. We are likely in peering mode and need to only act when the database signals the change in state.
349 if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performPowerAction(event.nodeids[i], 2); } }
352 case 'oneclickrecovery': { // React to Intel AMT One Click Recovery command
353 if (event.noact == 1) return; // Take no action on these events. We are likely in peering mode and need to only act when the database signals the change in state.
354 if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performOneClickRecoveryAction(event.nodeids[i], event.file); } }
357 case 'amtpoweraction': {
358 if (event.noact == 1) return; // Take no action on these events. We are likely in peering mode and need to only act when the database signals the change in state.
359 if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performPowerAction(event.nodeids[i], event.actiontype); } }
362 case 'changenode': { // React to changes in a device
363 var devices = obj.amtDevices[event.nodeid], rescan = false;
364 if (devices != null) {
365 for (var i in devices) {
366 var dev = devices[i];
367 dev.name = event.node.name;
368 dev.icon = event.node.icon;
369 dev.rname = event.node.rname;
371 // If there are any changes, apply them.
372 if (event.node.intelamt != null) {
373 if (dev.intelamt == null) { dev.intelamt = {}; }
374 if ((typeof event.node.intelamt.version == 'string') && (event.node.intelamt.version != dev.intelamt.ver)) { dev.intelamt.ver = event.node.intelamt.version; }
375 if ((typeof event.node.intelamt.user == 'string') && (event.node.intelamt.user != dev.intelamt.user)) { dev.intelamt.user = event.node.intelamt.user; }
376 if ((typeof event.node.intelamt.pass == 'string') && (event.node.intelamt.pass != dev.intelamt.pass)) { dev.intelamt.pass = event.node.intelamt.pass; }
377 if ((typeof event.node.intelamt.mpspass == 'string') && (event.node.intelamt.mpspass != dev.intelamt.mpspass)) { dev.intelamt.mpspass = event.node.intelamt.mpspass; }
378 if ((typeof event.node.intelamt.host == 'string') && (event.node.intelamt.host != dev.intelamt.host)) { dev.intelamt.host = event.node.intelamt.host; }
379 if ((typeof event.node.intelamt.realm == 'string') && (event.node.intelamt.realm != dev.intelamt.realm)) { dev.intelamt.realm = event.node.intelamt.realm; }
380 if ((typeof event.node.intelamt.hash == 'string') && (event.node.intelamt.hash != dev.intelamt.hash)) { dev.intelamt.hash = event.node.intelamt.hash; }
381 if ((typeof event.node.intelamt.tls == 'number') && (event.node.intelamt.tls != dev.intelamt.tls)) { dev.intelamt.tls = event.node.intelamt.tls; }
382 if ((typeof event.node.intelamt.state == 'number') && (event.node.intelamt.state != dev.intelamt.state)) { dev.intelamt.state = event.node.intelamt.state; }
385 if ((dev.connType == 3) && (dev.host != event.node.host)) {
386 dev.host = event.node.host; // The host has changed, if we are connected to this device locally, we need to reset.
387 removeAmtDevice(dev, 3); // We are going to wait for the AMT scanned to find this device again.
392 // If this event provides a hint that something changed with AMT and we are not managing this device, let's rescan the local network now.
393 if (event.amtchange == 1) { rescan = true; }
396 // If there is a significant change to the device AMT settings and this server manages local devices, perform a re-scan of the device now.
397 if (rescan && (parent.amtScanner != null)) { parent.amtScanner.performSpecificScan(event.node); }
403 // TODO: If a device changes to a device group that does not have a 802.1x policy, we may need to tell MeshCentral Satellite to remove the 802.1x profile.
407 case 'satelliteResponse': {
408 if ((typeof event.nodeid != 'string') || (typeof event.reqid != 'string') || (event.satelliteFlags != 2)) return;
409 var devices = obj.amtDevices[event.nodeid], devFound = null;
410 if (devices != null) { for (var i in devices) { if (devices[i].netAuthSatReqId == event.reqid) { devFound = devices[i]; } } }
411 if (devFound == null) return; // Unable to find a device for this 802.1x profile
412 switch (event.subaction) {
413 case '802.1x-KeyPair-Request': {
414 // 802.1x request for public/private key pair be generated
415 attempt8021xKeyGeneration(devFound);
418 case '802.1x-CSR-Request': {
419 // 802.1x request for a Certificate Signing Request
420 attempt8021xCRSRequest(devFound, event);
423 case '802.1x-Profile-Completed': {
424 // The 802.1x profile request is done, set it in Intel AMT.
425 if (devFound.netAuthSatReqTimer != null) { clearTimeout(devFound.netAuthSatReqTimer); delete devFound.netAuthSatReqTimer; }
427 if ((event.response == null) || (typeof event.response != 'object')) {
428 // Unable to create a 802.1x profile
429 delete devFound.netAuthSatReqId;
430 if (isAmtDeviceValid(devFound) == false) return; // Device no longer exists, ignore this request.
431 delete devFound.netAuthSatReqData;
432 devFound.consoleMsg("MeshCentral Satellite could not create a 802.1x profile for this device.");
433 devTaskCompleted(devFound);
437 if (typeof event.response.authProtocol != 'number') { delete devFound.netAuthSatReqId; break; }
439 // We got a new 802.1x profile
440 devFound.netAuthCredentials = event.response;
441 perform8021xRootCertCheck(devFound);
452 // Intel AMT Connection Setup
455 // Update information about a device
456 function fetchIntelAmtInformation(dev) {
457 parent.db.Get(dev.nodeid, function (err, nodes) {
458 if ((nodes == null) || (nodes.length != 1)) { removeAmtDevice(dev, 4); return; }
459 const node = nodes[0];
460 if ((node.intelamt == null) || (node.meshid == null)) { removeAmtDevice(dev, 5); return; }
461 const mesh = parent.webserver.meshes[node.meshid];
462 if (mesh == null) { removeAmtDevice(dev, 6); return; }
463 if (dev == null) { return; }
465 // Fetch Intel AMT setup policy
466 // mesh.amt.type: 0 = No Policy, 1 = Deactivate CCM, 2 = Manage in CCM, 3 = Manage in ACM
467 // mesh.amt.cirasetup: 0 = No Change, 1 = Remove CIRA, 2 = Setup CIRA
468 var amtPolicy = 0, ciraPolicy = 0, badPass = 0, password = null;
469 if (mesh.amt != null) {
470 if (mesh.amt.type) { amtPolicy = mesh.amt.type; }
471 if (mesh.amt.type == 4) {
472 // Fully automatic policy
473 ciraPolicy = 2; // CIRA will be setup
474 badPass = 1; // Automatically re-active CCM
475 password = null; // Randomize the password.
477 if (mesh.amt.cirasetup) { ciraPolicy = mesh.amt.cirasetup; }
478 if (mesh.amt.badpass) { badPass = mesh.amt.badpass; }
479 if ((typeof mesh.amt.password == 'string') && (mesh.amt.password != '')) { password = mesh.amt.password; }
482 if (amtPolicy == 0) { ciraPolicy = 0; } // If no policy, don't change CIRA state.
483 if (amtPolicy == 1) { ciraPolicy = 1; } // If deactivation policy, clear CIRA.
484 dev.policy = { amtPolicy: amtPolicy, ciraPolicy: ciraPolicy, badPass: badPass, password: password };
486 // Setup the monitored device
487 dev.name = node.name;
488 dev.rname = node.rname;
489 dev.icon = node.icon;
490 dev.meshid = node.meshid;
491 dev.intelamt = node.intelamt;
493 // Check if the status of Intel AMT sent by the agents matched what we have in the database
494 if ((dev.connType == 2) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null)) {
496 if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
497 dev.host = dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
499 if (typeof dev.mpsConnection.tag.meiState['ProvisioningState'] == 'number') {
500 dev.intelamt.state = dev.aquired.state = dev.mpsConnection.tag.meiState['ProvisioningState'];
502 if ((typeof dev.mpsConnection.tag.meiState['Versions'] == 'object') && (typeof dev.mpsConnection.tag.meiState['Versions']['AMT'] == 'string')) {
503 dev.intelamt.ver = dev.aquired.version = dev.mpsConnection.tag.meiState['Versions']['AMT'];
505 if (typeof dev.mpsConnection.tag.meiState['Flags'] == 'number') {
506 const flags = dev.intelamt.flags = dev.mpsConnection.tag.meiState['Flags'];
507 if (flags & 2) { dev.aquired.controlMode = 1; } // CCM
508 if (flags & 4) { dev.aquired.controlMode = 2; } // ACM
513 // If there is no Intel AMT policy for this device, stop here.
514 //if (amtPolicy == 0) { dev.consoleMsg("Done."); removeAmtDevice(dev, 7); return; }
516 // Initiate the communication to Intel AMT
517 dev.consoleMsg("Checking Intel AMT state...");
518 attemptInitialContact(dev);
522 // Attempt to perform initial contact with Intel AMT
523 function attemptInitialContact(dev) {
524 // If there is a WSMAN stack setup, clean it up now.
525 if (dev.amtstack != null) {
526 dev.amtstack.CancelAllQueries(999);
527 delete dev.amtstack.dev;
532 parent.debug('amt', dev.name, "Attempt Initial Contact", ["CIRA", "CIRA-Relay", "CIRA-LMS", "Local"][dev.connType]);
534 // Check Intel AMT policy when CIRA-LMS connection is in use.
535 if ((dev.connType == 2) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null)) {
536 // Intel AMT activation policy
537 if ((dev.policy.amtPolicy > 1) && (dev.mpsConnection.tag.meiState.ProvisioningState !== 2)) {
538 // This Intel AMT device is not activated, we need to work on activating it.
539 activateIntelAmt(dev);
542 // Check if we have an ACM activation policy, but the device is in CCM
543 if (((dev.policy.amtPolicy == 3) || (dev.policy.amtPolicy == 4)) && (dev.mpsConnection.tag.meiState.ProvisioningState == 2) && ((dev.mpsConnection.tag.meiState.Flags & 2) != 0)) {
544 // This device in is CCM, check if we can upgrade to ACM
545 if (activateIntelAmt(dev) == false) return; // If this return true, the platform is in CCM and can't go to ACM, keep going with management.
547 // Intel AMT CCM deactivation policy
548 if (dev.policy.amtPolicy == 1) {
549 if ((dev.mpsConnection.tag.meiState.ProvisioningState == 2) && ((dev.mpsConnection.tag.meiState.Flags & 2) != 0)) {
551 deactivateIntelAmtCCM(dev);
557 // See what username/password we need to try
558 // We create an efficient strategy for trying different Intel AMT passwords.
559 if (dev.acctry == null) {
562 // Add Intel AMT username and password provided by MeshCMD if available
563 if ((dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (typeof dev.mpsConnection.tag.meiState.amtuser == 'string') && (typeof dev.mpsConnection.tag.meiState.amtpass == 'string') && (dev.mpsConnection.tag.meiState.amtuser != '') && (dev.mpsConnection.tag.meiState.amtpass != '')) {
564 dev.acctry.push([dev.mpsConnection.tag.meiState.amtuser, dev.mpsConnection.tag.meiState.amtpass]);
567 // Add the know Intel AMT password for this device if available
568 if ((typeof dev.intelamt.user == 'string') && (typeof dev.intelamt.pass == 'string') && (dev.intelamt.user != '') && (dev.intelamt.pass != '')) { dev.acctry.push([dev.intelamt.user, dev.intelamt.pass]); }
570 // Add the policy password as an alternative
571 if ((typeof dev.policy.password == 'string') && (dev.policy.password != '')) { dev.acctry.push(['admin', dev.policy.password]); }
573 // Add any configured admin account as alternatives
574 if (obj.amtAdminAccounts[dev.domainid] != null) { for (var i in obj.amtAdminAccounts[dev.domainid]) { dev.acctry.push([obj.amtAdminAccounts[dev.domainid][i].user, obj.amtAdminAccounts[dev.domainid][i].pass]); } }
576 // Add any previous passwords for the device UUID as alternative
577 if ((parent.amtPasswords != null) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (dev.mpsConnection.tag.meiState.UUID != null) && (parent.amtPasswords[dev.mpsConnection.tag.meiState.UUID] != null)) {
578 for (var i in parent.amtPasswords[dev.mpsConnection.tag.meiState.UUID]) {
579 dev.acctry.push(['admin', parent.amtPasswords[dev.mpsConnection.tag.meiState.UUID][i]]);
583 // Remove any duplicates user/passwords
585 for (var i = 0; i < dev.acctry.length; i++) {
587 for (var j = 0; j < acctry2.length; j++) { if ((dev.acctry[i][0] == acctry2[j][0]) && (dev.acctry[i][1] == acctry2[j][1])) { found = true; } }
588 if (found == false) { acctry2.push(dev.acctry[i]); }
590 dev.acctry = acctry2;
592 // If we have passwords to try, try the first one now.
593 if (dev.acctry.length == 0) {
594 dev.consoleMsg("No admin login passwords to try, stopping now.");
595 removeAmtDevice(dev, 8);
600 if ((dev.acctry == null) || (dev.acctry.length == 0)) { removeAmtDevice(dev, 9); return; } // No Intel AMT credentials to try
601 var user = dev.acctry[0][0], pass = dev.acctry[0][1]; // Try the first user/pass in the list
603 switch (dev.connType) {
605 // Handle the case where the Intel AMT CIRA is connected (connType 0)
606 // In this connection type, we look at the port bindings to see if we need to do TLS or not.
608 // Check to see if CIRA is connected on this server.
609 var ciraconn = dev.mpsConnection;
610 if ((ciraconn == null) || (ciraconn.tag == null) || (ciraconn.tag.boundPorts == null)) { removeAmtDevice(dev, 9); return; } // CIRA connection is not on this server, no need to deal with this device anymore.
612 // See if we need to perform TLS or not. We prefer not to do TLS within CIRA.
614 if (ciraconn.tag.boundPorts.indexOf('16992')) { dotls = 0; }
615 else if (ciraconn.tag.boundPorts.indexOf('16993')) { dotls = 1; }
616 if (dotls == -1) { removeAmtDevice(dev, 10); return; } // The Intel AMT ports are not open, not a device we can deal with.
619 parent.debug('amt', dev.name, 'CIRA-Connect', (dotls == 1) ? "TLS" : "NoTLS", user, pass);
622 comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
623 comm.xtlsFingerprint = 0; // Perform no certificate checking
625 comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, ciraconn); // No TLS
627 var wsstack = WsmanStackCreateService(comm);
628 dev.amtstack = AmtStackCreateService(wsstack);
629 dev.amtstack.dev = dev;
630 dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
632 case 1: // CIRA-Relay
634 // Handle the case where the Intel AMT relay or LMS is connected (connType 1 or 2)
635 // Check to see if CIRA is connected on this server.
636 var ciraconn = dev.mpsConnection;
637 if ((ciraconn == null) || (ciraconn.tag == null) || (ciraconn.tag.boundPorts == null)) { removeAmtDevice(dev, 11); return; } // Relay connection not valid
641 if ((dev.tlsfail !== true) && (parent.config.domains[dev.domainid].amtmanager.tlsconnections !== false) && (dev.intelamt.tls == 1)) {
642 parent.debug('amt', dev.name, (dev.connType == 1) ? 'Relay-Connect' : 'LMS-Connect', "TLS", user);
643 comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
644 comm.xtlsFingerprint = 0; // Perform no certificate checking
646 parent.debug('amt', dev.name, (dev.connType == 1) ? 'Relay-Connect' : 'LMS-Connect', "NoTLS", user);
647 comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, ciraconn); // No TLS
649 var wsstack = WsmanStackCreateService(comm);
650 dev.amtstack = AmtStackCreateService(wsstack);
651 dev.amtstack.dev = dev;
652 dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
655 // Check if Intel AMT is activated. If not, stop here.
656 if ((dev.intelamt == null) || ((dev.intelamt.state != null) && (dev.intelamt.state != 2))) { removeAmtDevice(dev, 12); return; }
658 // Handle the case where the Intel AMT local scanner found the device (connType 3)
659 parent.debug('amt', dev.name, "Attempt Initial Local Contact", dev.connType, dev.host);
660 if (typeof dev.host != 'string') { removeAmtDevice(dev, 13); return; } // Local connection not valid
662 // Since we don't allow two or more connections to the same host, check if a pending connection is active.
663 if (obj.activeLocalConnections[dev.host] != null) {
664 // Active connection, hold and try later.
665 var tryAgainFunc = function tryAgainFunc() { if (obj.amtDevices[tryAgainFunc.dev.nodeid] != null) { attemptInitialContact(tryAgainFunc.dev); } }
666 tryAgainFunc.dev = dev;
667 setTimeout(tryAgainFunc, 5000);
669 // No active connections
673 if ((dev.tlsfail !== true) && (parent.config.domains[dev.domainid].amtmanager.tlsconnections !== false) && (dev.intelamt.tls == 1)) {
674 parent.debug('amt', dev.name, 'Direct-Connect', "TLS", dev.host, user);
675 comm = CreateWsmanComm(dev.host, 16993, user, pass, 1); // Always try with TLS first
676 comm.xtlsFingerprint = 0; // Perform no certificate checking
678 parent.debug('amt', dev.name, 'Direct-Connect', "NoTLS", dev.host, user);
679 comm = CreateWsmanComm(dev.host, 16992, user, pass, 0); // Try without TLS
681 var wsstack = WsmanStackCreateService(comm);
682 dev.amtstack = AmtStackCreateService(wsstack);
683 dev.amtstack.dev = dev;
684 obj.activeLocalConnections[dev.host] = dev;
685 dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
691 function attemptLocalConnectResponse(stack, name, responses, status) {
692 const dev = stack.dev;
693 parent.debug('amt', dev.name, "Initial Contact Response", status);
695 // If this is a local connection device, release active connection to this host.
696 if (dev.connType == 3) { delete obj.activeLocalConnections[dev.host]; }
698 // Check if the device still exists
699 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
701 // Check the response
702 if ((status == 200) && (responses['AMT_GeneralSettings'] != null) && (responses['IPS_HostBasedSetupService'] != null) && (responses['IPS_HostBasedSetupService'].response != null) && (responses['IPS_HostBasedSetupService'].response != null) && (stack.wsman.comm.digestRealm == responses['AMT_GeneralSettings'].response.DigestRealm)) {
703 // Everything looks good
704 dev.consoleMsg(stack.wsman.comm.xtls ? "Intel AMT connected with TLS." : "Intel AMT connected.");
706 if (dev.aquired == null) { dev.aquired = {}; }
707 dev.aquired.controlMode = responses['IPS_HostBasedSetupService'].response.CurrentControlMode; // 1 = CCM, 2 = ACM
708 if (typeof stack.wsman.comm.amtVersion == 'string') { // Set the Intel AMT version using the HTTP header if present
709 var verSplit = stack.wsman.comm.amtVersion.split('.');
710 if (verSplit.length >= 2) {
711 dev.aquired.version = verSplit[0] + '.' + verSplit[1];
712 dev.aquired.majorver = parseInt(verSplit[0]);
713 dev.aquired.minorver = parseInt(verSplit[1]);
714 if (verSplit.length >= 3) {
715 dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
716 dev.aquired.maintenancever = parseInt(verSplit[2]);
720 dev.aquired.realm = stack.wsman.comm.digestRealm;
721 dev.aquired.user = dev.intelamt.user = stack.wsman.comm.user;
722 dev.aquired.pass = dev.intelamt.pass = stack.wsman.comm.pass;
723 dev.aquired.lastContact = Date.now();
724 dev.aquired.warn = 0; // Clear all warnings (TODO: Check Realm and TLS cert pinning)
725 if ((dev.connType == 1) || (dev.connType == 3)) { dev.aquired.tls = stack.wsman.comm.xtls; } // Only set the TLS state if in relay or local mode. When using CIRA, this is auto-detected.
726 if (stack.wsman.comm.xtls == 1) { dev.aquired.hash = stack.wsman.comm.xtlsCertificate.fingerprint.split(':').join('').toLowerCase(); } else { delete dev.aquired.hash; }
729 // If this is the new first user/pass for the device UUID, update the activation log now.
730 if ((parent.amtPasswords != null) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (dev.mpsConnection.tag.meiState.UUID != null) && (parent.amtPasswords[dev.mpsConnection.tag.meiState.UUID] != null) && (parent.amtPasswords[dev.mpsConnection.tag.meiState.UUID][0] != dev.aquired.pass)) {
731 parent.certificateOperations.logAmtActivation(parent.config.domains[dev.domainid], { time: new Date(), action: 'amtpassword', domain: dev.domainid, amtUuid: dev.mpsConnection.tag.meiState.UUID, amtRealm: dev.aquired.realm, user: dev.aquired.user, password: dev.aquired.pass, computerName: dev.name });
734 // Perform Intel AMT clock sync
735 attemptSyncClock(dev, function (dev) {
736 // Check Intel AMT TLS state
737 attemptTlsSync(dev, function (dev) {
738 // If we need to switch to TLS, do it now.
739 if (dev.switchToTls == 1) { delete dev.switchToTls; attemptInitialContact(dev); return; }
740 // Check Intel AMT 802.1x wired state and Intel AMT WIFI state (must be done both at once).
741 attemptWifiSync(dev, function (dev) {
742 // Check Intel AMT root certificate state
743 attemptRootCertSync(dev, function (dev) {
744 // Check Intel AMT CIRA settings
745 attemptCiraSync(dev, function (dev) {
746 // Check Intel AMT settings
747 attemptSettingsSync(dev, function (dev) {
748 // Clean unused certificates
749 attemptCleanCertsSync(dev, function (dev) {
750 // See if we need to get hardware inventory
751 attemptFetchHardwareInventory(dev, function (dev) {
752 dev.consoleMsg('Done.');
754 // Remove from task limiter if needed
755 if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
757 if (dev.connType != 2) {
758 // Start power polling if not connected to LMS
759 var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); }
761 if(dev.polltimer){ clearInterval(dev.polltimer); delete dev.polltimer; }
762 dev.polltimer = new setInterval(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
763 fetchPowerState(dev);
765 // For LMS connections, close now.
766 dev.controlMsg({ action: 'close' });
777 // We got a bad response
778 if ((dev.connType != 0) && (dev.tlsfail !== false) && (status == 408)) { // If not using CIRA and we get a 408 error while using non-TLS, try TLS.
779 // non-TLS error on a local connection, try again with TLS
780 dev.tlsfail = false; dev.intelamt.tls = 1; attemptInitialContact(dev); return;
781 } else if ((dev.connType != 0) && (dev.tlsfail !== true) && (status == 408)) { // If not using CIRA and we get a 408 error while using TLS, try non-TLS.
782 // TLS error on a local connection, try again without TLS
783 dev.tlsfail = true; dev.intelamt.tls = 0; attemptInitialContact(dev); return;
784 } else if (status == 401) {
785 // Authentication error, see if we can use alternative credentials
786 if (dev.acctry != null) {
787 // Remove the first password from the trial list since it did not work.
788 if (dev.acctry.length > 0) { dev.acctry.shift(); }
790 // We have another password to try, hold 20 second and try the next user/password.
791 if (dev.acctry.length > 0) {
792 dev.consoleMsg("Holding 20 seconds and trying again with different credentials...");
793 setTimeout(function () { if (isAmtDeviceValid(dev)) { attemptInitialContact(dev); } }, 20000); return;
797 // If this device is in CCM mode and we have a bad password reset policy, do it now.
798 if ((dev.connType == 2) && (dev.policy.badPass == 1) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (dev.mpsConnection.tag.meiState.Flags != null) && ((dev.mpsConnection.tag.meiState.Flags & 2) != 0)) {
799 deactivateIntelAmtCCM(dev);
803 // We are unable to authenticate to this device
804 dev.consoleMsg("Unable to connect.");
806 // Set an error that we can't login to this device
807 if (dev.aquired == null) { dev.aquired = {}; }
808 dev.aquired.warn = 1; // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch, 8 = Trying credentials
811 //console.log(dev.nodeid, dev.name, dev.host, status, 'Bad response');
812 removeAmtDevice(dev, 14);
818 // Intel AMT Database Update
821 // Change the current core information string and event it
822 function UpdateDevice(dev) {
823 // Check that the mesh exists
824 const mesh = parent.webserver.meshes[dev.meshid];
825 if (mesh == null) { removeAmtDevice(dev, 15); return false; }
827 // Get the node and change it if needed
828 parent.db.Get(dev.nodeid, function (err, nodes) {
829 if ((nodes == null) || (nodes.length != 1)) return false;
830 const device = nodes[0];
831 var changes = [], change = 0, log = 0;
832 var domain = parent.config.domains[device.domain];
833 if (domain == null) return false;
835 // Check if anything changes
836 if (device.intelamt == null) { device.intelamt = {}; }
837 if ((typeof dev.aquired.version == 'string') && (dev.aquired.version != device.intelamt.ver)) { change = 1; log = 1; device.intelamt.ver = dev.aquired.version; changes.push('AMT version'); }
838 if ((typeof dev.aquired.user == 'string') && (dev.aquired.user != device.intelamt.user)) { change = 1; log = 1; device.intelamt.user = dev.aquired.user; changes.push('AMT user'); }
839 if ((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'); }
840 if ((typeof dev.aquired.mpspass == 'string') && (dev.aquired.mpspass != device.intelamt.mpspass)) { change = 1; log = 1; device.intelamt.mpspass = dev.aquired.mpspass; changes.push('AMT MPS pass'); }
841 if ((typeof dev.aquired.host == 'string') && (dev.aquired.host != device.intelamt.host)) { change = 1; log = 1; device.intelamt.host = dev.aquired.host; changes.push('AMT host'); }
842 if ((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'); }
843 if ((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'); }
844 if ((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');*/ }
845 if ((typeof dev.aquired.state == 'number') && (dev.aquired.state != device.intelamt.state)) { change = 1; log = 1; device.intelamt.state = dev.aquired.state; changes.push('AMT state'); }
847 // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch, 8 = Trying credentials
848 if ((typeof dev.aquired.warn == 'number')) {
849 if ((dev.aquired.warn == 0) && (device.intelamt.warn != null)) { delete device.intelamt.warn; change = 1; }
850 else if ((dev.aquired.warn != 0) && (dev.aquired.warn != device.intelamt.warn)) { device.intelamt.warn = dev.aquired.warn; change = 1; }
853 // Update Intel AMT flags if needed
854 // dev.aquired.controlMode // 1 = CCM, 2 = ACM
855 // (node.intelamt.flags & 2) == CCM, (node.intelamt.flags & 4) == ACM
857 if (typeof device.intelamt.flags == 'number') { flags = device.intelamt.flags; }
858 if (dev.aquired.controlMode == 1) { if ((flags & 4) != 0) { flags -= 4; } if ((flags & 2) == 0) { flags += 2; } } // CCM
859 if (dev.aquired.controlMode == 2) { if ((flags & 4) == 0) { flags += 4; } if ((flags & 2) != 0) { flags -= 2; } } // ACM
860 if (device.intelamt.flags != flags) { change = 1; log = 1; device.intelamt.flags = flags; changes.push('AMT flags'); }
862 // If there are changes, event the new device
864 // Save to the database
865 parent.db.Set(device);
867 // Event the node change
868 var event = { etype: 'node', action: 'changenode', nodeid: device._id, domain: domain.id, node: parent.webserver.CloneSafeNode(device) };
869 if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
870 if ((log == 0) || ((obj.agentInfo) && (obj.agentInfo.capabilities) && (obj.agentInfo.capabilities & 0x20)) || (changes.length == 0)) { event.nolog = 1; } // If this is a temporary device, don't log changes
871 if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
872 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(device.meshid, [device._id]), obj, event);
877 // Change the current core information string and event it
878 function ClearDeviceCredentials(dev) {
879 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
881 // Check that the mesh exists
882 const mesh = parent.webserver.meshes[dev.meshid];
883 if (mesh == null) { removeAmtDevice(dev, 16); return; }
885 // Get the node and change it if needed
886 parent.db.Get(dev.nodeid, function (err, nodes) {
887 if ((nodes == null) || (nodes.length != 1)) return;
888 const device = nodes[0];
889 var changes = [], change = 0, log = 0;
890 var domain = parent.config.domains[device.domain];
891 if (domain == null) return;
893 // Check if anything changes
894 if (device.intelamt == null) return;
895 if (device.intelamt.user != null) { change = 1; log = 1; delete device.intelamt.user; changes.push('AMT user'); }
896 if (device.intelamt.pass != null) { change = 1; log = 1; delete device.intelamt.pass; changes.push('AMT pass'); }
898 // If there are changes, event the new device
900 // Save to the database
901 parent.db.Set(device);
903 // Event the node change
904 var event = { etype: 'node', action: 'changenode', nodeid: device._id, domain: domain.id, node: parent.webserver.CloneSafeNode(device) };
905 if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
906 if ((log == 0) || ((obj.agentInfo) && (obj.agentInfo.capabilities) && (obj.agentInfo.capabilities & 0x20)) || (changes.length == 0)) { event.nolog = 1; } // If this is a temporary device, don't log changes
907 if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
908 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(device.meshid, [device._id]), obj, event);
915 // Intel AMT Power State
918 // Get the current power state of a device
919 function fetchPowerState(dev) {
920 if (isAmtDeviceValid(dev) == false) return;
922 // Check if the agent is connected
923 var constate = parent.GetConnectivityState(dev.nodeid);
924 if ((constate == null) || (constate.connectivity & 1)) return; // If there is no connectivity or the agent is connected, skip trying to poll power state.
926 // Fetch the power state
927 dev.amtstack.BatchEnum(null, ['CIM_ServiceAvailableToElement'], function (stack, name, responses, status) {
928 const dev = stack.dev;
929 if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
931 if ((status != 200) || (responses['CIM_ServiceAvailableToElement'] == null) || (responses['CIM_ServiceAvailableToElement'].responses == null) || (responses['CIM_ServiceAvailableToElement'].responses.length < 1)) return; // If the polling fails, just skip it.
932 var powerstate = responses['CIM_ServiceAvailableToElement'].responses[0].PowerState;
933 if ((powerstate == 2) && (dev.aquired.majorver != null) && (dev.aquired.majorver > 9)) {
934 // Device is powered on and Intel AMT 10+, poll the OS power state.
935 dev.amtstack.Get('IPS_PowerManagementService', function (stack, name, response, status) {
936 const dev = stack.dev;
937 if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
938 if (status != 200) return;
940 // Convert the OS power state
941 var meshPowerState = -1;
942 if (response.Body.OSPowerSavingState == 2) { meshPowerState = 1; } // Fully powered (S0);
943 else if (response.Body.OSPowerSavingState == 3) { meshPowerState = 2; } // Modern standby (We are going to call this S1);
945 // Set OS power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
946 if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); }
949 // Convert the power state
950 // AMT power: 1 = Other, 2 = On, 3 = Sleep-Light, 4 = Sleep-Deep, 5 = Power Cycle (Off-Soft), 6 = Off-Hard, 7 = Hibernate (Off-Soft), 8 = Off-Soft, 9 = Power Cycle (Off-Hard), 10 = Master Bus Reset, 11 = Diagnostic Interrupt (NMI), 12 = Off-Soft Graceful, 13 = Off-Hard Graceful, 14 = Master Bus Reset Graceful, 15 = Power Cycle (Off- oft Graceful), 16 = Power Cycle (Off - Hard Graceful), 17 = Diagnostic Interrupt (INIT)
951 // Mesh power: 0 = Unknown, 1 = S0 power on, 2 = S1 Sleep, 3 = S2 Sleep, 4 = S3 Sleep, 5 = S4 Hibernate, 6 = S5 Soft-Off, 7 = Present
952 var meshPowerState = -1, powerConversionTable = [-1, -1, 1, 2, 3, 6, 6, 5, 6];
953 if (powerstate < powerConversionTable.length) { meshPowerState = powerConversionTable[powerstate]; } else { powerstate = 6; }
955 // Set power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
956 if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); }
961 // Perform a power action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE
962 function performPowerAction(nodeid, action) {
963 console.log('performPowerAction', nodeid, action);
964 var devices = obj.amtDevices[nodeid];
965 if (devices == null) return;
966 for (var i in devices) {
967 var dev = devices[i];
968 // If not LMS, has a AMT stack present and is in connected state, perform power operation.
969 if ((dev.connType != 2) && (dev.state == 1) && (dev.amtstack != null)) {
970 parent.debug('amt', dev.name, "performPowerAction", action);
971 dev.powerAction = action;
973 // Action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset
974 try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { }
976 // 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE
977 dev.amtstack.BatchEnum(null, ['*AMT_BootSettingData'], performAdvancedPowerActionResponse);
983 // Response to Intel AMT advanced power action
984 function performAdvancedPowerActionResponse(stack, name, responses, status) {
985 const dev = stack.dev;
986 const action = dev.powerAction;
987 delete dev.powerAction;
988 if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
989 if (status != 200) return;
990 if ((responses['AMT_BootSettingData'] == null) || (responses['AMT_BootSettingData'].response == null)) return;
991 var bootSettingData = responses['AMT_BootSettingData'].response;
993 // Clean up parameters
994 bootSettingData['ConfigurationDataReset'] = false;
995 delete bootSettingData['WinREBootEnabled'];
996 delete bootSettingData['UEFILocalPBABootEnabled'];
997 delete bootSettingData['UEFIHTTPSBootEnabled'];
998 delete bootSettingData['SecureBootControlEnabled'];
999 delete bootSettingData['BootguardStatus'];
1000 delete bootSettingData['OptionsCleared'];
1001 delete bootSettingData['BIOSLastStatus'];
1002 delete bootSettingData['UefiBootParametersArray'];
1003 delete bootSettingData['RPEEnabled'];
1004 delete bootSettingData['RSEPassword']
1006 // Ready boot parameters
1007 bootSettingData['BIOSSetup'] = ((action >= 11) && (action <= 14));
1008 bootSettingData['UseSOL'] = ((action >= 13) && (action <= 14));
1009 if ((action == 11) || (action == 13) || (action == 15)) { dev.powerAction = 2; } // Power on
1010 if ((action == 12) || (action == 14) || (action == 16)) { dev.powerAction = 10; } // Reset
1012 // Set boot parameters
1013 dev.amtstack.Put('AMT_BootSettingData', bootSettingData, function (stack, name, response, status, tag) {
1014 const dev = stack.dev;
1015 if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
1017 dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status, tag) {
1018 const dev = stack.dev;
1019 if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
1021 var bootDevice = (action === 15 || action === 16) ? '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: Force PXE Boot</Selector></SelectorSet></ReferenceParameters>' : null;
1022 dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(bootDevice, function (stack, name, response, status) {
1023 const dev = stack.dev;
1024 if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
1025 // Perform power action
1026 try { dev.amtstack.RequestPowerStateChange(dev.powerAction, performPowerActionResponse); } catch (ex) { }
1032 // Response to Intel AMT power action
1033 function performPowerActionResponse(stack, name, responses, status) {
1034 const dev = stack.dev;
1035 const action = dev.powerAction;
1036 delete dev.powerAction;
1037 if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
1038 if (status != 200) return;
1040 // If this is Intel AMT 10 or higher and we are trying to wake the device, send an OS wake.
1041 // This will wake the device from "Modern Standby".
1042 if ((action == 2) && (dev.aquired.majorver > 9)) {
1043 try { dev.amtstack.RequestOSPowerStateChange(2, function (stack, name, response, status) { }); } catch (ex) { }
1049 // Intel AMT One Click Recovery
1052 // Perform Intel AMT One Click Recovery on a device
1053 function performOneClickRecoveryAction(nodeid, file) {
1054 var devices = obj.amtDevices[nodeid];
1055 if (devices == null) return;
1056 for (var i in devices) {
1057 var dev = devices[i];
1058 // If not LMS, has a AMT stack present and is in connected state, perform operation.
1059 if ((dev.connType != 2) && (dev.state == 1) && (dev.amtstack != null)) {
1060 // Make sure the MPS server root certificate is present.
1061 // Start by looking at existing certificates.
1063 dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', '*AMT_BootCapabilities'], performOneClickRecoveryActionEx);
1068 // Response with list of certificates in Intel AMT
1069 function performOneClickRecoveryActionEx(stack, name, responses, status) {
1070 const dev = stack.dev;
1071 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1072 if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); delete dev.ocrfile; return; }
1074 // Check if this Intel AMT device supports OCR
1075 if (responses['AMT_BootCapabilities'].response['ForceUEFIHTTPSBoot'] !== true) {
1076 dev.consoleMsg("This Intel AMT device does not support UEFI HTTPS boot (" + status + ")."); delete dev.ocrfile; return;
1079 // Organize the certificates and add the MPS root cert if missing
1080 var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
1081 for (var i in xxCertificates) {
1082 xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
1083 xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
1084 xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
1085 xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
1087 dev.policy.certificates = xxCertificates;
1088 attemptRootCertSync(dev, performOneClickRecoveryActionEx2, true);
1091 // MPS root certificate was added
1092 function performOneClickRecoveryActionEx2(dev) {
1093 // Ask for Boot Settings Data
1094 dev.amtstack.Get('AMT_BootSettingData', performOneClickRecoveryActionEx3, 0, 1);
1097 // Getting Intel AMT Boot Settings Data
1098 function performOneClickRecoveryActionEx3(stack, name, response, status) {
1099 const dev = stack.dev;
1100 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1101 if (status != 200) { dev.consoleMsg("Failed to get boot settings data (" + status + ")."); delete dev.ocrfile; return; }
1103 // Generate the one-time URL.
1104 var cookie = obj.parent.encodeCookie({ a: 'f', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey)
1105 var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.efi';
1108 // Generate the boot data for OCR with URL
1109 var r = response.Body;
1110 r['BIOSPause'] = false;
1111 r['BIOSSetup'] = false;
1112 r['EnforceSecureBoot'] = false;
1113 r['UefiBootParametersArray'] = Buffer.from(makeUefiBootParam(1, url) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2), 'binary').toString('base64');
1114 r['UefiBootNumberOfParams'] = 3;
1115 r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
1117 // Set the boot order to null, this is needed for some Intel AMT versions that don't clear this automatically.
1118 dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(null, function (stack, name, response, status) {
1119 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1120 if (status != 200) { dev.consoleMsg("Failed to set boot order (" + status + ")."); return; }
1121 dev.amtstack.Put('AMT_BootSettingData', r, performOneClickRecoveryActionEx4, 0, 1);
1125 // Intel AMT Put Boot Settings
1126 function performOneClickRecoveryActionEx4(stack, name, response, status) {
1127 const dev = stack.dev;
1128 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1129 if (status != 200) { dev.consoleMsg("Failed to set boot settings data (" + status + ")."); return; }
1130 dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status) {
1131 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1132 if (status != 200) { dev.consoleMsg("Failed to set boot config role (" + status + ")."); return; }
1133 dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder('<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: Force OCR UEFI HTTPS Boot</Selector></SelectorSet></ReferenceParameters>', function (stack, name, response, status) {
1134 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1135 if (status != 200) { dev.consoleMsg("Failed to set boot config (" + status + ")."); return; }
1136 dev.amtstack.RequestPowerStateChange(10, function (stack, name, response, status) { // 10 = Reset, 2 = Power Up
1137 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1138 if (status != 200) { dev.consoleMsg("Failed to perform power action (" + status + ")."); return; }
1139 console.log('One Click Recovery Completed.');
1147 // Intel AMT Clock Syncronization
1150 // Attempt to sync the Intel AMT clock if needed, call func back when done.
1151 // Care should be take not to have many pending WSMAN called when performing clock sync.
1152 function attemptSyncClock(dev, func) {
1153 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1154 if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
1156 dev.taskCompleted = func;
1157 dev.amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(attemptSyncClockEx);
1160 // Intel AMT clock query response
1161 function attemptSyncClockEx(stack, name, response, status) {
1162 const dev = stack.dev;
1163 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1164 if (status != 200) { dev.consoleMsg("Failed to get clock (" + status + ")."); removeAmtDevice(dev, 17); return; }
1166 // Compute how much drift between Intel AMT and our clock.
1167 var t = new Date(), now = new Date();
1168 t.setTime(response.Body['Ta0'] * 1000);
1169 if (Math.abs(t - now) > 10000) { // If the Intel AMT clock is more than 10 seconds off, set it.
1170 dev.consoleMsg("Performing clock sync.");
1171 var Tm1 = Math.round(now.getTime() / 1000);
1172 dev.amtstack.AMT_TimeSynchronizationService_SetHighAccuracyTimeSynch(response.Body['Ta0'], Tm1, Tm1, attemptSyncClockSet);
1174 // Clock is fine, we are done.
1175 devTaskCompleted(dev)
1179 // Intel AMT clock set response
1180 function attemptSyncClockSet(stack, name, responses, status) {
1181 const dev = stack.dev;
1182 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1183 if (status != 200) { dev.consoleMsg("Failed to sync clock (" + status + ")."); removeAmtDevice(dev, 18); }
1184 devTaskCompleted(dev)
1189 // Intel AMT TLS setup
1192 // Check if Intel AMT TLS state is correct
1193 function attemptTlsSync(dev, func) {
1194 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1195 if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
1197 dev.taskCompleted = func;
1198 // TODO: We only deal with certificates starting with Intel AMT 6 and beyond
1199 dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', 'AMT_PublicPrivateKeyPair', 'AMT_TLSSettingData', 'AMT_TLSCredentialContext'], attemptTlsSyncEx);
1202 // Intel AMT is not always in a good spot to generate a key pair. This will retry at 10 second interval.
1203 function generateKeyPairWithRetry(dev, func) {
1204 if (isAmtDeviceValid(dev) == false) return;
1205 if (dev.keyPairAttempts == null) { dev.keyPairAttempts = 1; } else { dev.keyPairAttempts++; }
1206 dev.amtstack.AMT_PublicKeyManagementService_GenerateKeyPair(0, 2048, function (stack, name, responses, status) {
1207 if (isAmtDeviceValid(dev) == false) { delete dev.keyPairAttempts; return; }
1208 if ((status == 200) || (dev.keyPairAttempts > 19)) {
1209 delete dev.keyPairAttempts;
1210 func(stack, name, responses, status);
1212 if ((responses.Body != null) && (responses.Body.ReturnValue != null) && (responses.Body.ReturnValueStr != null)) {
1213 dev.consoleMsg("Failed to generate a key pair (" + status + ", " + responses.Body.ReturnValue + ", \"" + responses.Body.ReturnValueStr + "\"), attempt " + dev.keyPairAttempts + ", trying again in 10 seconds...");
1215 dev.consoleMsg("Failed to generate a key pair (" + status + "), attempt " + dev.keyPairAttempts + ", trying again in 10 seconds...");
1218 // Wait 10 seconds before attempting again
1219 var f = function doManage() { generateKeyPairWithRetry(doManage.dev, doManage.func); }
1222 setTimeout(f, 10000);
1227 function attemptTlsSyncEx(stack, name, responses, status) {
1228 const dev = stack.dev;
1229 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1230 if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); removeAmtDevice(dev, 19); return; }
1232 // Setup the certificates
1233 dev.policy.certPrivateKeys = responses['AMT_PublicPrivateKeyPair'].responses;
1234 dev.policy.tlsSettings = responses['AMT_TLSSettingData'].responses;
1235 dev.policy.tlsCredentialContext = responses['AMT_TLSCredentialContext'].responses;
1236 var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
1237 for (var i in xxCertificates) {
1238 xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
1239 xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
1240 xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
1241 xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
1243 amtcert_linkCertPrivateKey(xxCertificates, dev.policy.certPrivateKeys);
1244 dev.policy.certificates = xxCertificates;
1246 // Find the current TLS certificate & MeshCentral root certificate
1247 var xxTlsCurrentCert = null;
1248 if (dev.policy.tlsCredentialContext.length > 0) {
1249 var certInstanceId = dev.policy.tlsCredentialContext[0]['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'];
1250 for (var i in dev.policy.certificates) { if (dev.policy.certificates[i]['InstanceID'] == certInstanceId) { xxTlsCurrentCert = i; } }
1253 // This is a managed device and TLS is not enabled, turn it on.
1254 if (xxTlsCurrentCert == null) {
1255 // Start by generating a key pair
1256 generateKeyPairWithRetry(dev, function (stack, name, responses, status) {
1257 const dev = stack.dev;
1258 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1259 if (status != 200) { dev.consoleMsg("Failed to generate a key pair (" + status + ")."); removeAmtDevice(dev, 20); return; }
1261 // Check that we get a key pair reference
1263 try { x = responses.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']; } catch (ex) { }
1264 if (x == null) { dev.consoleMsg("Unable to get key pair reference."); removeAmtDevice(dev, 21); return; }
1266 // Get the new key pair
1267 dev.amtstack.Enum('AMT_PublicPrivateKeyPair', function (stack, name, responses, status, tag) {
1268 const dev = stack.dev;
1269 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1270 if (status != 200) { dev.consoleMsg("Failed to get a key pair list (" + status + ")."); removeAmtDevice(dev, 22); return; }
1272 // Get the new DER key
1274 for (var i in responses) { if (responses[i]['InstanceID'] == tag) { DERKey = responses[i]['DERKey']; } }
1276 // Get certificate values
1277 const commonName = 'IntelAMT-' + Buffer.from(parent.crypto.randomBytes(6), 'binary').toString('hex');
1278 const domain = parent.config.domains[dev.domainid];
1279 var serverName = 'MeshCentral';
1280 if ((domain != null) && (domain.title != null)) { serverName = domain.title; }
1281 const certattributes = { 'CN': commonName, 'O': serverName, 'ST': 'MC', 'C': 'MC' };
1283 // See what root certificate to use to sign the TLS cert
1284 var xxCaPrivateKey = obj.parent.certificates.root.key; // Use our own root by default
1285 var issuerattributes = { 'CN': obj.rootCertCN };
1286 if (domain.amtmanager.tlsrootcert2 != null) {
1287 xxCaPrivateKey = domain.amtmanager.tlsrootcert2.key;
1288 issuerattributes = domain.amtmanager.tlsrootcert2.attributes;
1289 // TODO: We should change the start and end dates of our issued certificate to at least match the root.
1290 // TODO: We could do one better and auto-renew TLS certificates as needed.
1293 // Set the extended key usages
1294 var extKeyUsage = { name: 'extKeyUsage', serverAuth: true, clientAuth: true }
1296 // Sign the key pair using the CA certifiate
1297 const cert = obj.amtcert_createCertificate(certattributes, xxCaPrivateKey, DERKey, issuerattributes, extKeyUsage);
1298 if (cert == null) { dev.consoleMsg("Failed to sign the TLS certificate."); removeAmtDevice(dev, 23); return; }
1300 // Place the resulting signed certificate back into AMT
1301 var pem = obj.parent.certificateOperations.forge.pki.certificateToPem(cert).replace(/(\r\n|\n|\r)/gm, '');
1303 // Set the certificate finderprint (SHA1)
1304 var md = obj.parent.certificateOperations.forge.md.sha1.create();
1305 md.update(obj.parent.certificateOperations.forge.asn1.toDer(obj.parent.certificateOperations.forge.pki.certificateToAsn1(cert)).getBytes());
1306 dev.aquired.xhash = md.digest().toHex();
1308 dev.amtstack.AMT_PublicKeyManagementService_AddCertificate(pem.substring(27, pem.length - 25), function (stack, name, responses, status) {
1309 const dev = stack.dev;
1310 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1311 if (status != 200) { dev.consoleMsg("Failed to add TLS certificate (" + status + ")."); removeAmtDevice(dev, 24); return; }
1312 var certInstanceId = null;
1313 try { certInstanceId = responses.Body['CreatedCertificate']['ReferenceParameters']['SelectorSet']['Selector']['Value']; } catch (ex) { }
1314 if (certInstanceId == null) { dev.consoleMsg("Failed to get TLS certificate identifier."); removeAmtDevice(dev, 25); return; }
1316 // Set the TLS certificate
1317 if (dev.hbacmtls == 1) {
1318 dev.setTlsSecurityPendingCalls = 2; // Set remote port only
1320 dev.setTlsSecurityPendingCalls = 3; // Set local and remote port
1322 if (dev.policy.tlsCredentialContext.length > 0) {
1323 // Modify the current context
1324 var newTLSCredentialContext = Clone(dev.policy.tlsCredentialContext[0]);
1325 newTLSCredentialContext['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'] = certInstanceId;
1326 dev.amtstack.Put('AMT_TLSCredentialContext', newTLSCredentialContext, amtSwitchToTls, 0, 1);
1328 // Add a new security context
1329 dev.amtstack.Create('AMT_TLSCredentialContext', {
1330 'ElementInContext': '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + dev.amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + certInstanceId + '</w:Selector></w:SelectorSet></a:ReferenceParameters>',
1331 'ElementProvidingContext': '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + dev.amtstack.CompleteName('AMT_TLSProtocolEndpointCollection') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="ElementName">TLSProtocolEndpointInstances Collection</w:Selector></w:SelectorSet></a:ReferenceParameters>'
1335 // Figure out what index is local & remote
1336 var localNdx = ((dev.policy != null) && (dev.policy.tlsSettings != null) && (dev.policy.tlsSettings[0] != null) && (dev.policy.tlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);
1338 // Remote TLS settings
1339 var xxTlsSettings2 = Clone(dev.policy.tlsSettings);
1340 xxTlsSettings2[remoteNdx]['Enabled'] = true;
1341 xxTlsSettings2[remoteNdx]['MutualAuthentication'] = false;
1342 xxTlsSettings2[remoteNdx]['AcceptNonSecureConnections'] = true;
1343 delete xxTlsSettings2[remoteNdx]['TrustedCN'];
1345 // Local TLS settings
1346 xxTlsSettings2[localNdx]['Enabled'] = true;
1347 delete xxTlsSettings2[localNdx]['TrustedCN'];
1349 if (dev.hbacmtls == 1) {
1350 // If we are doing Host-based TLS ACM activation, you need to only enable the remote port with TLS.
1351 // If you enable on local port, the commit will succeed but be ignored.
1352 dev.consoleMsg("Enabling TLS on remote port...");
1353 if (remoteNdx == 0) { dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[0], amtSwitchToTls, 0, 1, xxTlsSettings2[0]); }
1354 else { dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[1], amtSwitchToTls, 0, 1, xxTlsSettings2[1]); }
1355 delete dev.hbacmtls; // Remove this indication
1357 // Update TLS settings
1358 dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[0], amtSwitchToTls, 0, 1, xxTlsSettings2[0]);
1359 dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[1], amtSwitchToTls, 0, 1, xxTlsSettings2[1]);
1363 }, responses.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']);
1366 // Update device in the database
1367 dev.intelamt.tls = dev.aquired.tls = 1;
1371 devTaskCompleted(dev);
1375 function amtSwitchToTls(stack, name, responses, status) {
1376 const dev = stack.dev;
1377 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1378 if (status != 200) { dev.consoleMsg("Failed setup TLS (" + status + ")."); removeAmtDevice(dev, 26); return; }
1380 // Check if all the calls are done & perform a commit
1381 if ((--dev.setTlsSecurityPendingCalls) == 0) {
1382 dev.consoleMsg("Performing Commit...");
1383 dev.amtstack.AMT_SetupAndConfigurationService_CommitChanges(null, function (stack, name, responses, status) {
1384 const dev = stack.dev;
1385 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1386 if (status != 200) { dev.consoleMsg("Failed perform commit (" + status + ")."); removeAmtDevice(dev, 27); return; }
1387 dev.consoleMsg("Enabled TLS, holding 10 seconds...");
1389 // Update device in the database
1390 dev.intelamt.tls = dev.aquired.tls = 1;
1391 dev.intelamt.hash = dev.aquired.hash = dev.aquired.xhash;
1392 delete dev.aquired.xhash;
1395 // Switch our communications to TLS (Restart our management of this node)
1396 dev.switchToTls = 1;
1399 // Wait 5 seconds before attempting to manage this device some more
1400 var f = function doManage() { if (isAmtDeviceValid(dev)) { devTaskCompleted(doManage.dev); } }
1402 setTimeout(f, 10000);
1409 // Intel AMT WIFI & Wired 802.1x
1412 // Check which key pair matches the public key in the certificate
1413 function amtcert_linkCertPrivateKey(certs, keys) {
1414 for (var i in certs) {
1415 var cert = certs[i];
1417 if (keys.length == 0) return;
1418 var publicKeyPEM = forge.pki.publicKeyToPem(forge.pki.certificateFromAsn1(forge.asn1.fromDer(cert.X509Certificate)).publicKey).substring(28 + 32).replace(/(\r\n|\n|\r)/gm, "");
1419 for (var j = 0; j < keys.length; j++) {
1420 if (publicKeyPEM === (keys[j]['DERKey'] + '-----END PUBLIC KEY-----')) {
1421 keys[j].XCert = cert; // Link the key pair to the certificate
1422 cert.XPrivateKey = keys[j]; // Link the certificate to the key pair
1425 } catch (e) { console.log(e); }
1429 // This method will sync the WIFI profiles from the device and the server, but does not care about profile priority.
1430 // We also sync wired 802.1x at the same time since we only allow a single 802.1x profile per device shared between wired and wireless
1431 // We may want to work on an alternate version that does do priority if requested.
1432 function attemptWifiSync(dev, func) {
1433 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1434 if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
1435 if (dev.connType != 2) { func(dev); return; } // Only configure wireless over a CIRA-LMS link
1436 //if (parent.config.domains[dev.domainid].amtmanager.wifiprofiles == null) { func(dev); return; } // No server WIFI profiles set, skip this.
1437 //if ((dev.mpsConnection.tag.meiState == null) || (dev.mpsConnection.tag.meiState.net1 == null)) { func(dev); return; } // No WIFI on this device, skip this.
1439 // Get the current list of WIFI profiles, wireless interface state and wired 802.1x profile
1441 dev.taskCompleted = func;
1443 const objQuery = ['CIM_WiFiEndpointSettings', '*CIM_WiFiPort', '*AMT_WiFiPortConfigurationService', 'CIM_IEEE8021xSettings', 'AMT_PublicKeyCertificate', 'AMT_PublicPrivateKeyPair'];
1444 if (parent.config.domains[dev.domainid].amtmanager['802.1x'] != null) { objQuery.push('*AMT_8021XProfile'); }
1445 dev.amtstack.BatchEnum(null, objQuery, function (stack, name, responses, status) {
1446 const dev = stack.dev;
1447 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1448 const domain = parent.config.domains[dev.domainid];
1449 if ((responses['AMT_PublicKeyCertificate'] == null) || (responses['AMT_PublicKeyCertificate'].status != 200) || (responses['AMT_PublicPrivateKeyPair'] == null) || (responses['AMT_PublicPrivateKeyPair'].status != 200)) { devTaskCompleted(dev); return; } // We can't get the certificate list, fail and carry on.
1451 // See if we need to perform wired or wireless 802.1x configuration
1452 var wiredConfig = ((parent.config.domains[dev.domainid].amtmanager['802.1x'] != null) && (responses['AMT_8021XProfile'] != null) && (responses['AMT_8021XProfile'].status == 200));
1453 const wirelessConfig = ((responses['CIM_WiFiEndpointSettings'] != null) && (responses['CIM_WiFiEndpointSettings'].status == 200) && (responses['AMT_WiFiPortConfigurationService'] != null) && (responses['AMT_WiFiPortConfigurationService'].status == 200) && (responses['CIM_WiFiPort'] != null) && (responses['CIM_WiFiPort'].status == 200) && (responses['CIM_IEEE8021xSettings'] != null) && (responses['CIM_IEEE8021xSettings'].status == 200));
1454 if (!wiredConfig && !wirelessConfig) { devTaskCompleted(dev); return; } // We can't get wired or wireless settings, ignore and carry on.
1456 // Sort out the certificates
1457 var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
1458 var xxCertPrivateKeys = responses['AMT_PublicPrivateKeyPair'].responses;
1459 for (var i in xxCertificates) {
1460 xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
1461 xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
1462 xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
1463 xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
1465 amtcert_linkCertPrivateKey(xxCertificates, xxCertPrivateKeys); // This links all certificates and private keys
1467 // Remove any unlinked private keys
1468 for (var i in xxCertPrivateKeys) {
1469 if (!xxCertPrivateKeys[i].XCert) {
1470 dev.amtstack.Delete('AMT_PublicPrivateKeyPair', { 'InstanceID': xxCertPrivateKeys[i]['InstanceID'] }, function (stack, name, response, status) {
1471 //if (status == 200) { dev.consoleMsg("Removed unassigned private key pair."); }
1476 // Check if wired 802.1x needs updating
1477 var newNetAuthProfileRequested = false;
1478 var srvNetAuthProfile = domain.amtmanager['802.1x'];
1479 var devNetAuthProfile = null;
1480 var netAuthClientCertInstanceId = null;
1484 devNetAuthProfile = responses['AMT_8021XProfile'].response;
1485 if ((srvNetAuthProfile === false) && (devNetAuthProfile != null)) {
1486 // Remove the 802.1x profile
1488 } else if ((srvNetAuthProfile != null) && (devNetAuthProfile == null)) {
1489 // Device has no 802.1x, add it
1491 } else if ((typeof srvNetAuthProfile == 'object') && (devNetAuthProfile != null)) {
1492 // Check if the existing 802.1x profile look good
1493 if (devNetAuthProfile.AuthenticationProtocol != srvNetAuthProfile.authenticationprotocol) { wiredMatch = 2; }
1494 if (devNetAuthProfile.ServerCertificateName != srvNetAuthProfile.servercertificatename) { wiredMatch = 2; }
1495 if (devNetAuthProfile.ServerCertificateNameComparison != srvNetAuthProfile.servercertificatenamecomparison) { wiredMatch = 2; }
1496 if (devNetAuthProfile.ActiveInS0 != srvNetAuthProfile.availableins0) { wiredMatch = 2; }
1497 if (typeof srvNetAuthProfile.satellitecredentials != 'string') {
1498 // Credentials for this profile are in the config file
1499 if (devNetAuthProfile.RoamingIdentity != srvNetAuthProfile.roamingidentity) { wiredMatch = 2; }
1500 if (devNetAuthProfile.Username != srvNetAuthProfile.username) { wiredMatch = 2; }
1501 if (devNetAuthProfile.Domain != srvNetAuthProfile.domain) { wiredMatch = 2; }
1503 // If the existing 802.1x profile has a certificate, remember the client certificate instance id for later checking
1504 if (devNetAuthProfile.ClientCertificate) { netAuthClientCertInstanceId = devNetAuthProfile.ClientCertificate.ReferenceParameters.SelectorSet.Selector.Value; }
1506 if (wiredMatch == 2) { newNetAuthProfileRequested = true; }
1509 if (wirelessConfig) {
1510 // If we have server WIFI profiles to sync, do this now.
1511 if (parent.config.domains[dev.domainid].amtmanager.wifiprofiles != null) {
1512 // The server and device WIFI profiles, find profiles to add and remove
1513 const sevProfiles = parent.config.domains[dev.domainid].amtmanager.wifiprofiles;
1514 const devProfiles = responses['CIM_WiFiEndpointSettings'].responses;
1515 const netAuthProfiles = responses['CIM_IEEE8021xSettings'].responses;
1516 var profilesToAdd = [], profilesToRemove = [];
1517 var profilesToAdd2 = [], profilesToRemove2 = [];
1519 // Look at the WIFI profiles in the device
1520 for (var i in sevProfiles) {
1521 var sevProfile = sevProfiles[i], wirelessMatch = false;
1522 for (var j in devProfiles) {
1523 var devProfile = devProfiles[j];
1525 (devProfile.ElementName == sevProfile.name) &&
1526 (devProfile.SSID == sevProfile.ssid) &&
1527 (devProfile.AuthenticationMethod == sevProfile.authentication) &&
1528 (devProfile.EncryptionMethod == sevProfile.encryption) &&
1529 (devProfile.BSSType == sevProfile.type)
1531 if (([5, 7, 32768, 32769].indexOf(sevProfile.authentication)) >= 0) {
1532 // This is a 802.1x profile, do some extra matching.
1533 // Start by finding the 802.1x profile for this WIFI profile
1534 var netAuthProfile = null, netAuthMatch = false;
1535 for (var k in netAuthProfiles) { if (netAuthProfiles[k].ElementName == devProfile.ElementName) { netAuthProfile = netAuthProfiles[k]; } }
1536 if (netAuthProfile != null) {
1537 netAuthMatch = true;
1538 if (srvNetAuthProfile.authenticationprotocol != netAuthProfile['AuthenticationProtocol']) { netAuthMatch = false; }
1539 if (srvNetAuthProfile.roamingidentity != netAuthProfile['RoamingIdentity']) { netAuthMatch = false; }
1540 if (srvNetAuthProfile.servercertificatename != netAuthProfile['ServerCertificateName']) { netAuthMatch = false; }
1541 if (srvNetAuthProfile.servercertificatenamecomparison != netAuthProfile['ServerCertificateNameComparison']) { netAuthMatch = false; }
1542 if (typeof srvNetAuthProfile.satellitecredentials != 'string') {
1543 // Credentials for this profile are in the config file
1544 if (srvNetAuthProfile.username != netAuthProfile['Username']) { netAuthMatch = false; }
1545 if (srvNetAuthProfile.domain != netAuthProfile['Domain']) { netAuthMatch = false; }
1549 // TODO: If the existing 802.1x profile has a certificate, remember the client certificate instance id for later checking
1551 if (netAuthMatch == true) {
1552 // The 802.1x profile seems to match what we want, keep it.
1553 wirelessMatch = true;
1554 devProfile.match = true;
1557 // Not a 802.1x profile, looks fine, keep it.
1558 wirelessMatch = true;
1559 devProfile.match = true;
1563 if (wirelessMatch == false) { profilesToAdd.push(sevProfile); } // Add non-matching profile
1564 if ((wirelessMatch == false) || (([5, 7, 32768, 32769].indexOf(sevProfile.authentication)) >= 0)) { profilesToAdd2.push(sevProfile); } // Add non-matching profile or 802.1x profile
1566 for (var j in devProfiles) {
1567 var devProfile = devProfiles[j];
1568 if (devProfile.InstanceID != null) {
1569 if (devProfile.match !== true) { profilesToRemove.push(devProfile); } // Missing profile to remove
1570 if ((devProfile.match !== true) || (([5, 7, 32768, 32769].indexOf(devProfile.AuthenticationMethod)) >= 0)) { profilesToRemove2.push(devProfile); } // Missing profile to remove or 802.1x profile
1574 // Compute what priorities are allowed
1575 var prioritiesInUse = [];
1576 for (var j in devProfiles) { if (devProfiles[j].match == true) { prioritiesInUse.push(devProfiles[j].Priority); } }
1578 // Check if any other WIFI profiles require a 802.1x request to MeshCentral Satellite
1579 if (dev.netAuthCredentials == null) {
1580 for (var i in profilesToAdd) { if (([5, 7, 32768, 32769].indexOf(profilesToAdd[i].authentication)) >= 0) { newNetAuthProfileRequested = true; } }
1583 // If we need to request a new 802.1x profile, remove all existing 802.1x WIFI profiles and re-add later.
1584 if (newNetAuthProfileRequested) {
1585 profilesToAdd = profilesToAdd2; // Just use the second list we built for this purpose.
1586 profilesToRemove = profilesToRemove2;
1589 // Notify of WIFI profile changes
1590 if ((profilesToAdd.length > 0) || (profilesToRemove.length > 0)) { dev.consoleMsg("Changing WIFI profiles, adding " + profilesToAdd.length + ", removing " + profilesToRemove.length + "."); }
1592 // Remove any extra WIFI profiles
1593 for (var i in profilesToRemove) {
1594 dev.amtstack.Delete('CIM_WiFiEndpointSettings', { InstanceID: 'Intel(r) AMT:WiFi Endpoint Settings ' + profilesToRemove[i].ElementName }, function (stack, name, responses, status) { }, 0, 1);
1599 // Check the 802.1x client certificate expiration time
1600 // TODO: We are only getting the client cert from the wired 802.1x profile, need to get it for wireless too.
1601 var netAuthClientCert = null;
1602 if (netAuthClientCertInstanceId != null) {
1603 netAuthClientCert = getInstance(responses['AMT_PublicKeyCertificate'].responses, netAuthClientCertInstanceId);
1604 if (netAuthClientCert) {
1606 try { cert = obj.parent.certificateOperations.forge.pki.certificateFromAsn1(obj.parent.certificateOperations.forge.asn1.fromDer(obj.parent.certificateOperations.forge.util.decode64(netAuthClientCert.X509Certificate))); } catch (ex) { }
1608 const certStart = new Date(cert.validity.notBefore).getTime();
1609 const certEnd = new Date(cert.validity.notAfter).getTime();
1610 const certMidPoint = certStart + ((certEnd - certStart) / 2);
1611 if (Date.now() > certMidPoint) { newNetAuthProfileRequested = true; } // Past mid-point or expired, request a new 802.1x certificate & profile
1616 // Figure out if there are no changes to 802.1x wired configuration
1617 if ((wiredMatch == 0) && (newNetAuthProfileRequested == false)) { wiredConfig = false; }
1619 // See if we need to ask MeshCentral Satellite for a new 802.1x profile
1620 if (newNetAuthProfileRequested && (typeof srvNetAuthProfile.satellitecredentials == 'string')) {
1621 // Credentials for this 802.1x profile are provided using MeshCentral Satellite
1622 // Send a message to Satellite requesting a 802.1x profile for this device
1623 dev.consoleMsg("Requesting 802.1x credentials for " + netAuthStrings[srvNetAuthProfile.authenticationprotocol] + " from MeshCentral Satellite...");
1624 dev.netAuthSatReqId = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64'); // Generate a crypto-secure request id.
1625 dev.netAuthSatReqData = { domain: domain, wiredConfig: wiredConfig, wirelessConfig: wirelessConfig, devNetAuthProfile: devNetAuthProfile, srvNetAuthProfile: srvNetAuthProfile, profilesToAdd: profilesToAdd, prioritiesInUse: prioritiesInUse, responses: responses, xxCertificates: xxCertificates, xxCertPrivateKeys: xxCertPrivateKeys }
1626 const request = { action: 'satellite', subaction: '802.1x-ProFile-Request', satelliteFlags: 2, nodeid: dev.nodeid, icon: dev.icon, domain: dev.nodeid.split('/')[1], nolog: 1, reqid: dev.netAuthSatReqId, authProtocol: srvNetAuthProfile.authenticationprotocol, devname: dev.name, osname: dev.rname, ver: dev.intelamt.ver };
1627 if (netAuthClientCert != null) { request.cert = netAuthClientCert.X509Certificate; request.certid = netAuthClientCertInstanceId; }
1628 parent.DispatchEvent([srvNetAuthProfile.satellitecredentials], obj, request);
1630 // Set a response timeout
1631 const netAuthTimeoutFunc = function netAuthTimeout() {
1632 if (isAmtDeviceValid(netAuthTimeout.dev) == false) return; // Device no longer exists, ignore this request.
1633 if (dev.netAuthSatReqId != null) {
1634 delete netAuthTimeout.dev.netAuthSatReqId;
1635 delete netAuthTimeout.dev.netAuthSatReqData;
1636 netAuthTimeout.dev.consoleMsg("MeshCentral Satellite did not respond in time, 802.1x profile will not be set.");
1637 devTaskCompleted(netAuthTimeout.dev);
1640 netAuthTimeoutFunc.dev = dev;
1641 dev.netAuthSatReqTimer = setTimeout(netAuthTimeoutFunc, 20000);
1644 // No need to call MeshCentral Satellite for a 802.1x profile, so configure everything now.
1645 attempt8021xSyncEx(dev, { domain: domain, wiredConfig: wiredConfig, wirelessConfig: wirelessConfig, devNetAuthProfile: devNetAuthProfile, srvNetAuthProfile: srvNetAuthProfile, profilesToAdd: profilesToAdd, prioritiesInUse: prioritiesInUse, responses: responses, xxCertificates: xxCertificates, xxCertPrivateKeys: xxCertPrivateKeys });
1651 // Check 802.1x root certificate
1652 function perform8021xRootCertCheck(dev) {
1653 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1655 // Check if there is a root certificate to add, if we already have it, get the instance id.
1656 if (dev.netAuthCredentials.rootcert) {
1657 var matchingRootCertId = null;
1658 for (var i in dev.netAuthSatReqData.xxCertificates) {
1659 if ((dev.netAuthSatReqData.xxCertificates[i].X509Certificate == dev.netAuthCredentials.rootcert) && (dev.netAuthSatReqData.xxCertificates[i].TrustedRootCertficate)) {
1660 matchingRootCertId = dev.netAuthSatReqData.xxCertificates[i].InstanceID;
1663 if (matchingRootCertId == null) {
1664 // Root certificate not found, add it
1665 dev.consoleMsg("Setting up new 802.1x root certificate...");
1666 const f = function perform8021xRootCertCheckResponse(stack, name, response, status) {
1667 if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
1668 // Failed to add the root certificate
1669 dev.consoleMsg("Failed to sign the certificate request.");
1671 // Root certificate added, move on to client certificate checking
1672 perform8021xRootCertCheckResponse.dev.netAuthSatReqData.rootCertInstanceId = response.Body.CreatedCertificate.ReferenceParameters.SelectorSet.Selector.Value;
1673 perform8021xClientCertCheck(perform8021xRootCertCheckResponse.dev);
1677 dev.amtstack.AMT_PublicKeyManagementService_AddTrustedRootCertificate(dev.netAuthCredentials.rootcert, f);
1679 // Root certificate already present, move on to client certificate checking
1680 dev.netAuthSatReqData.rootCertInstanceId = matchingRootCertId;
1681 perform8021xClientCertCheck(dev);
1684 // No root certificate to check, move on to client certificate checking
1685 perform8021xClientCertCheck(dev);
1689 // Check 802.1x client certificate
1690 function perform8021xClientCertCheck(dev) {
1691 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1693 if (dev.netAuthCredentials.certificate) {
1694 // The new 802.1x profile includes a new certificate, add it now before adding the 802.1x profiles
1695 // dev.netAuthCredentials.certificate must be in DER encoded format
1696 dev.consoleMsg("Setting up new 802.1x client certificate...");
1697 const f = function AddCertificateResponse(stack, name, response, status) {
1698 if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
1699 AddCertificateResponse.dev.consoleMsg("Unable to set 802.1x certificate.");
1701 // Keep the certificate reference since we need it to add 802.1x profiles
1702 const certInstanceId = response.Body.CreatedCertificate.ReferenceParameters.SelectorSet.Selector.Value;
1704 // Set the 802.1x wired profile in the device
1705 AddCertificateResponse.dev.consoleMsg("Setting MeshCentral Satellite 802.1x profile...");
1706 const netAuthSatReqData = AddCertificateResponse.dev.netAuthSatReqData;
1707 delete dev.netAuthSatReqData;
1708 netAuthSatReqData.certInstanceId = certInstanceId;
1709 attempt8021xSyncEx(AddCertificateResponse.dev, netAuthSatReqData);
1713 dev.amtstack.AMT_PublicKeyManagementService_AddCertificate(dev.netAuthCredentials.certificate, f);
1715 // No 802.1x certificate, set the 802.1x wired profile in the device
1716 dev.consoleMsg("Setting MeshCentral Satellite 802.1x profile...");
1717 const netAuthSatReqData = dev.netAuthSatReqData;
1718 delete dev.netAuthSatReqData;
1719 if (dev.netAuthCredentials.certid) { netAuthSatReqData.certInstanceId = dev.netAuthCredentials.certid; } // If we are reusing an existing certificate, set that now.
1720 attempt8021xSyncEx(dev, netAuthSatReqData);
1724 // Set the 802.1x wired profile
1725 function attempt8021xSyncEx(dev, devNetAuthData) {
1726 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1729 const domain = devNetAuthData.domain;
1730 const devNetAuthProfile = devNetAuthData.devNetAuthProfile;
1731 const srvNetAuthProfile = devNetAuthData.srvNetAuthProfile;
1732 const profilesToAdd = devNetAuthData.profilesToAdd;
1733 const responses = devNetAuthData.responses;
1734 const wiredConfig = devNetAuthData.wiredConfig;
1735 const wirelessConfig = devNetAuthData.wirelessConfig;
1738 var netAuthProfile = Clone(devNetAuthProfile);
1739 netAuthProfile['Enabled'] = ((srvNetAuthProfile != null) && (typeof srvNetAuthProfile == 'object'));
1740 if (netAuthProfile['Enabled']) {
1741 netAuthProfile['ActiveInS0'] = (srvNetAuthProfile.availableins0 !== false);
1742 netAuthProfile['AuthenticationProtocol'] = srvNetAuthProfile.authenticationprotocol;
1743 if (srvNetAuthProfile.roamingidentity && (srvNetAuthProfile.roamingidentity != '')) { netAuthProfile['RoamingIdentity'] = srvNetAuthProfile.roamingidentity; } else { delete netAuthProfile['RoamingIdentity']; }
1744 if (srvNetAuthProfile.servercertificatename && (srvNetAuthProfile.servercertificatename != '')) {
1745 netAuthProfile['ServerCertificateName'] = srvNetAuthProfile.servercertificatename;
1746 netAuthProfile['ServerCertificateNameComparison'] = srvNetAuthProfile.servercertificatenamecomparison;
1748 delete netAuthProfile['ServerCertificateName'];
1749 delete netAuthProfile['ServerCertificateNameComparison'];
1751 if (srvNetAuthProfile.username && (srvNetAuthProfile.username != '')) { netAuthProfile['Username'] = srvNetAuthProfile.username; } else { delete netAuthProfile['Username']; }
1752 if (srvNetAuthProfile.password && (srvNetAuthProfile.password != '')) { netAuthProfile['Password'] = srvNetAuthProfile.password; } else { delete netAuthProfile['Password']; }
1753 if (srvNetAuthProfile.domain && (srvNetAuthProfile.domain != '')) { netAuthProfile['Domain'] = srvNetAuthProfile.domain; } else { delete netAuthProfile['Domain']; }
1754 if (srvNetAuthProfile.authenticationprotocol > 3) {
1755 netAuthProfile['ProtectedAccessCredential'] = srvNetAuthProfile.protectedaccesscredentialhex;
1756 netAuthProfile['PACPassword'] = srvNetAuthProfile.pacpassword;
1758 delete netAuthProfile['ProtectedAccessCredential'];
1759 delete netAuthProfile['PACPassword'];
1762 // Setup Client Certificate
1763 if (devNetAuthData.certInstanceId) {
1764 netAuthProfile['ClientCertificate'] = '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + dev.amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + devNetAuthData.certInstanceId + '</w:Selector></w:SelectorSet></a:ReferenceParameters>';
1766 delete netAuthProfile['ClientCertificate'];
1769 // Setup Server Certificate
1770 if (devNetAuthData.rootCertInstanceId) {
1771 netAuthProfile['ServerCertificateIssuer'] = '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + dev.amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + devNetAuthData.rootCertInstanceId + '</w:Selector></w:SelectorSet></a:ReferenceParameters>';
1773 delete netAuthProfile['ServerCertificateIssuer'];
1776 netAuthProfile['PxeTimeout'] = (typeof srvNetAuthProfile.pxetimeoutinseconds == 'number') ? srvNetAuthProfile.pxetimeoutinseconds : 120;
1778 // If we have a MeshCentral Satellite profile, use that
1779 if (dev.netAuthCredentials != null) {
1780 const srvNetAuthProfile2 = dev.netAuthCredentials;
1781 if (srvNetAuthProfile2.username && (srvNetAuthProfile2.username != '')) { netAuthProfile['Username'] = srvNetAuthProfile2.username; }
1782 if (srvNetAuthProfile2.password && (srvNetAuthProfile2.password != '')) { netAuthProfile['Password'] = srvNetAuthProfile2.password; }
1783 if (srvNetAuthProfile2.domain && (srvNetAuthProfile2.domain != '')) { netAuthProfile['Domain'] = srvNetAuthProfile2.domain; }
1787 dev.amtstack.Put('AMT_8021XProfile', netAuthProfile, function (stack, name, responses, status) {
1788 const dev = stack.dev;
1789 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1790 if (status == 200) { dev.consoleMsg("802.1x wired profile set."); } else { dev.consoleMsg("Unable to set 802.1x wired profile."); }
1791 attemptWifiSyncEx(dev, devNetAuthData);
1794 // No wired interface, skip with WIFI config
1795 attemptWifiSyncEx(dev, devNetAuthData);
1799 function attemptWifiSyncEx(dev, devNetAuthData) {
1800 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1803 const domain = devNetAuthData.domain;
1804 const devNetAuthProfile = devNetAuthData.devNetAuthProfile;
1805 const srvNetAuthProfile = devNetAuthData.srvNetAuthProfile;
1806 const profilesToAdd = devNetAuthData.profilesToAdd;
1807 const responses = devNetAuthData.responses;
1808 const prioritiesInUse = devNetAuthData.prioritiesInUse;
1809 const wiredConfig = devNetAuthData.wiredConfig;
1810 const wirelessConfig = devNetAuthData.wirelessConfig;
1812 var taskCounter = 0;
1813 if (wirelessConfig) {
1814 // Add missing WIFI profiles
1815 var nextPriority = 1;
1816 for (var i in profilesToAdd) {
1817 while (prioritiesInUse.indexOf(nextPriority) >= 0) { nextPriority++; } // Figure out the next available priority slot.
1818 var profileToAdd = profilesToAdd[i];
1820 __parameterType: 'reference',
1821 __resourceUri: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpoint',
1822 Name: 'WiFi Endpoint 0'
1824 const wifiepsettinginput = {
1825 __parameterType: 'instance',
1826 __namespace: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpointSettings',
1827 ElementName: profileToAdd.name,
1828 InstanceID: 'Intel(r) AMT:WiFi Endpoint Settings ' + profileToAdd.name,
1829 AuthenticationMethod: profileToAdd.authentication,
1830 EncryptionMethod: profileToAdd.encryption,
1831 SSID: profileToAdd.ssid,
1832 Priority: nextPriority,
1834 var netAuthProfile, netAuthSettingsClientCert, netAuthSettingsServerCaCert;
1835 if (([4, 6].indexOf(profileToAdd.authentication)) >= 0) { wifiepsettinginput['PSKPassPhrase'] = profileToAdd.password; }
1836 if (([5, 7, 32768, 32769].indexOf(profileToAdd.authentication)) >= 0) {
1838 '__parameterType': 'instance',
1839 '__namespace': dev.amtstack.CompleteName('CIM_IEEE8021xSettings'),
1840 'ElementName': '8021x-' + profileToAdd.name,
1841 'InstanceID': '8021x-' + profileToAdd.name,
1842 'ActiveInS0': (domain.amtmanager['802.1x'].availableins0 !== false),
1843 'AuthenticationProtocol': domain.amtmanager['802.1x'].authenticationprotocol
1845 if (domain.amtmanager['802.1x'].roamingidentity) { netAuthProfile['RoamingIdentity'] = domain.amtmanager['802.1x'].roamingidentity; }
1846 if (domain.amtmanager['802.1x'].servercertificatename) { netAuthProfile['ServerCertificateName'] = domain.amtmanager['802.1x'].servercertificatename; netAuthProfile['ServerCertificateNameComparison'] = profileToAdd['802.1x'].servercertificatenamecomparison; }
1847 if (domain.amtmanager['802.1x'].username) { netAuthProfile['Username'] = domain.amtmanager['802.1x'].username; }
1848 if (domain.amtmanager['802.1x'].password) { netAuthProfile['Password'] = domain.amtmanager['802.1x'].password; }
1849 if (domain.amtmanager['802.1x'].domain) { netAuthProfile['Domain'] = domain.amtmanager['802.1x'].domain; }
1850 if (domain.amtmanager['802.1x'].authenticationprotocol > 3) { domain.amtmanager['ProtectedAccessCredential'] = profileToAdd['802.1x'].protectedaccesscredentialhex; netAuthProfile['PACPassword'] = profileToAdd['802.1x'].pacpassword; }
1852 // Setup Client Certificate
1853 if (devNetAuthData.certInstanceId) {
1854 netAuthSettingsClientCert = '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + dev.amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + devNetAuthData.certInstanceId + '</w:Selector></w:SelectorSet></a:ReferenceParameters>';
1856 // Setup Server Certificate
1857 if (devNetAuthData.rootCertInstanceId) {
1858 netAuthSettingsServerCaCert = '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + dev.amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + devNetAuthData.rootCertInstanceId + '</w:Selector></w:SelectorSet></a:ReferenceParameters>';
1861 // If we have credentials from MeshCentral Satelite, use that
1862 if (dev.netAuthCredentials != null) {
1863 const srvNetAuthProfile2 = dev.netAuthCredentials;
1864 if (srvNetAuthProfile2.username && (srvNetAuthProfile2.username != '')) { netAuthProfile['Username'] = srvNetAuthProfile2.username; }
1865 if (srvNetAuthProfile2.password && (srvNetAuthProfile2.password != '')) { netAuthProfile['Password'] = srvNetAuthProfile2.password; }
1866 if (srvNetAuthProfile2.domain && (srvNetAuthProfile2.domain != '')) { netAuthProfile['Domain'] = srvNetAuthProfile2.domain; }
1869 prioritiesInUse.push(nextPriority); // Occupy the priority slot and add the WIFI profile.
1872 dev.amtstack.AMT_WiFiPortConfigurationService_AddWiFiSettings(wifiep, wifiepsettinginput, netAuthProfile, netAuthSettingsClientCert, netAuthSettingsServerCaCert, function (stack, name, response, status) {
1873 if (status != 200) { dev.consoleMsg("Unable to set WIFI profile."); }
1874 if (--taskCounter == 0) { attemptWifiSyncEx2(dev, devNetAuthData); } // All done, complete WIFI configuration
1879 if (taskCounter == 0) { attemptWifiSyncEx2(dev, devNetAuthData); } // All done, complete WIFI configuration
1882 function attemptWifiSyncEx2(dev, devNetAuthData) {
1883 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1884 const responses = devNetAuthData.responses;
1885 const wirelessConfig = devNetAuthData.wirelessConfig;
1887 if (wirelessConfig) {
1888 // Check if local WIFI profile sync is enabled, if not, enabled it.
1889 if ((responses['AMT_WiFiPortConfigurationService'] != null) && (responses['AMT_WiFiPortConfigurationService'].response != null) && (responses['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] == 0)) {
1890 responses['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] = 1;
1891 dev.amtstack.Put('AMT_WiFiPortConfigurationService', responses['AMT_WiFiPortConfigurationService'].response, function (stack, name, response, status) {
1892 if (status != 200) { dev.consoleMsg("Unable to enable local WIFI profile sync."); } else { dev.consoleMsg("Enabled local WIFI profile sync."); }
1896 // Change the WIFI state if needed. Right now, we always enable it.
1897 // WifiState = { 3: "Disabled", 32768: "Enabled in S0", 32769: "Enabled in S0, Sx/AC" };
1898 var wifiState = 32769; // For now, always enable WIFI
1899 if (responses['CIM_WiFiPort'].responses.Body.EnabledState != 32769) {
1900 if (wifiState == 3) {
1901 dev.amtstack.CIM_WiFiPort_RequestStateChange(wifiState, null, function (stack, name, responses, status) {
1902 const dev = stack.dev;
1903 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1904 if (status == 200) { dev.consoleMsg("Disabled WIFI."); }
1907 dev.amtstack.CIM_WiFiPort_RequestStateChange(wifiState, null, function (stack, name, responses, status) {
1908 const dev = stack.dev;
1909 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1910 if (status == 200) { dev.consoleMsg("Enabled WIFI."); }
1917 devTaskCompleted(dev);
1920 // Request for a RSA key pair generation. This will be used to generate the 802.1x certificate
1921 function attempt8021xKeyGeneration(dev) {
1922 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1924 dev.amtstack.AMT_PublicKeyManagementService_GenerateKeyPair(0, 2048, function (stack, name, response, status) {
1925 if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
1926 // Failed to generate a key pair
1927 dev.consoleMsg("Failed to generate the requested RSA key pair.");
1929 dev.amtstack.Enum('AMT_PublicPrivateKeyPair', function (stack, name, xresponse, status, keyInstanceId) {
1930 if (status != 200) {
1931 // Failed to get the generated key pair
1932 dev.consoleMsg("Failed to get the generated RSA key pair.");
1934 // We got the key pair
1936 for (var i in xresponse) {
1937 if (xresponse[i]['InstanceID'] == keyInstanceId) {
1938 // We found our matching DER key
1939 DERKey = xresponse[i]['DERKey'];
1942 if (DERKey == null) { dev.consoleMsg("Failed to match the generated RSA key pair."); return; }
1943 dev.consoleMsg("Generated a RSA key pair.");
1944 var domain = parent.config.domains[dev.domainid];
1945 parent.DispatchEvent([domain.amtmanager['802.1x'].satellitecredentials], obj, { action: 'satellite', subaction: '802.1x-KeyPair-Response', satelliteFlags: 2, nodeid: dev.nodeid, icon: dev.icon, domain: dev.nodeid.split('/')[1], nolog: 1, reqid: dev.netAuthSatReqId, authProtocol: domain.amtmanager['802.1x'].authenticationprotocol, devname: dev.name, osname: dev.rname, DERKey: DERKey, keyInstanceId: keyInstanceId, ver: dev.intelamt.ver });
1947 }, response.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']);
1952 // 802.1x request to process a Certificate Signing Request, we ask Intel AMT to sign the request
1953 function attempt8021xCRSRequest(dev, event) {
1954 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1956 if ((event.response == null) || (event.response.keyInstanceId == null)) return;
1957 var keyPair = '<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address><a:ReferenceParameters><w:ResourceURI>http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicPrivateKeyPair</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + event.response.keyInstanceId + '</w:Selector></w:SelectorSet></a:ReferenceParameters>'; // keyPair EPR Reference
1958 var signingAlgorithm = 1; // 0 = SHA1-RSA, 1 = SHA256-RSA
1959 var nullSignedCertificateRequest = event.response.csr; // DEREncodedRequest
1960 dev.amtstack.AMT_PublicKeyManagementService_GeneratePKCS10RequestEx(keyPair, signingAlgorithm, nullSignedCertificateRequest, function (stack, name, response, status) {
1961 if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
1962 // Failed to get the generated key pair
1963 dev.consoleMsg("Failed to sign the certificate request.");
1965 // We got a signed certificate request, return that to the server
1966 dev.consoleMsg("Generated a signed certificate request.");
1967 var domain = parent.config.domains[dev.domainid];
1968 parent.DispatchEvent([domain.amtmanager['802.1x'].satellitecredentials], obj, { action: 'satellite', subaction: '802.1x-CSR-Response', satelliteFlags: 2, nodeid: dev.nodeid, icon: dev.icon, domain: dev.nodeid.split('/')[1], nolog: 1, reqid: dev.netAuthSatReqId, authProtocol: domain.amtmanager['802.1x'].authenticationprotocol, devname: dev.name, osname: dev.rname, signedcsr: response.Body['SignedCertificateRequest'], ver: dev.intelamt.ver });
1975 // Intel AMT Server Root Certificate
1978 // Check if Intel AMT has the server root certificate
1979 function attemptRootCertSync(dev, func, forced) {
1980 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1981 if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
1982 if (forced !== true) { if ((dev.connType != 2) || (dev.policy.ciraPolicy != 2)) { func(dev); return; } } // Server root certificate does not need to be present if CIRA is not needed and "forced" is false
1983 if (parent.mpsserver.server == null) { func(dev); return; } // Root cert not needed if MPS is not active.
1985 // Find the current TLS certificate & MeshCentral root certificate
1986 var xxMeshCentralRoot = null;
1987 if (dev.policy.tlsCredentialContext.length > 0) {
1988 for (var i in dev.policy.certificates) { if (dev.policy.certificates[i]['X509Certificate'] == obj.rootCertBase64) { xxMeshCentralRoot = i; } }
1991 // If the server root certificate is not present and we need to configure CIRA, add it
1992 if (xxMeshCentralRoot == null) {
1994 dev.taskCompleted = func;
1995 dev.amtstack.AMT_PublicKeyManagementService_AddTrustedRootCertificate(obj.rootCertBase64, function (stack, name, responses, status) {
1996 const dev = stack.dev;
1997 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
1998 if (status != 200) { dev.consoleMsg("Failed to add server root certificate (" + status + ")."); removeAmtDevice(dev, 28); return; }
1999 dev.consoleMsg("Added server root certificate.");
2000 devTaskCompleted(dev);
2002 } else { func(dev); }
2007 // Intel AMT CIRA Setup
2010 // Check if Intel AMT has the server root certificate
2011 // If deactivation policy is in effect, remove CIRA configuration
2012 function attemptCiraSync(dev, func) {
2013 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2014 if ((dev.connType != 2) || ((dev.policy.ciraPolicy != 1) && (dev.policy.ciraPolicy != 2))) { func(dev); return; } // Only setup CIRA when LMS connection is used and a CIRA policy is enabled.
2016 // Get current CIRA settings
2017 // TODO: We only deal with remote access starting with Intel AMT 6 and beyond
2019 dev.taskCompleted = func;
2021 var requests = ['*AMT_EnvironmentDetectionSettingData', 'AMT_ManagementPresenceRemoteSAP', 'AMT_RemoteAccessCredentialContext', 'AMT_RemoteAccessPolicyAppliesToMPS', 'AMT_RemoteAccessPolicyRule', '*AMT_UserInitiatedConnectionService', 'AMT_MPSUsernamePassword'];
2022 if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 11)) { requests.push('*IPS_HTTPProxyService', 'IPS_HTTPProxyAccessPoint'); }
2023 dev.amtstack.BatchEnum(null, requests, attemptCiraSyncResponse);
2026 function attemptCiraSyncResponse(stack, name, responses, status) {
2027 const dev = stack.dev;
2028 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2030 if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 11) && (status == 400)) {
2031 // Check if only the HTTP proxy objects failed
2033 if (responses['IPS_HTTPProxyAccessPoint'].status == 400) { delete responses['IPS_HTTPProxyAccessPoint']; }
2034 if (responses['IPS_HTTPProxyService'].status == 400) { delete responses['IPS_HTTPProxyService']; }
2035 for (var i in responses) { if (responses[i].status != 200) { status = responses[i].status; } }
2038 // If batch enumeration was not succesful, try again.
2039 if (status != 200) {
2040 // If we failed to get the CIRA state, try again up to 5 times.
2041 if (dev.tryCount <= 5) {
2043 var requests = ['*AMT_EnvironmentDetectionSettingData', 'AMT_ManagementPresenceRemoteSAP', 'AMT_RemoteAccessCredentialContext', 'AMT_RemoteAccessPolicyAppliesToMPS', 'AMT_RemoteAccessPolicyRule', '*AMT_UserInitiatedConnectionService', 'AMT_MPSUsernamePassword'];
2044 if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 11)) { requests.push('*IPS_HTTPProxyService', 'IPS_HTTPProxyAccessPoint'); }
2045 dev.amtstack.BatchEnum(null, requests, attemptCiraSyncResponse);
2049 // We tried 5 times, give up.
2050 dev.consoleMsg("Failed to get CIRA state (" + status + ").");
2051 removeAmtDevice(dev, 29);
2055 // Check if CIRA is supported
2056 if ((responses['AMT_UserInitiatedConnectionService'] == null) || (responses['AMT_UserInitiatedConnectionService'].response == null)) {
2057 dev.consoleMsg("This device does not support CIRA.");
2058 devTaskCompleted(dev);
2063 dev.cira.xxRemoteAccess = responses;
2064 dev.cira.xxEnvironementDetection = responses['AMT_EnvironmentDetectionSettingData'].response;
2065 dev.cira.xxEnvironementDetection['DetectionStrings'] = MakeToArray(dev.cira.xxEnvironementDetection['DetectionStrings']);
2066 dev.cira.xxCiraServers = responses['AMT_ManagementPresenceRemoteSAP'].responses;
2067 dev.cira.xxUserInitiatedCira = responses['AMT_UserInitiatedConnectionService'].response;
2068 dev.cira.xxRemoteAccessCredentiaLinks = responses['AMT_RemoteAccessCredentialContext'].responses;
2069 dev.cira.xxMPSUserPass = responses['AMT_MPSUsernamePassword'].responses;
2071 // Set CIRA initiation to BIOS & OS enabled
2072 if (dev.cira.xxUserInitiatedCira['EnabledState'] != 32771) { // 32768: "Disabled", 32769: "BIOS enabled", 32770: "OS enable", 32771: "BIOS & OS enabled"
2073 dev.amtstack.AMT_UserInitiatedConnectionService_RequestStateChange(32771, null, function (stack, name, responses, status) { }); // This is not a critical call.
2076 // Figure out policies attached to servers. Create a policy type to server table.
2077 dev.cira.xxPolicies = { 'User': [], 'Alert': [], 'Periodic': [] };
2078 for (var i in responses['AMT_RemoteAccessPolicyAppliesToMPS'].responses) {
2079 var policy = responses['AMT_RemoteAccessPolicyAppliesToMPS'].responses[i];
2080 var server = Clone(getItem(dev.cira.xxCiraServers, 'Name', getItem(policy['ManagedElement']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'Name')['Value']));
2081 server.MpsType = policy['MpsType']; // MpsType was added in Intel AMT 11.6
2082 var ptype = (getItem(policy['PolicySet']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'PolicyRuleName')['Value']).split(' ')[0];
2083 dev.cira.xxPolicies[ptype].push(server);
2086 // Fetch the server's CIRA settings
2087 dev.cira.mpsPresent = null;
2088 dev.cira.mpsPolicy = false;
2089 if ((dev.policy.ciraPolicy == 2) && (parent.mpsserver.server != null)) { // parent.mpsserver.server is not null if the MPS server is listening for TCP/TLS connections
2090 dev.cira.meshidx = dev.meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X').substring(0, 16);
2091 dev.cira.mpsName = parent.webserver.certificates.AmtMpsName;
2092 var serverNameSplit = dev.cira.mpsName.split('.');
2093 dev.cira.mpsPort = ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport);
2094 dev.cira.mpsAddressFormat = 201; // 201 = FQDN, 3 = IPv4
2095 dev.cira.mpsPass = getRandomAmtPassword();
2096 if ((serverNameSplit.length == 4) && (parseInt(serverNameSplit[0]) == serverNameSplit[0]) && (parseInt(serverNameSplit[1]) == serverNameSplit[1]) && (parseInt(serverNameSplit[2]) == serverNameSplit[2]) && (parseInt(serverNameSplit[3]) == serverNameSplit[3])) { dev.cira.mpsAddressFormat = 3; }
2098 // Check if our server is already present
2099 if ((dev.cira.xxCiraServers != null) && (dev.cira.xxCiraServers.length > 0)) {
2100 for (var i = 0; i < dev.cira.xxCiraServers.length; i++) {
2101 var mpsServer = dev.cira.xxCiraServers[i];
2102 if ((mpsServer.AccessInfo == dev.cira.mpsName) && (mpsServer.Port == dev.cira.mpsPort) && (mpsServer.InfoFormat == dev.cira.mpsAddressFormat)) { dev.cira.mpsPresent = mpsServer['Name']; }
2106 // Check if our server is already present
2107 if ((dev.cira.xxPolicies != null) && (dev.cira.xxPolicies['Periodic'].length > 0)) {
2108 var mpsServer = dev.cira.xxPolicies['Periodic'][0];
2109 if ((mpsServer.AccessInfo == dev.cira.mpsName) && (mpsServer.Port == dev.cira.mpsPort) && (mpsServer.InfoFormat == dev.cira.mpsAddressFormat)) { dev.cira.mpsPolicy = true; }
2113 // Remove all MPS policies that are not ours
2114 if (dev.cira.xxPolicies != null) {
2115 if ((dev.cira.xxPolicies['User'] != null) && (dev.cira.xxPolicies['User'].length > 0)) { dev.consoleMsg("Removing CIRA user trigger."); dev.amtstack.Delete('AMT_RemoteAccessPolicyRule', { 'PolicyRuleName': 'User Initiated' }, function (stack, name, responses, status) { }); }
2116 if ((dev.cira.xxPolicies['Alert'] != null) && (dev.cira.xxPolicies['Alert'].length > 0)) { dev.consoleMsg("Removing CIRA alert trigger."); dev.amtstack.Delete('AMT_RemoteAccessPolicyRule', { 'PolicyRuleName': 'Alert' }, function (stack, name, responses, status) { }); }
2117 if ((dev.cira.xxPolicies['Periodic'] != null) && (dev.cira.xxPolicies['Periodic'].length > 0) && (dev.cira.mpsPolicy == false)) { dev.consoleMsg("Removing CIRA periodic trigger."); dev.amtstack.Delete('AMT_RemoteAccessPolicyRule', { 'PolicyRuleName': 'Periodic' }, function (stack, name, responses, status) { }); }
2120 // Remove all MPS servers that are not ours
2121 if ((dev.cira.xxCiraServers != null) && (dev.cira.xxCiraServers.length > 0)) {
2122 for (var i = 0; i < dev.cira.xxCiraServers.length; i++) {
2123 var mpsServer = dev.cira.xxCiraServers[i];
2124 if ((mpsServer.AccessInfo != dev.cira.mpsName) || (mpsServer.Port != dev.cira.mpsPort) || (mpsServer.InfoFormat != dev.cira.mpsAddressFormat)) {
2125 dev.consoleMsg("Removing MPS server.");
2126 dev.amtstack.Delete('AMT_ManagementPresenceRemoteSAP', { 'Name': mpsServer['Name'] }, function (stack, name, responses, status) { });
2131 // If we need to setup CIRA, start by checking the MPS server
2132 // parent.mpsserver.server is not null if the MPS server is listening for TCP/TLS connections
2133 if ((dev.policy.ciraPolicy == 2) && (parent.mpsserver.server != null)) { addMpsServer(dev); } else { checkEnvironmentDetection(dev); }
2136 function addMpsServer(dev) {
2137 // Add the MPS server if not present
2138 if (dev.cira.mpsPresent == null) {
2139 dev.amtstack.AMT_RemoteAccessService_AddMpServer(dev.cira.mpsName, dev.cira.mpsAddressFormat, dev.cira.mpsPort, 2, null, dev.cira.meshidx, dev.cira.mpsPass, dev.cira.mpsName, function (stack, name, response, status) {
2140 const dev = stack.dev;
2141 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2142 if (status != 200) { dev.consoleMsg("Failed to create new MPS server (" + status + ")."); removeAmtDevice(dev, 31); return; }
2143 if ((response.Body.MpServer == null) || (response.Body.MpServer.ReferenceParameters == null) || (response.Body.MpServer.ReferenceParameters.SelectorSet == null) || (response.Body.MpServer.ReferenceParameters.SelectorSet.Selector == null)) { dev.consoleMsg("Create new MPS server invalid response."); removeAmtDevice(dev, 32); return; }
2144 dev.cira.mpsPresent = getItem(response.Body.MpServer.ReferenceParameters.SelectorSet.Selector, '@Name', 'Name').Value;
2145 dev.consoleMsg("Created new MPS server.");
2148 // Update the device with the MPS password
2149 dev.aquired.mpspass = dev.cira.mpsPass;
2153 // MPS server is present, check MPS trigger policy
2158 function addMpsPolicy(dev) {
2159 if (dev.cira.mpsPolicy == false) {
2160 var cilaSupport = ((dev.aquired.majorver != null) && (dev.aquired.minorver != null)) && ((dev.aquired.majorver > 11) || ((dev.aquired.majorver == 11) && (dev.aquired.minorver >= 6)));
2161 var trigger = 2; // 1 = Alert, 2 = Periodic
2163 // Setup extended data
2164 var extendedData = null;
2166 var timertype = 0; // 0 = Periodic, 1 = Time of day
2167 var exdata = IntToStr(10); // Interval trigger, 10 seconds
2168 extendedData = Buffer.from(IntToStr(timertype) + exdata, 'binary').toString('base64');
2171 // Create the MPS server references
2172 var server1 = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://intel.com/wbem/wscim/1/amt-schema/1/AMT_ManagementPresenceRemoteSAP</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="Name">' + dev.cira.mpsPresent + '</Selector></SelectorSet></ReferenceParameters>';
2175 // Put the CIRA/CILA servers in the right bins.
2176 var ciraServers = [], cilaServers = [];
2177 if (server1) { ciraServers.push(server1); if (server2) { ciraServers.push(server2); } }
2179 // Go ahead and create the new CIRA/CILA policy.
2180 dev.amtstack.AMT_RemoteAccessService_AddRemoteAccessPolicyRule(trigger, 0, extendedData, ciraServers, cilaServers, function (stack, name, responses, status) {
2181 const dev = stack.dev;
2182 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2183 if (status != 200) { dev.consoleMsg("Failed to create new MPS policy (" + status + ")."); removeAmtDevice(dev, 33); return; }
2184 dev.consoleMsg("Created new MPS policy.");
2185 checkEnvironmentDetection(dev);
2188 checkEnvironmentDetection(dev);
2192 function checkEnvironmentDetection(dev) {
2193 var changes = false;
2194 var editEnvironmentDetectionTmp = [];
2195 var currentEnvDetect = dev.cira.xxEnvironementDetection['DetectionStrings'];
2196 if (currentEnvDetect == null) { currentEnvDetect = []; }
2198 if ((dev.policy.ciraPolicy == 2) && (parent.mpsserver.server != null)) { // ciraPolicy: 0 = Do Nothing, 1 = Clear, 2 = Set
2199 const newEnvDetect = parent.config.domains[dev.domainid].amtmanager.environmentdetection;
2200 if (newEnvDetect == null) {
2201 // If no environment detection is specified in the config.json, check that we have a random environment detection
2202 if (currentEnvDetect.length == 0) { editEnvironmentDetectionTmp = [ Buffer.from(parent.crypto.randomBytes(6), 'binary').toString('hex') ]; changes = true; }
2204 // Check that we have exactly the correct environement detection suffixes
2205 var mismatch = false;
2206 if (currentEnvDetect.length != newEnvDetect.length) {
2209 // Check if everything matches
2210 for (var i in currentEnvDetect) { if (newEnvDetect.indexOf(currentEnvDetect[i]) == -1) { mismatch = true; } }
2211 for (var i in newEnvDetect) { if (currentEnvDetect.indexOf(newEnvDetect[i]) == -1) { mismatch = true; } }
2213 // If not, we need to set the new ones
2214 if (mismatch == true) { editEnvironmentDetectionTmp = newEnvDetect; changes = true; }
2217 } else if ((dev.policy.ciraPolicy == 1) || (parent.mpsserver.server == null)) {
2218 // Check environment detection is clear
2219 if (currentEnvDetect.length != 0) { editEnvironmentDetectionTmp = []; changes = true; }
2222 // If we need to change the environment detection on the remote device, do it now.
2223 if (changes == true) {
2224 var t = Clone(dev.cira.xxEnvironementDetection);
2225 t['DetectionStrings'] = editEnvironmentDetectionTmp;
2226 dev.cira.envclear = (editEnvironmentDetectionTmp.length == 0);
2227 dev.amtstack.Put('AMT_EnvironmentDetectionSettingData', t, function (stack, name, responses, status) {
2228 const dev = stack.dev;
2229 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2230 if (status != 200) { dev.consoleMsg("Failed to set environement detection (" + status + ")."); removeAmtDevice(dev, 34); return; }
2231 if (dev.cira.envclear) { dev.consoleMsg("Environment detection cleared."); } else { dev.consoleMsg("Environment detection set."); }
2232 devTaskCompleted(dev);
2235 devTaskCompleted(dev);
2241 // Intel AMT Settings
2244 function attemptSettingsSync(dev, func) {
2245 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2246 if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
2248 dev.taskCompleted = func;
2250 // Query the things we are going to be checking
2251 var query = ['*AMT_GeneralSettings', '*AMT_RedirectionService'];
2252 if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 5)) { query.push('*CIM_KVMRedirectionSAP', '*IPS_OptInService'); }
2253 dev.amtstack.BatchEnum('', query, attemptSettingsSyncResponse);
2256 function attemptSettingsSyncResponse(stack, name, responses, status) {
2257 const dev = stack.dev;
2258 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2259 if (status != 200) { devTaskCompleted(dev); return; }
2261 // If this device does not have KVM, ignore the response. This can happen for Intel Standard Manageability (Intel(R) SM).
2262 if ((responses['CIM_KVMRedirectionSAP'] == null) || (responses['CIM_KVMRedirectionSAP'].status == 400)) { responses['CIM_KVMRedirectionSAP'] = null; }
2264 // Set user consent requirement to match device group user consent
2265 const mesh = parent.webserver.meshes[dev.meshid];
2266 if (mesh == null) { removeAmtDevice(dev, 35); return; }
2267 const userConsentRequirement = ((typeof mesh.consent == 'number') && ((mesh.consent & 8) != 0)) ? 1 : 0; // Enable user consent for KVM if device group desktop "Prompt for user consent" is enabled.
2269 // Check user consent requirements
2270 if ((responses['IPS_OptInService'] != null) && (responses['IPS_OptInService'].response['OptInRequired'] != userConsentRequirement)) {
2271 responses['IPS_OptInService'].response['OptInRequired'] = userConsentRequirement; // 0 = Not Required, 1 = Required for KVM only, 0xFFFFFFFF = Always Required
2272 dev.amtstack.Put('IPS_OptInService', responses['IPS_OptInService'].response, function (stack, name, responses, status) {
2273 const dev = stack.dev;
2274 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2275 if (status == 200) {
2276 if (userConsentRequirement == 0) {
2277 dev.consoleMsg("Cleared user consent requirements.");
2278 } else if (userConsentRequirement == 1) {
2279 dev.consoleMsg("Enabled KVM user consent requirement.");
2280 } else if (userConsentRequirement == 0xFFFFFFFF) {
2281 dev.consoleMsg("Enabled all user consent requirement.");
2287 // Enable SOL & IDER
2288 if ((responses['AMT_RedirectionService'].response['EnabledState'] != 32771) || (responses['AMT_RedirectionService'].response['ListenerEnabled'] == false)) {
2289 dev.redirObj = responses['AMT_RedirectionService'].response;
2290 dev.redirObj['ListenerEnabled'] = true;
2291 dev.redirObj['EnabledState'] = 32771;
2293 dev.amtstack.AMT_RedirectionService_RequestStateChange(32771,
2294 function (stack, name, response, status) {
2295 const dev = stack.dev;
2296 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2297 dev.amtstack.Put('AMT_RedirectionService', dev.redirObj, function (stack, name, response, status) {
2298 const dev = stack.dev;
2299 delete dev.redirObj;
2300 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2301 if (status == 200) { dev.consoleMsg("Enabled redirection features."); }
2302 devTaskCompleted(dev);
2309 if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 5) && (responses['CIM_KVMRedirectionSAP'] != null)) {
2310 const kvm = ((responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 2) || (responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 6));
2314 dev.amtstack.CIM_KVMRedirectionSAP_RequestStateChange(2, 0,
2315 function (stack, name, response, status) {
2316 const dev = stack.dev;
2317 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2318 if (status == 200) { dev.consoleMsg("Enabled KVM."); }
2319 devTaskCompleted(dev);
2325 // Check device name and domain name
2326 if ((dev.connType == 2) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
2327 const generalSettings = responses['AMT_GeneralSettings'].response;
2328 if ((generalSettings['HostName'] != dev.mpsConnection.tag.meiState.OsHostname) || (generalSettings['DomainName'] != dev.mpsConnection.tag.meiState.OsDnsSuffix)) {
2329 // Change the computer and domain name
2330 generalSettings['HostName'] = dev.mpsConnection.tag.meiState.OsHostname;
2331 generalSettings['DomainName'] = dev.mpsConnection.tag.meiState.OsDnsSuffix;
2333 dev.xname = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
2334 dev.amtstack.Put('AMT_GeneralSettings', generalSettings, function () {
2335 const dev = stack.dev;
2336 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2337 if (status == 200) { dev.consoleMsg("Changed device name: " + dev.xname); }
2339 devTaskCompleted(dev);
2345 devTaskCompleted(dev);
2350 // Intel AMT Certificate cleanup
2353 // Remove any unused, non-trusted certificates
2354 function attemptCleanCertsSync(dev, func) {
2355 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2356 dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', 'AMT_PublicPrivateKeyPair'], function (stack, name, responses, status) {
2357 const dev = stack.dev;
2358 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2359 const domain = parent.config.domains[dev.domainid];
2360 if ((responses['AMT_PublicKeyCertificate'].status != 200) || (responses['AMT_PublicPrivateKeyPair'].status != 200)) { func(dev); return; } // We can't get the certificate list, fail and carry on.
2361 if ((responses['AMT_PublicKeyCertificate'].responses.length == 0) || (responses['AMT_PublicPrivateKeyPair'].responses.length == 0)) { func(dev); return; } // Empty certificate list, fail and carry on.
2363 // Sort out the certificates
2364 var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
2365 var xxCertPrivateKeys = responses['AMT_PublicPrivateKeyPair'].responses;
2366 for (var i in xxCertificates) {
2367 xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
2368 xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
2369 xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
2370 xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
2372 amtcert_linkCertPrivateKey(xxCertificates, xxCertPrivateKeys); // This links all certificates and private keys
2373 dev.certDeleteTasks = 0;
2375 // Remove any unlinked private keys
2376 for (var i in xxCertPrivateKeys) {
2377 if (!xxCertPrivateKeys[i].XCert) {
2378 dev.certDeleteTasks++;
2379 dev.amtstack.Delete('AMT_PublicPrivateKeyPair', { 'InstanceID': xxCertPrivateKeys[i]['InstanceID'] }, function (stack, name, response, status) {
2380 //if (status == 200) { dev.consoleMsg("Removed unassigned private key pair."); }
2381 if (--dev.certDeleteTasks == 0) { delete dev.certDeleteTasks; func(dev); }
2386 // Try to remove all untrusted certificates
2387 for (var i in xxCertificates) {
2388 if (xxCertificates[i].TrustedRootCertficate == false) {
2389 var privateKeyInstanceId = null;
2390 if (xxCertificates[i].XPrivateKey) { privateKeyInstanceId = { 'InstanceID': xxCertificates[i].XPrivateKey['InstanceID'] }; }
2391 dev.certDeleteTasks++;
2392 dev.amtstack.Delete('AMT_PublicKeyCertificate', { 'InstanceID': xxCertificates[i]['InstanceID'] }, function (stack, name, response, status, tag) {
2393 if ((status == 200) && (tag != null)) {
2394 // If there is a private key, delete it.
2395 dev.amtstack.Delete('AMT_PublicPrivateKeyPair', tag, function () {
2396 if (--dev.certDeleteTasks == 0) { delete dev.certDeleteTasks; func(dev); }
2399 if (--dev.certDeleteTasks == 0) { delete dev.certDeleteTasks; func(dev); }
2401 }, privateKeyInstanceId);
2409 // Intel AMT Hardware Inventory and Networking
2412 function attemptFetchHardwareInventory(dev, func) {
2413 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2414 const mesh = parent.webserver.meshes[dev.meshid];
2415 if (mesh == null) { removeAmtDevice(dev, 35); return; }
2416 if (mesh.mtype == 1) { // If this is a Intel AMT only device group, pull the hardware inventory and network information for this device
2417 dev.consoleMsg("Fetching hardware inventory.");
2419 dev.taskCompleted = func;
2420 dev.amtstack.BatchEnum('', ['*CIM_ComputerSystemPackage', 'CIM_SystemPackaging', '*CIM_Chassis', 'CIM_Chip', '*CIM_Card', '*CIM_BIOSElement', 'CIM_Processor', 'CIM_PhysicalMemory', 'CIM_MediaAccessDevice', 'CIM_PhysicalPackage'], attemptFetchHardwareInventoryResponse);
2421 dev.amtstack.BatchEnum('', ['AMT_EthernetPortSettings'], attemptFetchNetworkResponse);
2423 if (func) { func(dev); }
2427 function attemptFetchNetworkResponse(stack, name, responses, status) {
2428 const dev = stack.dev;
2429 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2430 if (status != 200) { devTaskCompleted(dev); return; }
2432 //console.log(JSON.stringify(responses, null, 2));
2433 if ((responses['AMT_EthernetPortSettings'] == null) || (responses['AMT_EthernetPortSettings'].responses == null)) { devTaskCompleted(dev); return; }
2435 // Find the wired and wireless interfaces
2436 var wired = null, wireless = null;
2437 for (var i in responses['AMT_EthernetPortSettings'].responses) {
2438 var netif = responses['AMT_EthernetPortSettings'].responses[i];
2439 if ((netif.MACAddress != null) && (netif.MACAddress != '00-00-00-00-00-00')) {
2440 if (netif.WLANLinkProtectionLevel != null) { wireless = netif; } else { wired = netif; }
2443 if ((wired == null) && (wireless == null)) { devTaskCompleted(dev); return; }
2445 // Sent by the agent to update agent network interface information
2446 var net = { netif2: {} };
2448 if (wired != null) {
2451 x.type = 'ethernet';
2452 x.address = wired.IPAddress;
2453 x.netmask = wired.SubnetMask;
2454 x.mac = wired.MACAddress.split('-').join(':').toUpperCase();
2455 x.gateway = wired.DefaultGateway;
2456 net.netif2['Ethernet'] = [x];
2459 if (wireless != null) {
2462 x.type = 'wireless';
2463 x.address = wireless.IPAddress;
2464 x.netmask = wireless.SubnetMask;
2465 x.mac = wireless.MACAddress.split('-').join(':').toUpperCase();
2466 x.gateway = wireless.DefaultGateway;
2467 net.netif2['Wireless'] = [x];
2470 net.updateTime = Date.now();
2471 net._id = 'if' + dev.nodeid;
2472 net.type = 'ifinfo';
2475 // Event the node interface information change
2476 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, { action: 'ifchange', nodeid: dev.nodeid, domain: dev.nodeid.split('/')[1], nolog: 1 });
2478 devTaskCompleted(dev);
2483 // http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
2484 const DMTFCPUStatus = ["Unknown", "Enabled", "Disabled by User", "Disabled By BIOS (POST Error)", "Idle", "Other"];
2485 const DMTFMemType = ["Unknown", "Other", "DRAM", "Synchronous DRAM", "Cache DRAM", "EDO", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "Flash", "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM", "DDR", "DDR-2", "BRAM", "FB-DIMM", "DDR3", "FBD2", "DDR4", "LPDDR", "LPDDR2", "LPDDR3", "LPDDR4"];
2486 const DMTFMemFormFactor = ['', "Other", "Unknown", "SIMM", "SIP", "Chip", "DIP", "ZIP", "Proprietary Card", "DIMM", "TSOP", "Row of chips", "RIMM", "SODIMM", "SRIMM", "FB-DIM"];
2487 const DMTFProcFamilly = { // Page 46 of DMTF document
2488 191: "Intel® Core™ 2 Duo Processor",
2489 192: "Intel® Core™ 2 Solo processor",
2490 193: "Intel® Core™ 2 Extreme processor",
2491 194: "Intel® Core™ 2 Quad processor",
2492 195: "Intel® Core™ 2 Extreme mobile processor",
2493 196: "Intel® Core™ 2 Duo mobile processor",
2494 197: "Intel® Core™ 2 Solo mobile processor",
2495 198: "Intel® Core™ i7 processor",
2496 199: "Dual-Core Intel® Celeron® processor"
2500 function attemptFetchHardwareInventoryResponse(stack, name, responses, status) {
2501 const dev = stack.dev;
2502 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2503 if (status != 200) { devTaskCompleted(dev); return; }
2505 // Extract basic data
2507 hw.PlatformGUID = responses['CIM_ComputerSystemPackage'].response.PlatformGUID;
2508 hw.Chassis = responses['CIM_Chassis'].response;
2509 hw.Chips = responses['CIM_Chip'].responses;
2510 hw.Card = responses['CIM_Card'].response;
2511 hw.Bios = responses['CIM_BIOSElement'].response;
2512 hw.Processors = responses['CIM_Processor'].responses;
2513 hw.PhysicalMemory = responses['CIM_PhysicalMemory'].responses;
2514 hw.MediaAccessDevice = responses['CIM_MediaAccessDevice'].responses;
2515 hw.PhysicalPackage = responses['CIM_PhysicalPackage'].responses;
2517 // Convert the hardware data into the same structure as we get from Windows
2518 var hw2 = { hardware: { windows: {}, identifiers: {} } };
2519 hw2.hardware.identifiers.product_uuid = guidToStr(hw.PlatformGUID);
2520 if ((hw.PhysicalMemory != null) && (hw.PhysicalMemory.length > 0)) {
2522 for (var i in hw.PhysicalMemory) {
2523 var m2 = {}, m = hw.PhysicalMemory[i];
2524 m2.BankLabel = m.BankLabel;
2525 m2.Capacity = m.Capacity;
2526 if (typeof m.PartNumber == 'string') { m2.PartNumber = m.PartNumber.trim(); }
2527 if (typeof m.PartNumber == 'number') { m2.PartNumber = m.PartNumber; }
2528 if (typeof m.SerialNumber == 'string') { m2.SerialNumber = m.SerialNumber.trim(); }
2529 if (typeof m.SerialNumber == 'number') { m2.SerialNumber = m.SerialNumber; }
2530 if (typeof m.Manufacturer == 'string') { m2.Manufacturer = m.Manufacturer.trim(); }
2531 if (typeof m.Manufacturer == 'number') { m2.Manufacturer = m.Manufacturer; }
2534 hw2.hardware.windows.memory = memory;
2536 if ((hw.MediaAccessDevice != null) && (hw.MediaAccessDevice.length > 0)) {
2538 for (var i in hw.MediaAccessDevice) {
2539 var m2 = {}, m = hw.MediaAccessDevice[i];
2540 m2.Caption = m.DeviceID;
2541 if (m.MaxMediaSize) { m2.Size = (m.MaxMediaSize * 1000); }
2544 hw2.hardware.identifiers.storage_devices = drives;
2546 if (hw.Bios != null) {
2547 if (typeof hw.Bios.Manufacturer == 'string') { hw2.hardware.identifiers.bios_vendor = hw.Bios.Manufacturer.trim(); }
2548 if (typeof hw.Bios.Manufacturer == 'number') { hw2.hardware.identifiers.bios_vendor = hw.Bios.Manufacturer; }
2549 hw2.hardware.identifiers.bios_version = hw.Bios.Version;
2550 if (hw.Bios.ReleaseDate && hw.Bios.ReleaseDate.Datetime) { hw2.hardware.identifiers.bios_date = hw.Bios.ReleaseDate.Datetime; }
2552 if (hw.PhysicalPackage != null) {
2553 if (typeof hw.Card.Model == 'string') { hw2.hardware.identifiers.board_name = hw.Card.Model.trim(); }
2554 if (typeof hw.Card.Model == 'number') { hw2.hardware.identifiers.board_name = hw.Card.Model; }
2555 if (typeof hw.Card.Manufacturer == 'string') { hw2.hardware.identifiers.board_vendor = hw.Card.Manufacturer.trim(); }
2556 if (typeof hw.Card.Manufacturer == 'number') { hw2.hardware.identifiers.board_vendor = hw.Card.Manufacturer; }
2557 if (typeof hw.Card.Version == 'string') { hw2.hardware.identifiers.board_version = hw.Card.Version.trim(); }
2558 if (typeof hw.Card.Version == 'number') { hw2.hardware.identifiers.board_version = hw.Card.Version; }
2559 if (typeof hw.Card.SerialNumber == 'string') { hw2.hardware.identifiers.board_serial = hw.Card.SerialNumber.trim(); }
2560 if (typeof hw.Card.SerialNumber == 'number') { hw2.hardware.identifiers.board_serial = hw.Card.SerialNumber; }
2562 if ((hw.Chips != null) && (hw.Chips.length > 0)) {
2563 for (var i in hw.Chips) {
2564 if ((hw.Chips[i].ElementName == 'Managed System Processor Chip') && (hw.Chips[i].Version)) {
2565 hw2.hardware.identifiers.cpu_name = hw.Chips[i].Version;
2570 // Compute the hash of the document
2571 hw2.hash = parent.crypto.createHash('sha384').update(JSON.stringify(hw2)).digest().toString('hex');
2573 // Fetch system information
2574 parent.db.GetHash('si' + dev.nodeid, function (err, results) {
2575 var sysinfohash = null;
2576 if ((results != null) && (results.length == 1)) { sysinfohash = results[0].hash; }
2577 if (sysinfohash != hw2.hash) {
2578 // Hardware information has changed, update the database
2579 hw2._id = 'si' + dev.nodeid;
2580 hw2.domain = dev.nodeid.split('/')[1];
2581 hw2.time = Date.now();
2582 hw2.type = 'sysinfo';
2585 // Event the new sysinfo hash, this will notify everyone that the sysinfo document was changed
2586 var event = { etype: 'node', action: 'sysinfohash', nodeid: dev.nodeid, domain: hw2.domain, hash: hw2.hash, nolog: 1 };
2587 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, event);
2591 devTaskCompleted(dev);
2596 // Intel AMT Activation
2599 function activateIntelAmt(dev) {
2600 // Find the Intel AMT policy
2601 const mesh = parent.webserver.meshes[dev.meshid];
2602 if (mesh == null) { dev.consoleMsg("Unable to find device group (" + dev.meshid + ")."); removeAmtDevice(dev, 36); return false; }
2603 var amtPolicy = 0; // 0 = Do nothing, 1 = Deactivate CCM, 2 = CCM, 3 = ACM
2604 var ccmPolicy = 0; // Only used when in ACM policy: 0 = Do nothing, 1 = Deactivate CCM, 2 = CCM is ACM fails
2605 if (mesh.amt != null) { if (typeof mesh.amt.type == 'number') { amtPolicy = mesh.amt.type; } if (typeof mesh.amt.ccm == 'number') { ccmPolicy = mesh.amt.ccm; } }
2606 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; }
2607 if (amtPolicy == 0) { removeAmtDevice(dev, 37); return false; } // Do nothing, we should not have gotten this CIRA-LMS connection.
2608 if (amtPolicy == 2) { activateIntelAmtCcm(dev, mesh.amt.password); } // Activate to CCM policy
2609 if ((amtPolicy == 3) || (amtPolicy == 4)) { // Activate to ACM policy
2610 var acminfo = checkAcmActivation(dev);
2611 if ((acminfo == null) || (acminfo.err != null)) {
2612 // No opportunity to activate to ACM, check if we are in CCM
2613 if ((dev.mpsConnection.tag.meiState.Flags & 2) != 0) {
2614 if ((amtPolicy == 3) && (ccmPolicy == 1)) { deactivateIntelAmtCCM(dev); } // If we are in ACM policy and CCM is not allowed, deactivate it now.
2615 else { return true; } // We are in CCM, keep going
2617 // We are not in CCM, go to CCM now
2618 if ((amtPolicy == 4) || ((amtPolicy == 3) && (ccmPolicy == 2))) { activateIntelAmtCcm(dev, mesh.amt.password); } // If we are in full automatic or ACM with CCM allowed, setup CCM.
2620 // Unable to find an activation match.
2621 if (acminfo == null) { dev.consoleMsg("No opportunity for ACM activation."); } else { dev.consoleMsg("No opportunity for ACM activation: " + acminfo.err); }
2622 removeAmtDevice(dev, 38);
2623 return false; // We are not in CCM and policy restricts use of CCM, so exit now.
2627 // Found a certificate to activate to ACM.
2628 if ((dev.mpsConnection.tag.meiState.Flags & 2) != 0) {
2629 // We are in CCM, deactivate CCM first.
2630 deactivateIntelAmtCCM(dev);
2632 // We are not activated now, go to ACM directly.
2633 // Check if we are allowed to perform TLS ACM activation
2634 var TlsAcmActivation = false;
2635 var domain = parent.config.domains[dev.domainid];
2636 if (domain && domain.amtmanager && (domain.amtmanager.tlsacmactivation == true)) { TlsAcmActivation = true; }
2638 // Check Intel AMT version
2639 if (typeof dev.intelamt.ver == 'string') {
2640 var verSplit = dev.intelamt.ver.split('.');
2641 if (verSplit.length >= 2) {
2642 dev.aquired.majorver = parseInt(verSplit[0]);
2643 dev.aquired.minorver = parseInt(verSplit[1]);
2644 if (verSplit.length >= 3) { dev.aquired.maintenancever = parseInt(verSplit[2]); }
2648 // If this is Intel AMT 14 or better and allowed, we are going to attempt a host-based end-to-end TLS activation.
2649 if (TlsAcmActivation && (dev.aquired.majorver >= 14)) {
2650 // Perform host-based TLS ACM activation
2651 activateIntelAmtTlsAcm(dev, mesh.amt.password, acminfo);
2653 // Perform host-based ACM activation
2654 activateIntelAmtAcm(dev, mesh.amt.password, acminfo);
2662 function activateIntelAmtCcm(dev, password) {
2663 // Generate a random Intel AMT password if needed
2664 if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
2665 dev.temp = { pass: password };
2667 // Setup the WSMAN stack, no TLS
2668 var comm = CreateWsmanComm(dev.nodeid, 16992, dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass, 0, null, dev.mpsConnection); // No TLS
2669 var wsstack = WsmanStackCreateService(comm);
2670 dev.amtstack = AmtStackCreateService(wsstack);
2671 dev.amtstack.dev = dev;
2672 dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtCcmEx1);
2675 function activateIntelAmtCcmEx1(stack, name, responses, status) {
2676 const dev = stack.dev;
2677 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2678 if (status != 200) { dev.consoleMsg("Failed to get Intel AMT state."); removeAmtDevice(dev, 39); return; }
2679 if (responses['IPS_HostBasedSetupService'].response['AllowedControlModes'].length != 2) { dev.consoleMsg("Client control mode activation not allowed."); removeAmtDevice(dev, 40); return; }
2681 // Log the activation request, logging is a required step for activation.
2682 var domain = parent.config.domains[dev.domainid];
2683 if (domain == null) { dev.consoleMsg("Invalid domain."); removeAmtDevice(dev, 41); return; }
2684 if (parent.certificateOperations.logAmtActivation(domain, { time: new Date(), action: 'ccmactivate', domain: dev.domainid, amtUuid: dev.mpsConnection.tag.meiState.UUID, amtRealm: responses['AMT_GeneralSettings'].response['DigestRealm'], user: 'admin', password: dev.temp.pass, ipport: dev.mpsConnection.remoteAddr + ':' + dev.mpsConnection.remotePort, nodeid: dev.nodeid, meshid: dev.meshid, computerName: dev.name }) == false) {
2685 dev.consoleMsg("Unable to log operation."); removeAmtDevice(dev, 42); return;
2688 // Perform CCM activation
2689 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);
2692 function activateIntelAmtCcmEx2(stack, name, responses, status) {
2693 const dev = stack.dev;
2694 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2695 if (status != 200) { dev.consoleMsg("Failed to activate Intel AMT to CCM."); removeAmtDevice(dev, 43); return; }
2697 // Update the device
2699 dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM
2700 if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') {
2701 var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
2702 if (verSplit.length >= 2) {
2703 dev.aquired.version = verSplit[0] + '.' + verSplit[1];
2704 dev.aquired.majorver = parseInt(verSplit[0]);
2705 dev.aquired.minorver = parseInt(verSplit[1]);
2706 if (verSplit.length >= 3) {
2707 dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
2708 dev.aquired.maintenancever = parseInt(verSplit[2]);
2712 if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
2713 dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
2715 dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm;
2716 dev.intelamt.user = dev.aquired.user = 'admin';
2717 dev.intelamt.pass = dev.aquired.pass = dev.temp.pass;
2718 dev.intelamt.tls = dev.aquired.tls = 0;
2719 dev.aquired.lastContact = Date.now();
2720 dev.aquired.state = 2; // Activated
2721 dev.aquired.warn = 0; // Clear all warnings
2726 // Success, switch to managing this device
2727 obj.parent.mpsserver.SendJsonControl(dev.mpsConnection, { action: 'mestate' }); // Request an MEI state refresh
2728 dev.consoleMsg("Succesfully activated in CCM mode, holding 10 seconds...");
2730 // Wait 10 seconds before attempting to manage this device in CCM
2731 var f = function doManage() { if (isAmtDeviceValid(dev)) { attemptInitialContact(doManage.dev); } }
2733 setTimeout(f, 10000);
2736 // Check if this device has any way to be activated in ACM using our server certificates.
2737 function checkAcmActivation(dev) {
2738 var domain = parent.config.domains[dev.domainid];
2739 if ((domain == null) || (domain.amtacmactivation == null) || (domain.amtacmactivation.certs == null) || (domain.amtacmactivation.certs.length == 0)) return { err: "Server does not have any ACM activation certificates." };
2740 const activationCerts = domain.amtacmactivation.certs;
2741 if ((dev.mpsConnection.tag.meiState == null) || (dev.mpsConnection.tag.meiState.Hashes == null) || (dev.mpsConnection.tag.meiState.Hashes.length == 0)) return { err: "Intel AMT did not report any trusted hashes." };
2742 const deviceHashes = dev.mpsConnection.tag.meiState.Hashes;
2744 // Get the trusted FQDN of the device
2745 var trustedFqdn = null;
2746 if (dev.mpsConnection.tag.meiState.OsDnsSuffix != null) { trustedFqdn = dev.mpsConnection.tag.meiState.OsDnsSuffix; }
2747 if (dev.mpsConnection.tag.meiState.DnsSuffix != null) { trustedFqdn = dev.mpsConnection.tag.meiState.DnsSuffix; }
2748 if (trustedFqdn == null) return { err: "No trusted DNS suffix reported" };
2750 // Find a matching certificate
2751 var gotSuffixMatch = false;
2752 var devValidHash = false;
2753 for (var i in activationCerts) {
2754 var cert = activationCerts[i];
2755 var certDnsMatch = checkAcmActivationCertName(cert.cn, trustedFqdn);
2756 if (certDnsMatch == true) { gotSuffixMatch = true; }
2757 if ((cert.cn == '*') || certDnsMatch) {
2758 for (var j in deviceHashes) {
2759 var hashInfo = deviceHashes[j];
2760 if ((hashInfo != null) && (hashInfo.isActive == 1)) {
2761 devValidHash = true;
2762 if ((hashInfo.hashAlgorithmStr == 'SHA256') && (hashInfo.certificateHash.toLowerCase() == cert.sha256)) { return { cert: cert, fqdn: trustedFqdn, hash: cert.sha256 }; } // Found a match
2763 else if ((hashInfo.hashAlgorithmStr == 'SHA1') && (hashInfo.certificateHash.toLowerCase() == cert.sha1)) { return { cert: cert, fqdn: trustedFqdn, hash: cert.sha1 }; } // Found a match
2768 if (!devValidHash) { return { err: "Intel AMT has no trusted root hashes for \"" + trustedFqdn + "\"." }; } // Found no trusted root hashes
2769 if (gotSuffixMatch) { return { err: "Certificate root hash matching failed for \"" + trustedFqdn + "\"." }; } // Found a DNS suffix match, but root hash failed to match.
2770 return { err: "No matching ACM activation certificate for \"" + trustedFqdn + "\"." }; // Did not find a match
2773 // Return true if the trusted FQDN matched the certificate common name
2774 function checkAcmActivationCertName(commonName, trustedFqdn) {
2775 commonName = commonName.toLowerCase();
2776 trustedFqdn = trustedFqdn.toLowerCase();
2777 if (commonName.startsWith('*.') && (commonName.length > 2)) { commonName = commonName.substring(2); }
2778 return ((commonName == trustedFqdn) || (trustedFqdn.endsWith('.' + commonName)));
2781 // Attempt Intel AMT TLS ACM activation
2782 function activateIntelAmtTlsAcm(dev, password, acminfo) {
2783 // Check if MeshAgent/MeshCMD can support the startConfigurationhostB() call.
2784 if ((dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (typeof dev.mpsConnection.tag.meiState['core-ver'] == 'number') && (dev.mpsConnection.tag.meiState['core-ver'] > 0)) {
2785 // Generate a random Intel AMT password if needed
2786 if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
2787 dev.temp = { pass: password, acminfo: acminfo };
2789 // Get our ACM activation certificate chain
2790 var acmTlsInfo = parent.certificateOperations.getAcmCertChain(parent.config.domains[dev.domainid], dev.temp.acminfo.fqdn, dev.temp.acminfo.hash);
2791 if (acmTlsInfo.error == 1) { dev.consoleMsg(acmTlsInfo.errorText); removeAmtDevice(dev, 44); return; }
2792 dev.acmTlsInfo = acmTlsInfo;
2794 // Send the MEI command to enable TLS connections
2795 dev.consoleMsg("Performing TLS ACM activation...");
2796 dev.controlMsg({ action: 'startTlsHostConfig', hash: acmTlsInfo.hash256, hostVpn: false, dnsSuffixList: null }); // TODO: Use SHA384 is possible.
2798 // MeshCore or MeshCMD is to old
2799 dev.consoleMsg("This software is to old to support ACM activation, pleasse update and try again.");
2800 removeAmtDevice(dev);
2804 // Attempt Intel AMT TLS ACM activation after startConfiguration() is called on remote device
2805 function activateIntelAmtTlsAcmEx(dev, startConfigData) {
2806 if ((startConfigData == null) || (startConfigData.status != 0) || (typeof startConfigData.hash != 'string')) {
2807 // Unable to call startTlsHostConfig on remote host.
2808 dev.consoleMsg("Failed to startConfigurationHBased(), status = " + startConfigData.status);
2809 removeAmtDevice(dev);
2811 // Setup the WSMAN stack, no TLS
2812 dev.consoleMsg("Attempting TLS connection...");
2813 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.
2814 comm.xtlsFingerprint = startConfigData.hash.toLowerCase(); // Intel AMT leaf TLS cert need to match this hash (SHA256 or SHA384)
2815 var wsstack = WsmanStackCreateService(comm);
2816 dev.amtstack = AmtStackCreateService(wsstack);
2817 dev.amtstack.dev = dev;
2818 dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', 'CIM_SoftwareIdentity', '*AMT_SetupAndConfigurationService'], activateIntelAmtTlsAcmEx1);
2822 function activateIntelAmtTlsAcmEx1(stack, name, responses, status) {
2823 const dev = stack.dev;
2824 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2826 // Check if we succesfully connected
2827 if (status != 200) {
2828 dev.consoleMsg("Failed to perform ACM TLS connection, status " + status + ".");
2829 //activateIntelAmtAcm(dev); // It's possible to fallback to legacy WSMAN ACM activation here if we needed to..
2830 removeAmtDevice(dev);
2834 // Fetch the Intel AMT version from WSMAN
2835 if ((responses != null) && (responses['CIM_SoftwareIdentity'] != null) && (responses['CIM_SoftwareIdentity'].responses != null)) {
2836 var amtlogicalelements = [];
2837 amtlogicalelements = responses['CIM_SoftwareIdentity'].responses;
2838 if (responses['AMT_SetupAndConfigurationService'] != null && responses['AMT_SetupAndConfigurationService'].response != null) {
2839 amtlogicalelements.push(responses['AMT_SetupAndConfigurationService'].response);
2841 if (amtlogicalelements.length > 0) {
2842 var vs = getInstance(amtlogicalelements, 'AMT')['VersionString'];
2844 dev.aquired.version = vs;
2845 version = dev.aquired.version.split('.')
2846 dev.aquired.versionmajor = parseInt(version[0]);
2847 dev.aquired.versionminor = parseInt(version[1]);
2848 if (version.length > 2) { dev.aquired.versionmaintenance = parseInt(version[2]); }
2853 // Fetch the Intel AMT version from HTTP stack
2854 if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) {
2855 var s = stack.wsman.comm.amtVersion.split('.');
2856 if (s.length >= 2) {
2857 dev.aquired.version = s[0] + '.' + s[1] + '.';
2858 dev.aquired.versionmajor = parseInt(s[0]);
2859 dev.aquired.versionminor = parseInt(s[1]);
2860 if (s.length >= 3) {
2861 dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
2862 dev.aquired.versionmaintenance = parseInt(s[2]);
2867 // If we can't get the Intel AMT version, stop here.
2868 if (dev.aquired.version == null) { dev.consoleMsg('Could not get Intel AMT version.'); removeAmtDevice(dev); return; } // Could not get Intel AMT version, disconnect();
2870 // Get the digest realm
2871 if (responses['AMT_GeneralSettings'] && responses['AMT_GeneralSettings'].response && (typeof responses['AMT_GeneralSettings'].response['DigestRealm'] == 'string')) {
2872 // Set the realm in the stack since we are not doing HTTP digest and this will be checked later by different code.
2873 dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm = responses['AMT_GeneralSettings'].response['DigestRealm'];
2875 dev.consoleMsg('Could not get Intel AMT digest realm.'); removeAmtDevice(dev); return;
2878 // Looks like we are doing well.
2879 dev.consoleMsg('Succesful TLS connection, Intel AMT v' + dev.aquired.version);
2881 // Log this activation event
2882 var event = { etype: 'node', action: 'amtactivate', nodeid: dev.nodeid, domain: dev.domainid, msgid: 111, msgArgs: [dev.temp.acminfo.fqdn], msg: 'Device requested Intel(R) AMT ACM TLS activation, FQDN: ' + dev.temp.acminfo.fqdn };
2883 if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
2884 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, event);
2886 // Log the activation request, logging is a required step for activation.
2887 var domain = parent.config.domains[dev.domainid];
2888 if (domain == null) { dev.consoleMsg("Invalid domain."); removeAmtDevice(dev, 41); return; }
2889 if (parent.certificateOperations.logAmtActivation(domain, { time: new Date(), action: 'acmactivate-tls', domain: dev.domainid, amtUuid: dev.mpsConnection.tag.meiState.UUID, amtRealm: dev.aquired.realm, user: 'admin', password: dev.temp.pass, ipport: dev.mpsConnection.remoteAddr + ':' + dev.mpsConnection.remotePort, nodeid: dev.nodeid, meshid: dev.meshid, computerName: dev.name }) == false) {
2890 dev.consoleMsg("Unable to log operation."); removeAmtDevice(dev, 42); return;
2893 // See what admin password to use
2894 dev.aquired.user = 'admin';
2895 dev.aquired.pass = dev.temp.password;
2897 // Set the account password
2898 if (typeof dev.temp.mebxpass == 'string') {
2899 // Set the new MEBx password
2900 dev.consoleMsg('Setting MEBx password...');
2901 dev.amtstack.AMT_SetupAndConfigurationService_SetMEBxPassword(dev.temp.mebxpass, activateIntelAmtTlsAcmEx2);
2903 // Set the admin password
2904 dev.consoleMsg('Setting admin password...');
2905 dev.amtstack.AMT_AuthorizationService_SetAdminAclEntryEx(dev.aquired.user, hex_md5(dev.aquired.user + ':' + dev.aquired.realm + ':' + dev.aquired.pass), activateIntelAmtTlsAcmEx3);
2909 // Response from setting MEBx password
2910 function activateIntelAmtTlsAcmEx2(stack, name, responses, status) {
2911 const dev = stack.dev;
2912 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2913 if (status != 200) { dev.consoleMsg('Failed to set MEBx password, status=' + status + '.'); destroyDevice(dev); return; }
2914 dev.consoleMsg('MEBx password set. Setting admin password...');
2916 // Set the admin password
2917 dev.amtstack.AMT_AuthorizationService_SetAdminAclEntryEx(dev.aquired.user, hex_md5(dev.aquired.user + ':' + dev.aquired.realm + ':' + dev.aquired.pass), activateIntelAmtTlsAcmEx3);
2920 // Response from setting admin password
2921 function activateIntelAmtTlsAcmEx3(stack, name, responses, status) {
2922 const dev = stack.dev;
2923 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2924 if (status != 200) { dev.consoleMsg('Failed to set admin password, status=' + status + '.'); removeAmtDevice(dev); return; }
2925 dev.consoleMsg('Admin password set.');
2927 // Switch the state of Intel AMT.
2928 if ((dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null)) { dev.mpsConnection.tag.meiState.ProvisioningState = 2; }
2929 dev.aquired.controlMode = 2; // 1 = CCM, 2 = ACM
2930 dev.aquired.state = 2; // Activated
2931 dev.hbacmtls = 1; // Indicate that we are doing a Host
2933 // Proceed to going the normal Intel AMT sync. This will trigger a commit when the TLS cert is setup.
2934 dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
2937 // Attempt Intel AMT ACM activation
2938 function activateIntelAmtAcm(dev, password, acminfo) {
2939 // Check if MeshAgent/MeshCMD can support the stopConfiguration() call.
2940 if ((dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null) && (typeof dev.mpsConnection.tag.meiState['core-ver'] == 'number') && (dev.mpsConnection.tag.meiState['core-ver'] > 0)) {
2941 // Generate a random Intel AMT password if needed
2942 if (acminfo != null) {
2943 if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
2944 dev.temp = { pass: password, acminfo: acminfo };
2946 dev.acmactivate = 1;
2948 // Send the MEI command to stop configuration.
2949 // If Intel AMT is "in-provisioning" mode, the WSMAN ACM activation will not work, so we need to do this first.
2950 dev.consoleMsg("Getting ready for ACM activation...");
2951 dev.controlMsg({ action: 'stopConfiguration' });
2953 // MeshCore or MeshCMD is to old
2954 dev.consoleMsg("This software is to old to support ACM activation, pleasse update and try again.");
2955 removeAmtDevice(dev);
2959 function activateIntelAmtAcmEx0(dev) {
2960 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2962 // Setup the WSMAN stack, no TLS
2963 var comm = CreateWsmanComm(dev.nodeid, 16992, dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass, 0, null, dev.mpsConnection); // No TLS
2964 var wsstack = WsmanStackCreateService(comm);
2965 dev.amtstack = AmtStackCreateService(wsstack);
2966 dev.amtstack.dev = dev;
2967 dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtAcmEx1);
2970 function activateIntelAmtAcmEx1(stack, name, responses, status) {
2971 const dev = stack.dev;
2972 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
2973 if (status != 200) { dev.consoleMsg("Failed to get Intel AMT state."); removeAmtDevice(dev, 46); return; }
2975 // Sign the Intel AMT ACM activation request
2976 var info = { nonce: responses['IPS_HostBasedSetupService'].response['ConfigurationNonce'], realm: responses['AMT_GeneralSettings'].response['DigestRealm'], fqdn: dev.temp.acminfo.fqdn, hash: dev.temp.acminfo.hash, uuid: dev.mpsConnection.tag.meiState.UUID };
2977 var acmdata = parent.certificateOperations.signAcmRequest(parent.config.domains[dev.domainid], info, 'admin', dev.temp.pass, dev.mpsConnection.remoteAddr + ':' + dev.mpsConnection.remotePort, dev.nodeid, dev.meshid, dev.name, 0);
2978 if (acmdata == null) { dev.consoleMsg("Failed to sign ACM nonce."); removeAmtDevice(dev, 47); return; }
2979 if (acmdata.error != null) { dev.consoleMsg(acmdata.errorText); removeAmtDevice(dev, 48); return; }
2981 // Log this activation event
2982 var event = { etype: 'node', action: 'amtactivate', nodeid: dev.nodeid, domain: dev.domainid, msgid: 58, msgArgs: [ dev.temp.acminfo.fqdn ], msg: 'Device requested Intel(R) AMT ACM activation, FQDN: ' + dev.temp.acminfo.fqdn };
2983 if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
2984 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, event);
2986 // Start the activation process
2987 dev.temp.acmdata = acmdata;
2988 dev.temp.acmdata.index = 0;
2989 dev.consoleMsg("Performing ACM activation...");
2990 activateIntelAmtAcmEx2(dev);
2993 // Recursive function to inject the provisioning certificates into AMT in the proper order and completes ACM activation
2994 function activateIntelAmtAcmEx2(dev) {
2995 var acmdata = dev.temp.acmdata;
2996 var leaf = (acmdata.index == 0), root = (acmdata.index == (acmdata.certs.length - 1));
2997 if ((acmdata.index < acmdata.certs.length) && (acmdata.certs[acmdata.index] != null)) {
2998 dev.amtstack.IPS_HostBasedSetupService_AddNextCertInChain(acmdata.certs[acmdata.index], leaf, root,
2999 function (stack, name, responses, status) {
3000 const dev = stack.dev;
3001 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
3002 if (status != 200) { dev.consoleMsg("Failed to set ACM certificate chain (" + status + ")."); removeAmtDevice(dev, 49); return; }
3003 if (responses['Body']['ReturnValue'] != 0) { dev.consoleMsg("Failed to set ACM certificate chain (ERR/" + responses['Body']['ReturnValue'] + ")."); removeAmtDevice(dev, 50); return; }
3005 // Move to the next activation operation
3006 dev.temp.acmdata.index++;
3007 activateIntelAmtAcmEx2(dev);
3011 dev.amtstack.IPS_HostBasedSetupService_AdminSetup(2, acmdata.password, acmdata.nonce, 2, acmdata.signature,
3012 function (stack, name, responses, status) {
3013 const dev = stack.dev;
3014 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
3015 if (status != 200) { dev.consoleMsg("Failed to complete ACM activation (" + status + ")."); removeAmtDevice(dev, 51); return; }
3016 if (responses['Body']['ReturnValue'] != 0) { dev.consoleMsg("Failed to complete ACM activation (ERR/" + responses['Body']['ReturnValue'] + ")."); removeAmtDevice(dev, 52); return; }
3018 // Success, switch to managing this device
3019 obj.parent.mpsserver.SendJsonControl(dev.mpsConnection, { action: 'mestate' }); // Request an MEI state refresh
3020 dev.consoleMsg("Succesfully activated in ACM mode, holding 10 seconds...");
3022 // Update the device
3024 dev.aquired.controlMode = 2; // 1 = CCM, 2 = ACM
3025 if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') {
3026 var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
3027 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]); }
3029 if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
3030 dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
3032 dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm;
3033 dev.intelamt.user = dev.aquired.user = 'admin';
3034 dev.intelamt.pass = dev.aquired.pass = dev.temp.pass;
3035 dev.intelamt.tls = dev.aquired.tls = 0;
3036 dev.aquired.lastContact = Date.now();
3037 dev.aquired.state = 2; // Activated
3042 // Wait 10 seconds before attempting to manage this device in ACM
3043 var f = function doManage() { if (isAmtDeviceValid(dev)) { attemptInitialContact(doManage.dev); } }
3045 setTimeout(f, 10000);
3053 // Intel AMT CCM deactivation
3056 function deactivateIntelAmtCCM(dev) {
3057 dev.consoleMsg("Deactivating CCM...");
3058 dev.deactivateCcmPending = 1;
3059 dev.controlMsg({ action: 'deactivate' });
3062 // This is called after the deactivation call
3063 function deactivateIntelAmtCCMEx(dev, state) {
3065 dev.consoleMsg("Failed to deactivate Intel AMT CCM.");
3066 removeAmtDevice(dev, 53);
3068 // Update the device
3070 dev.aquired.controlMode = 0; // 1 = CCM, 2 = ACM
3071 dev.aquired.state = 0; // Not activated
3073 delete dev.amtstack;
3076 if (dev.policy.amtPolicy == 1) { // Deactivation policy, we are done.
3077 dev.consoleMsg("Deactivation successful.");
3078 dev.consoleMsg("Done.");
3079 removeAmtDevice(dev, 54);
3081 // Wait 20 seconds before attempting any operation on this device
3082 dev.consoleMsg("Deactivation successful, holding for 1 minute...");
3083 var f = function askMeiState() {
3084 askMeiState.dev.pendingUpdatedMeiState = 1;
3085 askMeiState.dev.controlMsg({ action: 'mestate' });
3088 setTimeout(f, 60000);
3098 // Called this when a task is completed, when all tasks are completed the call back function will be called.
3099 function devTaskCompleted(dev) {
3101 if (dev.taskCount == 0) { var f = dev.taskCompleted; delete dev.taskCount; delete dev.taskCompleted; if (f != null) { f(dev); } }
3104 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); }
3106 // Base64 to string conversion utility functions
3107 function atob(x) { return Buffer.from(x, 'base64').toString('binary'); }
3108 function btoa(x) { return Buffer.from(x, 'binary').toString('base64'); }
3110 // Check which key pair matches the public key in the certificate
3111 function amtcert_linkCertPrivateKey(certs, keys) {
3112 if ((keys == null) || (keys.length == 0)) return;
3113 for (var i in certs) {
3114 var cert = certs[i];
3116 var publicKeyPEM = obj.parent.certificateOperations.forge.pki.publicKeyToPem(obj.parent.certificateOperations.forge.pki.certificateFromAsn1(obj.parent.certificateOperations.forge.asn1.fromDer(cert.X509CertificateBin)).publicKey).substring(28 + 32).replace(/(\r\n|\n|\r)/gm, "");
3117 publicKeyPEM = publicKeyPEM.substring(0, publicKeyPEM.length - 24); // Remove the PEM footer
3118 for (var j = 0; j < keys.length; j++) {
3119 if ((publicKeyPEM === (keys[j]['DERKey'])) || (publicKeyPEM == btoa(atob(keys[j]['DERKey']).substring(24)))) { // Match directly or, new version of Intel AMT put the key type OID in the private key, skip that and match.
3120 keys[j].XCert = cert; // Link the key pair to the certificate
3121 cert.XPrivateKey = keys[j]; // Link the certificate to the key pair
3124 } catch (ex) { console.log(ex); }
3128 // Generate a random Intel AMT password
3129 function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
3130 function getRandomAmtPassword() { var p; do { p = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
3131 function getRandomPassword() { return Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
3132 function getRandomLowerCase(len) { var r = '', random = parent.crypto.randomBytes(len); for (var i = 0; i < len; i++) { r += String.fromCharCode(97 + (random[i] % 26)); } return r; }
3133 function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
3135 function hex_md5(str) { return parent.crypto.createHash('md5').update(str).digest('hex'); }
3136 function Clone(v) { return JSON.parse(JSON.stringify(v)); }
3137 function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
3138 function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
3139 function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
3141 // Returns a UEFI boot parameter in binary
3142 function makeUefiBootParam(type, data, len) {
3143 if (typeof data == 'number') { if (len == 1) { data = String.fromCharCode(data & 0xFF); } if (len == 2) { data = parent.common.ShortToStrX(data); } if (len == 4) { data = parent.common.IntToStrX(data); } }
3144 return parent.common.ShortToStrX(0x8086) + parent.common.ShortToStrX(type) + parent.common.IntToStrX(data.length) + data;
3147 function parseCertName(x) {
3148 var j, r = {}, xx = x.split(',');
3149 for (var i in xx) { j = xx[i].indexOf('='); r[xx[i].substring(0, j)] = xx[i].substring(j + 1); }
3154 function amtcert_signWithCaKey(DERKey, caPrivateKey, certAttributes, issuerAttributes, extKeyUsage) {
3155 return obj.amtcert_createCertificate(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage);
3159 // --- Extended Key Usage OID's ---
3160 // 1.3.6.1.5.5.7.3.1 = TLS Server certificate
3161 // 1.3.6.1.5.5.7.3.2 = TLS Client certificate
3162 // 2.16.840.1.113741.1.2.1 = Intel AMT Remote Console
3163 // 2.16.840.1.113741.1.2.2 = Intel AMT Local Console
3164 // 2.16.840.1.113741.1.2.3 = Intel AMT Client Setup Certificate (Zero-Touch)
3166 // Generate a certificate with a set of attributes signed by a rootCert. If the rootCert is obmitted, the generated certificate is self-signed.
3167 obj.amtcert_createCertificate = function(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage) {
3168 // Generate a keypair and create an X.509v3 certificate
3169 var keys, cert = obj.parent.certificateOperations.forge.pki.createCertificate();
3170 cert.publicKey = obj.parent.certificateOperations.forge.pki.publicKeyFromPem('-----BEGIN PUBLIC KEY-----' + DERKey + '-----END PUBLIC KEY-----');
3171 cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1);
3172 cert.validity.notBefore = new Date(2018, 0, 1);
3173 //cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert.
3174 cert.validity.notAfter = new Date(2049, 11, 31);
3175 //cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20);
3177 if (certAttributes['CN']) attrs.push({ name: 'commonName', value: certAttributes['CN'] });
3178 if (certAttributes['C']) attrs.push({ name: 'countryName', value: certAttributes['C'] });
3179 if (certAttributes['ST']) attrs.push({ shortName: 'ST', value: certAttributes['ST'] });
3180 if (certAttributes['O']) attrs.push({ name: 'organizationName', value: certAttributes['O'] });
3181 cert.setSubject(attrs);
3183 // Use root attributes
3185 if (issuerAttributes['CN']) rootattrs.push({ name: 'commonName', value: issuerAttributes['CN'] });
3186 if (issuerAttributes['C']) rootattrs.push({ name: 'countryName', value: issuerAttributes['C'] });
3187 if (issuerAttributes['ST']) rootattrs.push({ shortName: 'ST', value: issuerAttributes['ST'] });
3188 if (issuerAttributes['O']) rootattrs.push({ name: 'organizationName', value: issuerAttributes['O'] });
3189 cert.setIssuer(rootattrs);
3191 if (extKeyUsage == null) { extKeyUsage = { name: 'extKeyUsage', serverAuth: true, } } else { extKeyUsage.name = 'extKeyUsage'; }
3195 name: 'extKeyUsage',
3199 emailProtection: true,
3201 '2.16.840.1.113741.1.2.1': true
3205 // Create a leaf certificate
3206 cert.setExtensions([{
3207 name: 'basicConstraints'
3211 digitalSignature: true,
3212 nonRepudiation: true,
3213 keyEncipherment: true,
3214 dataEncipherment: true
3222 name: 'subjectKeyIdentifier'
3225 // Self-sign certificate
3226 var privatekey = obj.parent.certificateOperations.forge.pki.privateKeyFromPem(caPrivateKey);
3227 cert.sign(privatekey, obj.parent.certificateOperations.forge.md.sha256.create());