amtmanager.js 202 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232
  1. /**
  2. * @description MeshCentral Intel AMT manager
  3. * @author Ylian Saint-Hilaire
  4. * @copyright Intel Corporation 2018-2022
  5. * @license Apache-2.0
  6. * @version v0.0.1
  7. */
  8. /*jslint node: true */
  9. /*jshint node: true */
  10. /*jshint strict:false */
  11. /*jshint -W097 */
  12. /*jshint esversion: 6 */
  13. 'use strict';
  14. module.exports.CreateAmtManager = function (parent) {
  15. var obj = {};
  16. obj.parent = parent;
  17. obj.amtDevices = {}; // Nodeid --> [ dev ]
  18. obj.activeLocalConnections = {}; // Host --> dev
  19. obj.amtAdminAccounts = {}; // DomainId -> [ { user, pass } ]
  20. obj.rootCertBase64 = obj.parent.certificates.root.cert.split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('').split('\r').join('').split('\n').join('')
  21. obj.rootCertCN = obj.parent.certificateOperations.forge.pki.certificateFromPem(obj.parent.certificates.root.cert).subject.getField('CN').value;
  22. // 802.1x authentication protocols
  23. 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'];
  24. // WSMAN stack
  25. const CreateWsmanComm = require('./amt/amt-wsman-comm');
  26. const WsmanStackCreateService = require('./amt/amt-wsman');
  27. const AmtStackCreateService = require('./amt/amt');
  28. const ConnectionTypeStrings = { 0: "CIRA", 1: "Relay", 2: "LMS", 3: "Local" };
  29. // Check that each domain configuration is correct because we are not going to be checking this later.
  30. if (parent.config == null) parent.config = {};
  31. if (parent.config.domains == null) parent.config.domains = {};
  32. for (var domainid in parent.config.domains) {
  33. var domain = parent.config.domains[domainid];
  34. if (typeof domain.amtmanager != 'object') { domain.amtmanager = {}; }
  35. // Load administrator accounts
  36. if (Array.isArray(domain.amtmanager.adminaccounts) == true) {
  37. for (var i = 0; i < domain.amtmanager.adminaccounts.length; i++) {
  38. var c = domain.amtmanager.adminaccounts[i], c2 = {};
  39. if (typeof c.user == 'string') { c2.user = c.user; } else { c2.user = 'admin'; }
  40. if (typeof c.pass == 'string') {
  41. c2.pass = c.pass;
  42. if (obj.amtAdminAccounts[domainid] == null) { obj.amtAdminAccounts[domainid] = []; }
  43. obj.amtAdminAccounts[domainid].push(c2);
  44. }
  45. }
  46. } else {
  47. delete domain.amtmanager.adminaccounts;
  48. }
  49. // Check environment detection
  50. if (Array.isArray(domain.amtmanager.environmentdetection) == true) {
  51. var envDetect = [];
  52. for (var i = 0; i < domain.amtmanager.environmentdetection.length; i++) {
  53. var x = domain.amtmanager.environmentdetection[i].toLowerCase();
  54. if ((typeof x == 'string') && (x != '') && (x.length < 64) && (envDetect.indexOf(x) == -1)) { envDetect.push(x); }
  55. if (envDetect.length >= 4) break; // Maximum of 4 DNS suffix
  56. }
  57. if (envDetect.length > 0) { domain.amtmanager.environmentdetection = envDetect; } else { delete domain.amtmanager.environmentdetection; }
  58. } else {
  59. delete domain.amtmanager.environmentdetection;
  60. }
  61. // Check 802.1x wired profile if present
  62. if ((domain.amtmanager['802.1x'] != null) && (typeof domain.amtmanager['802.1x'] == 'object')) {
  63. if (domain.amtmanager['802.1x'].satellitecredentials != null) {
  64. if (typeof domain.amtmanager['802.1x'].satellitecredentials != 'string') { delete domain.amtmanager['802.1x']; } else {
  65. const userSplit = domain.amtmanager['802.1x'].satellitecredentials.split('/');
  66. if (userSplit.length > 3) { delete domain.amtmanager['802.1x']; }
  67. else if (userSplit.length == 2) { domain.amtmanager['802.1x'].satellitecredentials = 'user/' + domain.id + '/' + userSplit[1]; }
  68. else if (userSplit.length == 1) { domain.amtmanager['802.1x'].satellitecredentials = 'user/' + domain.id + '/' + userSplit[0]; }
  69. }
  70. }
  71. if (typeof domain.amtmanager['802.1x'].servercertificatename != 'string') {
  72. delete domain.amtmanager['802.1x'].servercertificatenamecomparison;
  73. } else {
  74. const serverCertCompareStrings = ['', '', 'fullname', 'domainsuffix'];
  75. if (typeof domain.amtmanager['802.1x'].servercertificatenamecomparison == 'string') {
  76. domain.amtmanager['802.1x'].servercertificatenamecomparison = serverCertCompareStrings.indexOf(domain.amtmanager['802.1x'].servercertificatenamecomparison.toLowerCase());
  77. if (domain.amtmanager['802.1x'].servercertificatenamecomparison == -1) { domain.amtmanager['802.1x'].servercertificatenamecomparison = 2; } // Default to full name compare
  78. }
  79. }
  80. if (typeof domain.amtmanager['802.1x'].authenticationprotocol == 'string') {
  81. domain.amtmanager['802.1x'].authenticationprotocol = netAuthStrings.indexOf(domain.amtmanager['802.1x'].authenticationprotocol.toLowerCase());
  82. if (domain.amtmanager['802.1x'].authenticationprotocol == -1) { delete domain.amtmanager['802.1x']; }
  83. }
  84. }
  85. // Check WIFI profiles
  86. //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" };
  87. //var wifiEncMethod = { 1: "Other", 2: "WEP", 3: "TKIP", 4: "CCMP", 5: "None" }
  88. if (Array.isArray(domain.amtmanager.wifiprofiles) == true) {
  89. var goodWifiProfiles = [];
  90. for (var i = 0; i < domain.amtmanager.wifiprofiles.length; i++) {
  91. var wifiProfile = domain.amtmanager.wifiprofiles[i];
  92. if ((typeof wifiProfile.ssid == 'string') && (wifiProfile.ssid != '')) {
  93. if ((wifiProfile.name == null) || (wifiProfile.name == '')) { wifiProfile.name = wifiProfile.ssid; }
  94. // Authentication
  95. if (typeof wifiProfile.authentication == 'string') { wifiProfile.authentication = wifiProfile.authentication.toLowerCase(); }
  96. if (wifiProfile.authentication == 'wpa-psk') { wifiProfile.authentication = 4; }
  97. if (wifiProfile.authentication == 'wpa2-psk') { wifiProfile.authentication = 6; }
  98. if (wifiProfile.authentication == 'wpa-8021x') { wifiProfile.authentication = 5; }
  99. if (wifiProfile.authentication == 'wpa2-802.1x') { wifiProfile.authentication = 7; }
  100. if (wifiProfile.authentication == 'wpa3-sae-802.1x') { wifiProfile.authentication = 32768; }
  101. if (wifiProfile.authentication == 'wpa3-owe-802.1x') { wifiProfile.authentication = 32769; }
  102. if (typeof wifiProfile.authentication != 'number') {
  103. if (wifiProfile['802.1x']) { wifiProfile.authentication = 7; } // Default to WPA2-802.1x
  104. else { wifiProfile.authentication = 6; } // Default to WPA2-PSK
  105. }
  106. // Encyption
  107. if (typeof wifiProfile.encryption == 'string') { wifiProfile.encryption = wifiProfile.encryption.toLowerCase(); }
  108. if ((wifiProfile.encryption == 'ccmp-aes') || (wifiProfile.encryption == 'ccmp')) { wifiProfile.encryption = 4; }
  109. if ((wifiProfile.encryption == 'tkip-rc4') || (wifiProfile.encryption == 'tkip')) { wifiProfile.encryption = 3; }
  110. if (typeof wifiProfile.encryption != 'number') { wifiProfile.encryption = 4; } // Default to CCMP-AES
  111. // Type
  112. wifiProfile.type = 3; // Infrastructure
  113. // Check authentication
  114. if ([4, 6].indexOf(wifiProfile.authentication) >= 0) {
  115. // Password authentication
  116. if ((typeof wifiProfile.password != 'string') || (wifiProfile.password.length < 8) || (wifiProfile.password.length > 63)) continue;
  117. } else if ([5, 7, 32768, 32769].indexOf(wifiProfile.authentication) >= 0) {
  118. // 802.1x authentication
  119. if ((domain.amtmanager['802.1x'] == null) || (typeof domain.amtmanager['802.1x'] != 'object')) continue;
  120. }
  121. goodWifiProfiles.push(wifiProfile);
  122. }
  123. }
  124. domain.amtmanager.wifiprofiles = goodWifiProfiles;
  125. } else {
  126. delete domain.amtmanager.wifiprofiles;
  127. }
  128. }
  129. // Check if an Intel AMT device is being managed
  130. function isAmtDeviceValid(dev) {
  131. var devices = obj.amtDevices[dev.nodeid];
  132. if (devices == null) return false;
  133. return (devices.indexOf(dev) >= 0)
  134. }
  135. // Add an Intel AMT managed device
  136. function addAmtDevice(dev) {
  137. var devices = obj.amtDevices[dev.nodeid];
  138. if (devices == null) { obj.amtDevices[dev.nodeid] = [dev]; return true; }
  139. if (devices.indexOf(dev) >= 0) return false; // This device is already in the list
  140. devices.push(dev); // Add the device to the list
  141. return true;
  142. }
  143. // Remove an Intel AMT managed device
  144. function removeAmtDevice(dev, tag) {
  145. parent.debug('amt', dev.name, "Remove device", dev.nodeid, dev.connType, tag);
  146. // Find the device in the list
  147. var devices = obj.amtDevices[dev.nodeid];
  148. if (devices == null) return false;
  149. var i = devices.indexOf(dev);
  150. if (i == -1) return false;
  151. // Remove from task limiter if needed
  152. if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
  153. // Clean up this device
  154. if (dev.amtstack != null) { dev.amtstack.CancelAllQueries(999); if (dev.amtstack != null) { delete dev.amtstack.dev; delete dev.amtstack; } }
  155. if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
  156. // Remove the device from the list
  157. devices.splice(i, 1);
  158. if (devices.length == 0) { delete obj.amtDevices[dev.nodeid]; } else { obj.amtDevices[dev.nodeid] = devices; }
  159. // Notify connection closure if this is a LMS connection
  160. if (dev.connType == 2) { dev.controlMsg({ action: 'close' }); }
  161. return true;
  162. }
  163. // Remove all Intel AMT devices for a given nodeid
  164. function removeDevice(nodeid) {
  165. parent.debug('amt', "Remove nodeid", nodeid);
  166. // Find the devices in the list
  167. var devices = obj.amtDevices[nodeid];
  168. if (devices == null) return false;
  169. for (var i in devices) {
  170. var dev = devices[i];
  171. // Remove from task limiter if needed
  172. if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
  173. // Clean up this device
  174. if (dev.amtstack != null) { dev.amtstack.wsman.comm.FailAllError = 999; delete dev.amtstack; } // Disconnect any active connections.
  175. if (dev.polltimer != null) { clearInterval(dev.polltimer); delete dev.polltimer; }
  176. // Notify connection closure if this is a LMS connection
  177. if (dev.connType == 2) { dev.controlMsg({ action: 'close' }); }
  178. }
  179. // Remove all Intel AMT management sessions for this nodeid
  180. delete obj.amtDevices[nodeid];
  181. // If a 802.1x profile is active with MeshCentral Satellite, notify Satellite of the removal
  182. if (domain.amtmanager['802.1x'] != null) {
  183. var reqId = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64'); // Generate a crypto-secure request id.
  184. 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 });
  185. }
  186. return true;
  187. }
  188. // Start Intel AMT management
  189. // connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
  190. obj.startAmtManagement = function (nodeid, connType, connection) {
  191. //if (connType == 3) return; // DEBUG
  192. var devices = obj.amtDevices[nodeid], dev = null;
  193. if (devices != null) { for (var i in devices) { if ((devices[i].mpsConnection == connection) || (devices[i].host == connection)) { dev = devices[i]; } } }
  194. if (dev != null) return false; // We are already managing this device on this connection
  195. dev = { nodeid: nodeid, connType: connType, domainid: nodeid.split('/')[1] };
  196. if (typeof connection == 'string') { dev.host = connection; }
  197. if (typeof connection == 'object') { dev.mpsConnection = connection; }
  198. dev.consoleMsg = function deviceConsoleMsg(msg) { parent.debug('amt', deviceConsoleMsg.dev.name, msg); if (typeof deviceConsoleMsg.conn == 'object') { deviceConsoleMsg.conn.ControlMsg({ action: 'console', msg: msg }); } }
  199. dev.consoleMsg.conn = connection;
  200. dev.consoleMsg.dev = dev;
  201. dev.controlMsg = function deviceControlMsg(msg) { if (typeof deviceControlMsg.conn == 'object') { deviceControlMsg.conn.ControlMsg(msg); } }
  202. dev.controlMsg.conn = connection;
  203. parent.debug('amt', "Start Management", nodeid, connType);
  204. addAmtDevice(dev);
  205. // Start the device manager in the task limiter so not to flood the server. Low priority task
  206. obj.parent.taskLimiter.launch(function (dev, taskid, taskLimiterQueue) {
  207. if (isAmtDeviceValid(dev)) {
  208. // Start managing this device
  209. dev.taskid = taskid;
  210. fetchIntelAmtInformation(dev);
  211. } else {
  212. // Device is not valid anymore, do nothing
  213. obj.parent.taskLimiter.completed(taskid);
  214. }
  215. }, dev, 2);
  216. }
  217. // Stop Intel AMT management
  218. obj.stopAmtManagement = function (nodeid, connType, connection) {
  219. var devices = obj.amtDevices[nodeid], dev = null;
  220. if (devices != null) { for (var i in devices) { if ((devices[i].mpsConnection == connection) || (devices[i].host == connection)) { dev = devices[i]; } } }
  221. if (dev == null) return false; // We are not managing this device on this connection
  222. parent.debug('amt', dev.name, "Stop Management", nodeid, connType);
  223. return removeAmtDevice(dev, 1);
  224. }
  225. // Get a string status of the managed devices
  226. obj.getStatusString = function () {
  227. var r = '';
  228. for (var nodeid in obj.amtDevices) {
  229. var devices = obj.amtDevices[nodeid];
  230. r += devices[0].nodeid + ', ' + devices[0].name + '\r\n';
  231. for (var i in devices) {
  232. var dev = devices[i];
  233. var items = [];
  234. if (dev.state == 1) { items.push('Connected'); } else { items.push('Trying'); }
  235. items.push(ConnectionTypeStrings[dev.connType]);
  236. if (dev.connType == 3) { items.push(dev.host); }
  237. if (dev.polltimer != null) { items.push('Polling Power'); }
  238. r += ' ' + items.join(', ') + '\r\n';
  239. }
  240. }
  241. if (r == '') { r = "No managed Intel AMT devices"; }
  242. return r;
  243. }
  244. // Receive a JSON control message from the MPS server
  245. obj.mpsControlMessage = function (nodeid, conn, connType, jsondata) {
  246. // Find the devices in the list
  247. var dev = null;
  248. var devices = obj.amtDevices[nodeid];
  249. if (devices == null) return;
  250. for (var i in devices) { if (devices[i].mpsConnection === conn) { dev = devices[i]; } }
  251. if (dev == null) return;
  252. // Process the message
  253. switch (jsondata.action) {
  254. case 'deactivate':
  255. if ((dev.connType != 2) || (dev.deactivateCcmPending != 1)) break; // Only accept MEI state on CIRA-LMS connection
  256. delete dev.deactivateCcmPending;
  257. deactivateIntelAmtCCMEx(dev, jsondata.value);
  258. break;
  259. case 'meiState':
  260. if (dev.acmactivate == 1) {
  261. // Continue ACM activation
  262. dev.consoleMsg("Got new Intel AMT MEI state. Holding 40 seconds prior to ACM activation...");
  263. delete dev.acmactivate;
  264. var continueAcmFunc = function continueAcm() { if (isAmtDeviceValid(continueAcm.dev)) { activateIntelAmtAcmEx0(continueAcm.dev); } }
  265. continueAcmFunc.dev = dev;
  266. setTimeout(continueAcmFunc, 40000);
  267. } else {
  268. if (dev.pendingUpdatedMeiState != 1) break;
  269. delete dev.pendingUpdatedMeiState;
  270. attemptInitialContact(dev);
  271. }
  272. break;
  273. case 'startTlsHostConfig':
  274. if (dev.acmTlsInfo == null) break;
  275. if ((typeof jsondata.value != 'object') || (typeof jsondata.value.status != 'number')) {
  276. removeAmtDevice(dev, 2); // Invalid startTlsHostConfig response
  277. } else {
  278. activateIntelAmtTlsAcmEx(dev, jsondata.value); // Start TLS activation.
  279. }
  280. break;
  281. case 'stopConfiguration':
  282. if (dev.acmactivate != 1) break;
  283. if (jsondata.value == 3) { delete dev.acmactivate; activateIntelAmtAcmEx0(dev); } // Intel AMT was already not in in-provisioning state, keep going right away.
  284. else if (jsondata.value == 0) {
  285. dev.consoleMsg("Cleared in-provisioning state. Holding 30 seconds prior to getting Intel AMT MEI state...");
  286. var askStateFunc = function askState() { if (isAmtDeviceValid(askState.dev)) { askState.dev.controlMsg({ action: 'mestate' }); } }
  287. askStateFunc.dev = dev;
  288. setTimeout(askStateFunc, 30000);
  289. }
  290. else { dev.consoleMsg("Unknown stopConfiguration() state of " + jsondata.value + ". Continuing with ACM activation..."); delete dev.acmactivate; activateIntelAmtAcmEx0(dev); }
  291. break;
  292. }
  293. }
  294. // Subscribe to server events
  295. parent.AddEventDispatch(['*'], obj);
  296. // Handle server events
  297. // 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.
  298. obj.HandleEvent = function (source, event, ids, id) {
  299. switch (event.action) {
  300. case 'removenode': { // React to node being removed
  301. 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.
  302. removeDevice(event.nodeid);
  303. break;
  304. }
  305. case 'wakedevices': { // React to node wakeup command, perform Intel AMT wake if possible
  306. 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.
  307. if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performPowerAction(event.nodeids[i], 2); } }
  308. break;
  309. }
  310. case 'oneclickrecovery': { // React to Intel AMT One Click Recovery command
  311. 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.
  312. if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performOneClickRecoveryAction(event.nodeids[i], event.file); } }
  313. break;
  314. }
  315. case 'amtpoweraction': {
  316. 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.
  317. if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performPowerAction(event.nodeids[i], event.actiontype); } }
  318. break;
  319. }
  320. case 'changenode': { // React to changes in a device
  321. var devices = obj.amtDevices[event.nodeid], rescan = false;
  322. if (devices != null) {
  323. for (var i in devices) {
  324. var dev = devices[i];
  325. dev.name = event.node.name;
  326. dev.icon = event.node.icon;
  327. dev.rname = event.node.rname;
  328. // If there are any changes, apply them.
  329. if (event.node.intelamt != null) {
  330. if (dev.intelamt == null) { dev.intelamt = {}; }
  331. if ((typeof event.node.intelamt.version == 'string') && (event.node.intelamt.version != dev.intelamt.ver)) { dev.intelamt.ver = event.node.intelamt.version; }
  332. if ((typeof event.node.intelamt.user == 'string') && (event.node.intelamt.user != dev.intelamt.user)) { dev.intelamt.user = event.node.intelamt.user; }
  333. if ((typeof event.node.intelamt.pass == 'string') && (event.node.intelamt.pass != dev.intelamt.pass)) { dev.intelamt.pass = event.node.intelamt.pass; }
  334. if ((typeof event.node.intelamt.mpspass == 'string') && (event.node.intelamt.mpspass != dev.intelamt.mpspass)) { dev.intelamt.mpspass = event.node.intelamt.mpspass; }
  335. if ((typeof event.node.intelamt.host == 'string') && (event.node.intelamt.host != dev.intelamt.host)) { dev.intelamt.host = event.node.intelamt.host; }
  336. if ((typeof event.node.intelamt.realm == 'string') && (event.node.intelamt.realm != dev.intelamt.realm)) { dev.intelamt.realm = event.node.intelamt.realm; }
  337. if ((typeof event.node.intelamt.hash == 'string') && (event.node.intelamt.hash != dev.intelamt.hash)) { dev.intelamt.hash = event.node.intelamt.hash; }
  338. if ((typeof event.node.intelamt.tls == 'number') && (event.node.intelamt.tls != dev.intelamt.tls)) { dev.intelamt.tls = event.node.intelamt.tls; }
  339. if ((typeof event.node.intelamt.state == 'number') && (event.node.intelamt.state != dev.intelamt.state)) { dev.intelamt.state = event.node.intelamt.state; }
  340. }
  341. if ((dev.connType == 3) && (dev.host != event.node.host)) {
  342. dev.host = event.node.host; // The host has changed, if we are connected to this device locally, we need to reset.
  343. removeAmtDevice(dev, 3); // We are going to wait for the AMT scanned to find this device again.
  344. rescan = true;
  345. }
  346. }
  347. } else {
  348. // 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.
  349. if (event.amtchange == 1) { rescan = true; }
  350. }
  351. // 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.
  352. if (rescan && (parent.amtScanner != null)) { parent.amtScanner.performSpecificScan(event.node); }
  353. break;
  354. }
  355. case 'meshchange': {
  356. // TODO
  357. // 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.
  358. break;
  359. }
  360. case 'satelliteResponse': {
  361. if ((typeof event.nodeid != 'string') || (typeof event.reqid != 'string') || (event.satelliteFlags != 2)) return;
  362. var devices = obj.amtDevices[event.nodeid], devFound = null;
  363. if (devices != null) { for (var i in devices) { if (devices[i].netAuthSatReqId == event.reqid) { devFound = devices[i]; } } }
  364. if (devFound == null) return; // Unable to find a device for this 802.1x profile
  365. switch (event.subaction) {
  366. case '802.1x-KeyPair-Request': {
  367. // 802.1x request for public/private key pair be generated
  368. attempt8021xKeyGeneration(devFound);
  369. break;
  370. }
  371. case '802.1x-CSR-Request': {
  372. // 802.1x request for a Certificate Signing Request
  373. attempt8021xCRSRequest(devFound, event);
  374. break;
  375. }
  376. case '802.1x-Profile-Completed': {
  377. // The 802.1x profile request is done, set it in Intel AMT.
  378. if (devFound.netAuthSatReqTimer != null) { clearTimeout(devFound.netAuthSatReqTimer); delete devFound.netAuthSatReqTimer; }
  379. if ((event.response == null) || (typeof event.response != 'object')) {
  380. // Unable to create a 802.1x profile
  381. delete devFound.netAuthSatReqId;
  382. if (isAmtDeviceValid(devFound) == false) return; // Device no longer exists, ignore this request.
  383. delete devFound.netAuthSatReqData;
  384. devFound.consoleMsg("MeshCentral Satellite could not create a 802.1x profile for this device.");
  385. devTaskCompleted(devFound);
  386. return;
  387. }
  388. if (typeof event.response.authProtocol != 'number') { delete devFound.netAuthSatReqId; break; }
  389. // We got a new 802.1x profile
  390. devFound.netAuthCredentials = event.response;
  391. perform8021xRootCertCheck(devFound);
  392. break;
  393. }
  394. }
  395. break;
  396. }
  397. }
  398. }
  399. //
  400. // Intel AMT Connection Setup
  401. //
  402. // Update information about a device
  403. function fetchIntelAmtInformation(dev) {
  404. parent.db.Get(dev.nodeid, function (err, nodes) {
  405. if ((nodes == null) || (nodes.length != 1)) { removeAmtDevice(dev, 4); return; }
  406. const node = nodes[0];
  407. if ((node.intelamt == null) || (node.meshid == null)) { removeAmtDevice(dev, 5); return; }
  408. const mesh = parent.webserver.meshes[node.meshid];
  409. if (mesh == null) { removeAmtDevice(dev, 6); return; }
  410. if (dev == null) { return; }
  411. // Fetch Intel AMT setup policy
  412. // mesh.amt.type: 0 = No Policy, 1 = Deactivate CCM, 2 = Manage in CCM, 3 = Manage in ACM
  413. // mesh.amt.cirasetup: 0 = No Change, 1 = Remove CIRA, 2 = Setup CIRA
  414. var amtPolicy = 0, ciraPolicy = 0, badPass = 0, password = null;
  415. if (mesh.amt != null) {
  416. if (mesh.amt.type) { amtPolicy = mesh.amt.type; }
  417. if (mesh.amt.type == 4) {
  418. // Fully automatic policy
  419. ciraPolicy = 2; // CIRA will be setup
  420. badPass = 1; // Automatically re-active CCM
  421. password = null; // Randomize the password.
  422. } else {
  423. if (mesh.amt.cirasetup) { ciraPolicy = mesh.amt.cirasetup; }
  424. if (mesh.amt.badpass) { badPass = mesh.amt.badpass; }
  425. if ((typeof mesh.amt.password == 'string') && (mesh.amt.password != '')) { password = mesh.amt.password; }
  426. }
  427. }
  428. if (amtPolicy == 0) { ciraPolicy = 0; } // If no policy, don't change CIRA state.
  429. if (amtPolicy == 1) { ciraPolicy = 1; } // If deactivation policy, clear CIRA.
  430. dev.policy = { amtPolicy: amtPolicy, ciraPolicy: ciraPolicy, badPass: badPass, password: password };
  431. // Setup the monitored device
  432. dev.name = node.name;
  433. dev.rname = node.rname;
  434. dev.icon = node.icon;
  435. dev.meshid = node.meshid;
  436. dev.intelamt = node.intelamt;
  437. // Check if the status of Intel AMT sent by the agents matched what we have in the database
  438. if ((dev.connType == 2) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null)) {
  439. dev.aquired = {};
  440. if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
  441. dev.host = dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
  442. }
  443. if (typeof dev.mpsConnection.tag.meiState['ProvisioningState'] == 'number') {
  444. dev.intelamt.state = dev.aquired.state = dev.mpsConnection.tag.meiState['ProvisioningState'];
  445. }
  446. if ((typeof dev.mpsConnection.tag.meiState['Versions'] == 'object') && (typeof dev.mpsConnection.tag.meiState['Versions']['AMT'] == 'string')) {
  447. dev.intelamt.ver = dev.aquired.version = dev.mpsConnection.tag.meiState['Versions']['AMT'];
  448. }
  449. if (typeof dev.mpsConnection.tag.meiState['Flags'] == 'number') {
  450. const flags = dev.intelamt.flags = dev.mpsConnection.tag.meiState['Flags'];
  451. if (flags & 2) { dev.aquired.controlMode = 1; } // CCM
  452. if (flags & 4) { dev.aquired.controlMode = 2; } // ACM
  453. }
  454. UpdateDevice(dev);
  455. }
  456. // If there is no Intel AMT policy for this device, stop here.
  457. //if (amtPolicy == 0) { dev.consoleMsg("Done."); removeAmtDevice(dev, 7); return; }
  458. // Initiate the communication to Intel AMT
  459. dev.consoleMsg("Checking Intel AMT state...");
  460. attemptInitialContact(dev);
  461. });
  462. }
  463. // Attempt to perform initial contact with Intel AMT
  464. function attemptInitialContact(dev) {
  465. // If there is a WSMAN stack setup, clean it up now.
  466. if (dev.amtstack != null) {
  467. dev.amtstack.CancelAllQueries(999);
  468. delete dev.amtstack.dev;
  469. delete dev.amtstack;
  470. }
  471. delete dev.amtstack;
  472. parent.debug('amt', dev.name, "Attempt Initial Contact", ["CIRA", "CIRA-Relay", "CIRA-LMS", "Local"][dev.connType]);
  473. // Check Intel AMT policy when CIRA-LMS connection is in use.
  474. if ((dev.connType == 2) && (dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null)) {
  475. // Intel AMT activation policy
  476. if ((dev.policy.amtPolicy > 1) && (dev.mpsConnection.tag.meiState.ProvisioningState !== 2)) {
  477. // This Intel AMT device is not activated, we need to work on activating it.
  478. activateIntelAmt(dev);
  479. return;
  480. }
  481. // Check if we have an ACM activation policy, but the device is in CCM
  482. if (((dev.policy.amtPolicy == 3) || (dev.policy.amtPolicy == 4)) && (dev.mpsConnection.tag.meiState.ProvisioningState == 2) && ((dev.mpsConnection.tag.meiState.Flags & 2) != 0)) {
  483. // This device in is CCM, check if we can upgrade to ACM
  484. if (activateIntelAmt(dev) == false) return; // If this return true, the platform is in CCM and can't go to ACM, keep going with management.
  485. }
  486. // Intel AMT CCM deactivation policy
  487. if (dev.policy.amtPolicy == 1) {
  488. if ((dev.mpsConnection.tag.meiState.ProvisioningState == 2) && ((dev.mpsConnection.tag.meiState.Flags & 2) != 0)) {
  489. // Deactivate CCM.
  490. deactivateIntelAmtCCM(dev);
  491. return;
  492. }
  493. }
  494. }
  495. // See what username/password we need to try
  496. // We create an efficient strategy for trying different Intel AMT passwords.
  497. if (dev.acctry == null) {
  498. dev.acctry = [];
  499. // Add Intel AMT username and password provided by MeshCMD if available
  500. 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 != '')) {
  501. dev.acctry.push([dev.mpsConnection.tag.meiState.amtuser, dev.mpsConnection.tag.meiState.amtpass]);
  502. }
  503. // Add the know Intel AMT password for this device if available
  504. 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]); }
  505. // Add the policy password as an alternative
  506. if ((typeof dev.policy.password == 'string') && (dev.policy.password != '')) { dev.acctry.push(['admin', dev.policy.password]); }
  507. // Add any configured admin account as alternatives
  508. 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]); } }
  509. // Add any previous passwords for the device UUID as alternative
  510. 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)) {
  511. for (var i in parent.amtPasswords[dev.mpsConnection.tag.meiState.UUID]) {
  512. dev.acctry.push(['admin', parent.amtPasswords[dev.mpsConnection.tag.meiState.UUID][i]]);
  513. }
  514. }
  515. // Remove any duplicates user/passwords
  516. var acctry2 = [];
  517. for (var i = 0; i < dev.acctry.length; i++) {
  518. var found = false;
  519. 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; } }
  520. if (found == false) { acctry2.push(dev.acctry[i]); }
  521. }
  522. dev.acctry = acctry2;
  523. // If we have passwords to try, try the first one now.
  524. if (dev.acctry.length == 0) {
  525. dev.consoleMsg("No admin login passwords to try, stopping now.");
  526. removeAmtDevice(dev, 8);
  527. return;
  528. }
  529. }
  530. if ((dev.acctry == null) || (dev.acctry.length == 0)) { removeAmtDevice(dev, 9); return; } // No Intel AMT credentials to try
  531. var user = dev.acctry[0][0], pass = dev.acctry[0][1]; // Try the first user/pass in the list
  532. switch (dev.connType) {
  533. case 0: // CIRA
  534. // Handle the case where the Intel AMT CIRA is connected (connType 0)
  535. // In this connection type, we look at the port bindings to see if we need to do TLS or not.
  536. // Check to see if CIRA is connected on this server.
  537. var ciraconn = dev.mpsConnection;
  538. 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.
  539. // See if we need to perform TLS or not. We prefer not to do TLS within CIRA.
  540. var dotls = -1;
  541. if (ciraconn.tag.boundPorts.indexOf('16992')) { dotls = 0; }
  542. else if (ciraconn.tag.boundPorts.indexOf('16993')) { dotls = 1; }
  543. if (dotls == -1) { removeAmtDevice(dev, 10); return; } // The Intel AMT ports are not open, not a device we can deal with.
  544. // Connect now
  545. parent.debug('amt', dev.name, 'CIRA-Connect', (dotls == 1) ? "TLS" : "NoTLS", user, pass);
  546. var comm;
  547. if (dotls == 1) {
  548. comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
  549. comm.xtlsFingerprint = 0; // Perform no certificate checking
  550. } else {
  551. comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, ciraconn); // No TLS
  552. }
  553. var wsstack = WsmanStackCreateService(comm);
  554. dev.amtstack = AmtStackCreateService(wsstack);
  555. dev.amtstack.dev = dev;
  556. dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
  557. break;
  558. case 1: // CIRA-Relay
  559. case 2: // CIRA-LMS
  560. // Handle the case where the Intel AMT relay or LMS is connected (connType 1 or 2)
  561. // Check to see if CIRA is connected on this server.
  562. var ciraconn = dev.mpsConnection;
  563. if ((ciraconn == null) || (ciraconn.tag == null) || (ciraconn.tag.boundPorts == null)) { removeAmtDevice(dev, 11); return; } // Relay connection not valid
  564. // Connect now
  565. var comm;
  566. if ((dev.tlsfail !== true) && (parent.config.domains[dev.domainid].amtmanager.tlsconnections !== false) && (dev.intelamt.tls == 1)) {
  567. parent.debug('amt', dev.name, (dev.connType == 1) ? 'Relay-Connect' : 'LMS-Connect', "TLS", user);
  568. comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
  569. comm.xtlsFingerprint = 0; // Perform no certificate checking
  570. } else {
  571. parent.debug('amt', dev.name, (dev.connType == 1) ? 'Relay-Connect' : 'LMS-Connect', "NoTLS", user);
  572. comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, ciraconn); // No TLS
  573. }
  574. var wsstack = WsmanStackCreateService(comm);
  575. dev.amtstack = AmtStackCreateService(wsstack);
  576. dev.amtstack.dev = dev;
  577. dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
  578. break;
  579. case 3: // Local LAN
  580. // Check if Intel AMT is activated. If not, stop here.
  581. if ((dev.intelamt == null) || ((dev.intelamt.state != null) && (dev.intelamt.state != 2))) { removeAmtDevice(dev, 12); return; }
  582. // Handle the case where the Intel AMT local scanner found the device (connType 3)
  583. parent.debug('amt', dev.name, "Attempt Initial Local Contact", dev.connType, dev.host);
  584. if (typeof dev.host != 'string') { removeAmtDevice(dev, 13); return; } // Local connection not valid
  585. // Since we don't allow two or more connections to the same host, check if a pending connection is active.
  586. if (obj.activeLocalConnections[dev.host] != null) {
  587. // Active connection, hold and try later.
  588. var tryAgainFunc = function tryAgainFunc() { if (obj.amtDevices[tryAgainFunc.dev.nodeid] != null) { attemptInitialContact(tryAgainFunc.dev); } }
  589. tryAgainFunc.dev = dev;
  590. setTimeout(tryAgainFunc, 5000);
  591. } else {
  592. // No active connections
  593. // Connect now
  594. var comm;
  595. if ((dev.tlsfail !== true) && (parent.config.domains[dev.domainid].amtmanager.tlsconnections !== false) && (dev.intelamt.tls == 1)) {
  596. parent.debug('amt', dev.name, 'Direct-Connect', "TLS", dev.host, user);
  597. comm = CreateWsmanComm(dev.host, 16993, user, pass, 1); // Always try with TLS first
  598. comm.xtlsFingerprint = 0; // Perform no certificate checking
  599. } else {
  600. parent.debug('amt', dev.name, 'Direct-Connect', "NoTLS", dev.host, user);
  601. comm = CreateWsmanComm(dev.host, 16992, user, pass, 0); // Try without TLS
  602. }
  603. var wsstack = WsmanStackCreateService(comm);
  604. dev.amtstack = AmtStackCreateService(wsstack);
  605. dev.amtstack.dev = dev;
  606. obj.activeLocalConnections[dev.host] = dev;
  607. dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
  608. }
  609. break;
  610. }
  611. }
  612. function attemptLocalConnectResponse(stack, name, responses, status) {
  613. const dev = stack.dev;
  614. parent.debug('amt', dev.name, "Initial Contact Response", status);
  615. // If this is a local connection device, release active connection to this host.
  616. if (dev.connType == 3) { delete obj.activeLocalConnections[dev.host]; }
  617. // Check if the device still exists
  618. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  619. // Check the response
  620. 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)) {
  621. // Everything looks good
  622. dev.consoleMsg(stack.wsman.comm.xtls ? "Intel AMT connected with TLS." : "Intel AMT connected.");
  623. dev.state = 1;
  624. if (dev.aquired == null) { dev.aquired = {}; }
  625. dev.aquired.controlMode = responses['IPS_HostBasedSetupService'].response.CurrentControlMode; // 1 = CCM, 2 = ACM
  626. if (typeof stack.wsman.comm.amtVersion == 'string') { // Set the Intel AMT version using the HTTP header if present
  627. var verSplit = stack.wsman.comm.amtVersion.split('.');
  628. if (verSplit.length >= 2) {
  629. dev.aquired.version = verSplit[0] + '.' + verSplit[1];
  630. dev.aquired.majorver = parseInt(verSplit[0]);
  631. dev.aquired.minorver = parseInt(verSplit[1]);
  632. if (verSplit.length >= 3) {
  633. dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
  634. dev.aquired.maintenancever = parseInt(verSplit[2]);
  635. }
  636. }
  637. }
  638. dev.aquired.realm = stack.wsman.comm.digestRealm;
  639. dev.aquired.user = dev.intelamt.user = stack.wsman.comm.user;
  640. dev.aquired.pass = dev.intelamt.pass = stack.wsman.comm.pass;
  641. dev.aquired.lastContact = Date.now();
  642. dev.aquired.warn = 0; // Clear all warnings (TODO: Check Realm and TLS cert pinning)
  643. 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.
  644. if (stack.wsman.comm.xtls == 1) { dev.aquired.hash = stack.wsman.comm.xtlsCertificate.fingerprint.split(':').join('').toLowerCase(); } else { delete dev.aquired.hash; }
  645. UpdateDevice(dev);
  646. // If this is the new first user/pass for the device UUID, update the activation log now.
  647. 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)) {
  648. 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 });
  649. }
  650. // Perform Intel AMT clock sync
  651. attemptSyncClock(dev, function (dev) {
  652. // Check Intel AMT TLS state
  653. attemptTlsSync(dev, function (dev) {
  654. // If we need to switch to TLS, do it now.
  655. if (dev.switchToTls == 1) { delete dev.switchToTls; attemptInitialContact(dev); return; }
  656. // Check Intel AMT 802.1x wired state and Intel AMT WIFI state (must be done both at once).
  657. attemptWifiSync(dev, function (dev) {
  658. // Check Intel AMT root certificate state
  659. attemptRootCertSync(dev, function (dev) {
  660. // Check Intel AMT CIRA settings
  661. attemptCiraSync(dev, function (dev) {
  662. // Check Intel AMT settings
  663. attemptSettingsSync(dev, function (dev) {
  664. // Clean unused certificates
  665. attemptCleanCertsSync(dev, function (dev) {
  666. // See if we need to get hardware inventory
  667. attemptFetchHardwareInventory(dev, function (dev) {
  668. dev.consoleMsg('Done.');
  669. // Remove from task limiter if needed
  670. if (dev.taskid != null) { obj.parent.taskLimiter.completed(dev.taskid); delete dev.taskLimiter; }
  671. if (dev.connType != 2) {
  672. // Start power polling if not connected to LMS
  673. var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); }
  674. ppfunc.dev = dev;
  675. if(dev.polltimer){ clearInterval(dev.polltimer); delete dev.polltimer; }
  676. dev.polltimer = new setInterval(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
  677. fetchPowerState(dev);
  678. } else {
  679. // For LMS connections, close now.
  680. dev.controlMsg({ action: 'close' });
  681. }
  682. });
  683. });
  684. });
  685. });
  686. });
  687. });
  688. });
  689. });
  690. } else {
  691. // We got a bad response
  692. 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.
  693. // non-TLS error on a local connection, try again with TLS
  694. dev.tlsfail = false; dev.intelamt.tls = 1; attemptInitialContact(dev); return;
  695. } 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.
  696. // TLS error on a local connection, try again without TLS
  697. dev.tlsfail = true; dev.intelamt.tls = 0; attemptInitialContact(dev); return;
  698. } else if (status == 401) {
  699. // Authentication error, see if we can use alternative credentials
  700. if (dev.acctry != null) {
  701. // Remove the first password from the trial list since it did not work.
  702. if (dev.acctry.length > 0) { dev.acctry.shift(); }
  703. // We have another password to try, hold 20 second and try the next user/password.
  704. if (dev.acctry.length > 0) {
  705. dev.consoleMsg("Holding 20 seconds and trying again with different credentials...");
  706. setTimeout(function () { if (isAmtDeviceValid(dev)) { attemptInitialContact(dev); } }, 20000); return;
  707. }
  708. }
  709. // If this device is in CCM mode and we have a bad password reset policy, do it now.
  710. 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)) {
  711. deactivateIntelAmtCCM(dev);
  712. return;
  713. }
  714. // We are unable to authenticate to this device
  715. dev.consoleMsg("Unable to connect.");
  716. // Set an error that we can't login to this device
  717. if (dev.aquired == null) { dev.aquired = {}; }
  718. dev.aquired.warn = 1; // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch, 8 = Trying credentials
  719. UpdateDevice(dev);
  720. }
  721. //console.log(dev.nodeid, dev.name, dev.host, status, 'Bad response');
  722. removeAmtDevice(dev, 14);
  723. }
  724. }
  725. //
  726. // Intel AMT Database Update
  727. //
  728. // Change the current core information string and event it
  729. function UpdateDevice(dev) {
  730. // Check that the mesh exists
  731. const mesh = parent.webserver.meshes[dev.meshid];
  732. if (mesh == null) { removeAmtDevice(dev, 15); return false; }
  733. // Get the node and change it if needed
  734. parent.db.Get(dev.nodeid, function (err, nodes) {
  735. if ((nodes == null) || (nodes.length != 1)) return false;
  736. const device = nodes[0];
  737. var changes = [], change = 0, log = 0;
  738. var domain = parent.config.domains[device.domain];
  739. if (domain == null) return false;
  740. // Check if anything changes
  741. if (device.intelamt == null) { device.intelamt = {}; }
  742. 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'); }
  743. 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'); }
  744. 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'); }
  745. 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'); }
  746. 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'); }
  747. 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'); }
  748. 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'); }
  749. 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');*/ }
  750. 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'); }
  751. // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch, 8 = Trying credentials
  752. if ((typeof dev.aquired.warn == 'number')) {
  753. if ((dev.aquired.warn == 0) && (device.intelamt.warn != null)) { delete device.intelamt.warn; change = 1; }
  754. else if ((dev.aquired.warn != 0) && (dev.aquired.warn != device.intelamt.warn)) { device.intelamt.warn = dev.aquired.warn; change = 1; }
  755. }
  756. // Update Intel AMT flags if needed
  757. // dev.aquired.controlMode // 1 = CCM, 2 = ACM
  758. // (node.intelamt.flags & 2) == CCM, (node.intelamt.flags & 4) == ACM
  759. var flags = 0;
  760. if (typeof device.intelamt.flags == 'number') { flags = device.intelamt.flags; }
  761. if (dev.aquired.controlMode == 1) { if ((flags & 4) != 0) { flags -= 4; } if ((flags & 2) == 0) { flags += 2; } } // CCM
  762. if (dev.aquired.controlMode == 2) { if ((flags & 4) == 0) { flags += 4; } if ((flags & 2) != 0) { flags -= 2; } } // ACM
  763. if (device.intelamt.flags != flags) { change = 1; log = 1; device.intelamt.flags = flags; changes.push('AMT flags'); }
  764. // If there are changes, event the new device
  765. if (change == 1) {
  766. // Save to the database
  767. parent.db.Set(device);
  768. // Event the node change
  769. var event = { etype: 'node', action: 'changenode', nodeid: device._id, domain: domain.id, node: parent.webserver.CloneSafeNode(device) };
  770. if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
  771. 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
  772. 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.
  773. parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(device.meshid, [device._id]), obj, event);
  774. }
  775. });
  776. }
  777. // Change the current core information string and event it
  778. function ClearDeviceCredentials(dev) {
  779. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  780. // Check that the mesh exists
  781. const mesh = parent.webserver.meshes[dev.meshid];
  782. if (mesh == null) { removeAmtDevice(dev, 16); return; }
  783. // Get the node and change it if needed
  784. parent.db.Get(dev.nodeid, function (err, nodes) {
  785. if ((nodes == null) || (nodes.length != 1)) return;
  786. const device = nodes[0];
  787. var changes = [], change = 0, log = 0;
  788. var domain = parent.config.domains[device.domain];
  789. if (domain == null) return;
  790. // Check if anything changes
  791. if (device.intelamt == null) return;
  792. if (device.intelamt.user != null) { change = 1; log = 1; delete device.intelamt.user; changes.push('AMT user'); }
  793. if (device.intelamt.pass != null) { change = 1; log = 1; delete device.intelamt.pass; changes.push('AMT pass'); }
  794. // If there are changes, event the new device
  795. if (change == 1) {
  796. // Save to the database
  797. parent.db.Set(device);
  798. // Event the node change
  799. var event = { etype: 'node', action: 'changenode', nodeid: device._id, domain: domain.id, node: parent.webserver.CloneSafeNode(device) };
  800. if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
  801. 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
  802. 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.
  803. parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(device.meshid, [device._id]), obj, event);
  804. }
  805. });
  806. }
  807. //
  808. // Intel AMT Power State
  809. //
  810. // Get the current power state of a device
  811. function fetchPowerState(dev) {
  812. if (isAmtDeviceValid(dev) == false) return;
  813. // Check if the agent is connected
  814. var constate = parent.GetConnectivityState(dev.nodeid);
  815. if ((constate == null) || (constate.connectivity & 1)) return; // If there is no connectivity or the agent is connected, skip trying to poll power state.
  816. // Fetch the power state
  817. dev.amtstack.BatchEnum(null, ['CIM_ServiceAvailableToElement'], function (stack, name, responses, status) {
  818. const dev = stack.dev;
  819. if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
  820. 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.
  821. var powerstate = responses['CIM_ServiceAvailableToElement'].responses[0].PowerState;
  822. if ((powerstate == 2) && (dev.aquired.majorver != null) && (dev.aquired.majorver > 9)) {
  823. // Device is powered on and Intel AMT 10+, poll the OS power state.
  824. dev.amtstack.Get('IPS_PowerManagementService', function (stack, name, response, status) {
  825. const dev = stack.dev;
  826. if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
  827. if (status != 200) return;
  828. // Convert the OS power state
  829. var meshPowerState = -1;
  830. if (response.Body.OSPowerSavingState == 2) { meshPowerState = 1; } // Fully powered (S0);
  831. else if (response.Body.OSPowerSavingState == 3) { meshPowerState = 2; } // Modern standby (We are going to call this S1);
  832. // Set OS power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
  833. if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); }
  834. });
  835. } else {
  836. // Convert the power state
  837. // 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)
  838. // 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
  839. var meshPowerState = -1, powerConversionTable = [-1, -1, 1, 2, 3, 6, 6, 5, 6];
  840. if (powerstate < powerConversionTable.length) { meshPowerState = powerConversionTable[powerstate]; } else { powerstate = 6; }
  841. // Set power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
  842. if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); }
  843. }
  844. });
  845. }
  846. // 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
  847. function performPowerAction(nodeid, action) {
  848. console.log('performPowerAction', nodeid, action);
  849. var devices = obj.amtDevices[nodeid];
  850. if (devices == null) return;
  851. for (var i in devices) {
  852. var dev = devices[i];
  853. // If not LMS, has a AMT stack present and is in connected state, perform power operation.
  854. if ((dev.connType != 2) && (dev.state == 1) && (dev.amtstack != null)) {
  855. parent.debug('amt', dev.name, "performPowerAction", action);
  856. dev.powerAction = action;
  857. if (action <= 10) {
  858. // Action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset
  859. try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { }
  860. } else {
  861. // 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
  862. dev.amtstack.BatchEnum(null, ['*AMT_BootSettingData'], performAdvancedPowerActionResponse);
  863. }
  864. }
  865. }
  866. }
  867. // Response to Intel AMT advanced power action
  868. function performAdvancedPowerActionResponse(stack, name, responses, status) {
  869. const dev = stack.dev;
  870. const action = dev.powerAction;
  871. delete dev.powerAction;
  872. if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
  873. if (status != 200) return;
  874. if ((responses['AMT_BootSettingData'] == null) || (responses['AMT_BootSettingData'].response == null)) return;
  875. var bootSettingData = responses['AMT_BootSettingData'].response;
  876. // Clean up parameters
  877. bootSettingData['ConfigurationDataReset'] = false;
  878. delete bootSettingData['WinREBootEnabled'];
  879. delete bootSettingData['UEFILocalPBABootEnabled'];
  880. delete bootSettingData['UEFIHTTPSBootEnabled'];
  881. delete bootSettingData['SecureBootControlEnabled'];
  882. delete bootSettingData['BootguardStatus'];
  883. delete bootSettingData['OptionsCleared'];
  884. delete bootSettingData['BIOSLastStatus'];
  885. delete bootSettingData['UefiBootParametersArray'];
  886. delete bootSettingData['RPEEnabled'];
  887. delete bootSettingData['RSEPassword']
  888. // Ready boot parameters
  889. bootSettingData['BIOSSetup'] = ((action >= 11) && (action <= 14));
  890. bootSettingData['UseSOL'] = ((action >= 13) && (action <= 14));
  891. if ((action == 11) || (action == 13) || (action == 15)) { dev.powerAction = 2; } // Power on
  892. if ((action == 12) || (action == 14) || (action == 16)) { dev.powerAction = 10; } // Reset
  893. // Set boot parameters
  894. dev.amtstack.Put('AMT_BootSettingData', bootSettingData, function (stack, name, response, status, tag) {
  895. const dev = stack.dev;
  896. if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
  897. // Set boot config
  898. dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status, tag) {
  899. const dev = stack.dev;
  900. if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
  901. // Set boot order
  902. 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;
  903. dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(bootDevice, function (stack, name, response, status) {
  904. const dev = stack.dev;
  905. if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
  906. // Perform power action
  907. try { dev.amtstack.RequestPowerStateChange(dev.powerAction, performPowerActionResponse); } catch (ex) { }
  908. }, 0, 1);
  909. }, 0, 1);
  910. }, 0, 1);
  911. }
  912. // Response to Intel AMT power action
  913. function performPowerActionResponse(stack, name, responses, status) {
  914. const dev = stack.dev;
  915. const action = dev.powerAction;
  916. delete dev.powerAction;
  917. if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
  918. if (status != 200) return;
  919. // If this is Intel AMT 10 or higher and we are trying to wake the device, send an OS wake.
  920. // This will wake the device from "Modern Standby".
  921. if ((action == 2) && (dev.aquired.majorver > 9)) {
  922. try { dev.amtstack.RequestOSPowerStateChange(2, function (stack, name, response, status) { }); } catch (ex) { }
  923. }
  924. }
  925. //
  926. // Intel AMT One Click Recovery
  927. //
  928. // Perform Intel AMT One Click Recovery on a device
  929. function performOneClickRecoveryAction(nodeid, file) {
  930. var devices = obj.amtDevices[nodeid];
  931. if (devices == null) return;
  932. for (var i in devices) {
  933. var dev = devices[i];
  934. // If not LMS, has a AMT stack present and is in connected state, perform operation.
  935. if ((dev.connType != 2) && (dev.state == 1) && (dev.amtstack != null)) {
  936. // Make sure the MPS server root certificate is present.
  937. // Start by looking at existing certificates.
  938. dev.ocrfile = file;
  939. dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', '*AMT_BootCapabilities'], performOneClickRecoveryActionEx);
  940. }
  941. }
  942. }
  943. // Response with list of certificates in Intel AMT
  944. function performOneClickRecoveryActionEx(stack, name, responses, status) {
  945. const dev = stack.dev;
  946. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  947. if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); delete dev.ocrfile; return; }
  948. // Check if this Intel AMT device supports OCR
  949. if (responses['AMT_BootCapabilities'].response['ForceUEFIHTTPSBoot'] !== true) {
  950. dev.consoleMsg("This Intel AMT device does not support UEFI HTTPS boot (" + status + ")."); delete dev.ocrfile; return;
  951. }
  952. // Organize the certificates and add the MPS root cert if missing
  953. var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
  954. for (var i in xxCertificates) {
  955. xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
  956. xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
  957. xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
  958. xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
  959. }
  960. dev.policy.certificates = xxCertificates;
  961. attemptRootCertSync(dev, performOneClickRecoveryActionEx2, true);
  962. }
  963. // MPS root certificate was added
  964. function performOneClickRecoveryActionEx2(dev) {
  965. // Ask for Boot Settings Data
  966. dev.amtstack.Get('AMT_BootSettingData', performOneClickRecoveryActionEx3, 0, 1);
  967. }
  968. // Getting Intel AMT Boot Settings Data
  969. function performOneClickRecoveryActionEx3(stack, name, response, status) {
  970. const dev = stack.dev;
  971. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  972. if (status != 200) { dev.consoleMsg("Failed to get boot settings data (" + status + ")."); delete dev.ocrfile; return; }
  973. // Generate the one-time URL.
  974. var cookie = obj.parent.encodeCookie({ a: 'f', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey)
  975. var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.efi';
  976. delete dev.ocrfile;
  977. // Generate the boot data for OCR with URL
  978. var r = response.Body;
  979. r['BIOSPause'] = false;
  980. r['BIOSSetup'] = false;
  981. r['EnforceSecureBoot'] = false;
  982. r['UefiBootParametersArray'] = Buffer.from(makeUefiBootParam(1, url) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2), 'binary').toString('base64');
  983. r['UefiBootNumberOfParams'] = 3;
  984. r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
  985. // Set the boot order to null, this is needed for some Intel AMT versions that don't clear this automatically.
  986. dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(null, function (stack, name, response, status) {
  987. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  988. if (status != 200) { dev.consoleMsg("Failed to set boot order (" + status + ")."); return; }
  989. dev.amtstack.Put('AMT_BootSettingData', r, performOneClickRecoveryActionEx4, 0, 1);
  990. }, 0, 1);
  991. }
  992. // Intel AMT Put Boot Settings
  993. function performOneClickRecoveryActionEx4(stack, name, response, status) {
  994. const dev = stack.dev;
  995. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  996. if (status != 200) { dev.consoleMsg("Failed to set boot settings data (" + status + ")."); return; }
  997. dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status) {
  998. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  999. if (status != 200) { dev.consoleMsg("Failed to set boot config role (" + status + ")."); return; }
  1000. 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) {
  1001. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1002. if (status != 200) { dev.consoleMsg("Failed to set boot config (" + status + ")."); return; }
  1003. dev.amtstack.RequestPowerStateChange(10, function (stack, name, response, status) { // 10 = Reset, 2 = Power Up
  1004. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1005. if (status != 200) { dev.consoleMsg("Failed to perform power action (" + status + ")."); return; }
  1006. console.log('One Click Recovery Completed.');
  1007. });
  1008. });
  1009. }, 0, 1);
  1010. }
  1011. //
  1012. // Intel AMT Clock Syncronization
  1013. //
  1014. // Attempt to sync the Intel AMT clock if needed, call func back when done.
  1015. // Care should be take not to have many pending WSMAN called when performing clock sync.
  1016. function attemptSyncClock(dev, func) {
  1017. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1018. if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
  1019. dev.taskCount = 1;
  1020. dev.taskCompleted = func;
  1021. dev.amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(attemptSyncClockEx);
  1022. }
  1023. // Intel AMT clock query response
  1024. function attemptSyncClockEx(stack, name, response, status) {
  1025. const dev = stack.dev;
  1026. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1027. if (status != 200) { dev.consoleMsg("Failed to get clock (" + status + ")."); removeAmtDevice(dev, 17); return; }
  1028. // Compute how much drift between Intel AMT and our clock.
  1029. var t = new Date(), now = new Date();
  1030. t.setTime(response.Body['Ta0'] * 1000);
  1031. if (Math.abs(t - now) > 10000) { // If the Intel AMT clock is more than 10 seconds off, set it.
  1032. dev.consoleMsg("Performing clock sync.");
  1033. var Tm1 = Math.round(now.getTime() / 1000);
  1034. dev.amtstack.AMT_TimeSynchronizationService_SetHighAccuracyTimeSynch(response.Body['Ta0'], Tm1, Tm1, attemptSyncClockSet);
  1035. } else {
  1036. // Clock is fine, we are done.
  1037. devTaskCompleted(dev)
  1038. }
  1039. }
  1040. // Intel AMT clock set response
  1041. function attemptSyncClockSet(stack, name, responses, status) {
  1042. const dev = stack.dev;
  1043. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1044. if (status != 200) { dev.consoleMsg("Failed to sync clock (" + status + ")."); removeAmtDevice(dev, 18); }
  1045. devTaskCompleted(dev)
  1046. }
  1047. //
  1048. // Intel AMT TLS setup
  1049. //
  1050. // Check if Intel AMT TLS state is correct
  1051. function attemptTlsSync(dev, func) {
  1052. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1053. if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
  1054. dev.taskCount = 1;
  1055. dev.taskCompleted = func;
  1056. // TODO: We only deal with certificates starting with Intel AMT 6 and beyond
  1057. dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', 'AMT_PublicPrivateKeyPair', 'AMT_TLSSettingData', 'AMT_TLSCredentialContext'], attemptTlsSyncEx);
  1058. }
  1059. // Intel AMT is not always in a good spot to generate a key pair. This will retry at 10 second interval.
  1060. function generateKeyPairWithRetry(dev, func) {
  1061. if (isAmtDeviceValid(dev) == false) return;
  1062. if (dev.keyPairAttempts == null) { dev.keyPairAttempts = 1; } else { dev.keyPairAttempts++; }
  1063. dev.amtstack.AMT_PublicKeyManagementService_GenerateKeyPair(0, 2048, function (stack, name, responses, status) {
  1064. if (isAmtDeviceValid(dev) == false) { delete dev.keyPairAttempts; return; }
  1065. if ((status == 200) || (dev.keyPairAttempts > 19)) {
  1066. delete dev.keyPairAttempts;
  1067. func(stack, name, responses, status);
  1068. } else {
  1069. if ((responses.Body != null) && (responses.Body.ReturnValue != null) && (responses.Body.ReturnValueStr != null)) {
  1070. dev.consoleMsg("Failed to generate a key pair (" + status + ", " + responses.Body.ReturnValue + ", \"" + responses.Body.ReturnValueStr + "\"), attempt " + dev.keyPairAttempts + ", trying again in 10 seconds...");
  1071. } else {
  1072. dev.consoleMsg("Failed to generate a key pair (" + status + "), attempt " + dev.keyPairAttempts + ", trying again in 10 seconds...");
  1073. }
  1074. // Wait 10 seconds before attempting again
  1075. var f = function doManage() { generateKeyPairWithRetry(doManage.dev, doManage.func); }
  1076. f.dev = dev;
  1077. f.func = func;
  1078. setTimeout(f, 10000);
  1079. }
  1080. });
  1081. }
  1082. function attemptTlsSyncEx(stack, name, responses, status) {
  1083. const dev = stack.dev;
  1084. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1085. if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); removeAmtDevice(dev, 19); return; }
  1086. // Setup the certificates
  1087. dev.policy.certPrivateKeys = responses['AMT_PublicPrivateKeyPair'].responses;
  1088. dev.policy.tlsSettings = responses['AMT_TLSSettingData'].responses;
  1089. dev.policy.tlsCredentialContext = responses['AMT_TLSCredentialContext'].responses;
  1090. var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
  1091. for (var i in xxCertificates) {
  1092. xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
  1093. xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
  1094. xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
  1095. xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
  1096. }
  1097. amtcert_linkCertPrivateKey(xxCertificates, dev.policy.certPrivateKeys);
  1098. dev.policy.certificates = xxCertificates;
  1099. // Find the current TLS certificate & MeshCentral root certificate
  1100. var xxTlsCurrentCert = null;
  1101. if (dev.policy.tlsCredentialContext.length > 0) {
  1102. var certInstanceId = dev.policy.tlsCredentialContext[0]['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'];
  1103. for (var i in dev.policy.certificates) { if (dev.policy.certificates[i]['InstanceID'] == certInstanceId) { xxTlsCurrentCert = i; } }
  1104. }
  1105. // This is a managed device and TLS is not enabled, turn it on.
  1106. if (xxTlsCurrentCert == null) {
  1107. // Start by generating a key pair
  1108. generateKeyPairWithRetry(dev, function (stack, name, responses, status) {
  1109. const dev = stack.dev;
  1110. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1111. if (status != 200) { dev.consoleMsg("Failed to generate a key pair (" + status + ")."); removeAmtDevice(dev, 20); return; }
  1112. // Check that we get a key pair reference
  1113. var x = null;
  1114. try { x = responses.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']; } catch (ex) { }
  1115. if (x == null) { dev.consoleMsg("Unable to get key pair reference."); removeAmtDevice(dev, 21); return; }
  1116. // Get the new key pair
  1117. dev.amtstack.Enum('AMT_PublicPrivateKeyPair', function (stack, name, responses, status, tag) {
  1118. const dev = stack.dev;
  1119. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1120. if (status != 200) { dev.consoleMsg("Failed to get a key pair list (" + status + ")."); removeAmtDevice(dev, 22); return; }
  1121. // Get the new DER key
  1122. var DERKey = null;
  1123. for (var i in responses) { if (responses[i]['InstanceID'] == tag) { DERKey = responses[i]['DERKey']; } }
  1124. // Get certificate values
  1125. const commonName = 'IntelAMT-' + Buffer.from(parent.crypto.randomBytes(6), 'binary').toString('hex');
  1126. const domain = parent.config.domains[dev.domainid];
  1127. var serverName = 'MeshCentral';
  1128. if ((domain != null) && (domain.title != null)) { serverName = domain.title; }
  1129. const certattributes = { 'CN': commonName, 'O': serverName, 'ST': 'MC', 'C': 'MC' };
  1130. // See what root certificate to use to sign the TLS cert
  1131. var xxCaPrivateKey = obj.parent.certificates.root.key; // Use our own root by default
  1132. var issuerattributes = { 'CN': obj.rootCertCN };
  1133. if (domain.amtmanager.tlsrootcert2 != null) {
  1134. xxCaPrivateKey = domain.amtmanager.tlsrootcert2.key;
  1135. issuerattributes = domain.amtmanager.tlsrootcert2.attributes;
  1136. // TODO: We should change the start and end dates of our issued certificate to at least match the root.
  1137. // TODO: We could do one better and auto-renew TLS certificates as needed.
  1138. }
  1139. // Set the extended key usages
  1140. var extKeyUsage = { name: 'extKeyUsage', serverAuth: true, clientAuth: true }
  1141. // Sign the key pair using the CA certifiate
  1142. const cert = obj.amtcert_createCertificate(certattributes, xxCaPrivateKey, DERKey, issuerattributes, extKeyUsage);
  1143. if (cert == null) { dev.consoleMsg("Failed to sign the TLS certificate."); removeAmtDevice(dev, 23); return; }
  1144. // Place the resulting signed certificate back into AMT
  1145. var pem = obj.parent.certificateOperations.forge.pki.certificateToPem(cert).replace(/(\r\n|\n|\r)/gm, '');
  1146. // Set the certificate finderprint (SHA1)
  1147. var md = obj.parent.certificateOperations.forge.md.sha1.create();
  1148. md.update(obj.parent.certificateOperations.forge.asn1.toDer(obj.parent.certificateOperations.forge.pki.certificateToAsn1(cert)).getBytes());
  1149. dev.aquired.xhash = md.digest().toHex();
  1150. dev.amtstack.AMT_PublicKeyManagementService_AddCertificate(pem.substring(27, pem.length - 25), function (stack, name, responses, status) {
  1151. const dev = stack.dev;
  1152. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1153. if (status != 200) { dev.consoleMsg("Failed to add TLS certificate (" + status + ")."); removeAmtDevice(dev, 24); return; }
  1154. var certInstanceId = null;
  1155. try { certInstanceId = responses.Body['CreatedCertificate']['ReferenceParameters']['SelectorSet']['Selector']['Value']; } catch (ex) { }
  1156. if (certInstanceId == null) { dev.consoleMsg("Failed to get TLS certificate identifier."); removeAmtDevice(dev, 25); return; }
  1157. // Set the TLS certificate
  1158. if (dev.hbacmtls == 1) {
  1159. dev.setTlsSecurityPendingCalls = 2; // Set remote port only
  1160. } else {
  1161. dev.setTlsSecurityPendingCalls = 3; // Set local and remote port
  1162. }
  1163. if (dev.policy.tlsCredentialContext.length > 0) {
  1164. // Modify the current context
  1165. var newTLSCredentialContext = Clone(dev.policy.tlsCredentialContext[0]);
  1166. newTLSCredentialContext['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'] = certInstanceId;
  1167. dev.amtstack.Put('AMT_TLSCredentialContext', newTLSCredentialContext, amtSwitchToTls, 0, 1);
  1168. } else {
  1169. // Add a new security context
  1170. dev.amtstack.Create('AMT_TLSCredentialContext', {
  1171. '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>',
  1172. '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>'
  1173. }, amtSwitchToTls);
  1174. }
  1175. // Figure out what index is local & remote
  1176. 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);
  1177. // Remote TLS settings
  1178. var xxTlsSettings2 = Clone(dev.policy.tlsSettings);
  1179. xxTlsSettings2[remoteNdx]['Enabled'] = true;
  1180. xxTlsSettings2[remoteNdx]['MutualAuthentication'] = false;
  1181. xxTlsSettings2[remoteNdx]['AcceptNonSecureConnections'] = true;
  1182. delete xxTlsSettings2[remoteNdx]['TrustedCN'];
  1183. // Local TLS settings
  1184. xxTlsSettings2[localNdx]['Enabled'] = true;
  1185. delete xxTlsSettings2[localNdx]['TrustedCN'];
  1186. if (dev.hbacmtls == 1) {
  1187. // If we are doing Host-based TLS ACM activation, you need to only enable the remote port with TLS.
  1188. // If you enable on local port, the commit will succeed but be ignored.
  1189. dev.consoleMsg("Enabling TLS on remote port...");
  1190. if (remoteNdx == 0) { dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[0], amtSwitchToTls, 0, 1, xxTlsSettings2[0]); }
  1191. else { dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[1], amtSwitchToTls, 0, 1, xxTlsSettings2[1]); }
  1192. delete dev.hbacmtls; // Remove this indication
  1193. } else {
  1194. // Update TLS settings
  1195. dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[0], amtSwitchToTls, 0, 1, xxTlsSettings2[0]);
  1196. dev.amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[1], amtSwitchToTls, 0, 1, xxTlsSettings2[1]);
  1197. }
  1198. });
  1199. }, responses.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']);
  1200. });
  1201. } else {
  1202. // Update device in the database
  1203. dev.intelamt.tls = dev.aquired.tls = 1;
  1204. UpdateDevice(dev);
  1205. // TLS is setup
  1206. devTaskCompleted(dev);
  1207. }
  1208. }
  1209. function amtSwitchToTls(stack, name, responses, status) {
  1210. const dev = stack.dev;
  1211. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1212. if (status != 200) { dev.consoleMsg("Failed setup TLS (" + status + ")."); removeAmtDevice(dev, 26); return; }
  1213. // Check if all the calls are done & perform a commit
  1214. if ((--dev.setTlsSecurityPendingCalls) == 0) {
  1215. dev.consoleMsg("Performing Commit...");
  1216. dev.amtstack.AMT_SetupAndConfigurationService_CommitChanges(null, function (stack, name, responses, status) {
  1217. const dev = stack.dev;
  1218. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1219. if (status != 200) { dev.consoleMsg("Failed perform commit (" + status + ")."); removeAmtDevice(dev, 27); return; }
  1220. dev.consoleMsg("Enabled TLS, holding 10 seconds...");
  1221. // Update device in the database
  1222. dev.intelamt.tls = dev.aquired.tls = 1;
  1223. dev.intelamt.hash = dev.aquired.hash = dev.aquired.xhash;
  1224. delete dev.aquired.xhash;
  1225. UpdateDevice(dev);
  1226. // Switch our communications to TLS (Restart our management of this node)
  1227. dev.switchToTls = 1;
  1228. delete dev.tlsfail;
  1229. // Wait 5 seconds before attempting to manage this device some more
  1230. var f = function doManage() { if (isAmtDeviceValid(dev)) { devTaskCompleted(doManage.dev); } }
  1231. f.dev = dev;
  1232. setTimeout(f, 10000);
  1233. });
  1234. }
  1235. }
  1236. //
  1237. // Intel AMT WIFI & Wired 802.1x
  1238. //
  1239. // Check which key pair matches the public key in the certificate
  1240. function amtcert_linkCertPrivateKey(certs, keys) {
  1241. for (var i in certs) {
  1242. var cert = certs[i];
  1243. try {
  1244. if (keys.length == 0) return;
  1245. var publicKeyPEM = forge.pki.publicKeyToPem(forge.pki.certificateFromAsn1(forge.asn1.fromDer(cert.X509Certificate)).publicKey).substring(28 + 32).replace(/(\r\n|\n|\r)/gm, "");
  1246. for (var j = 0; j < keys.length; j++) {
  1247. if (publicKeyPEM === (keys[j]['DERKey'] + '-----END PUBLIC KEY-----')) {
  1248. keys[j].XCert = cert; // Link the key pair to the certificate
  1249. cert.XPrivateKey = keys[j]; // Link the certificate to the key pair
  1250. }
  1251. }
  1252. } catch (e) { console.log(e); }
  1253. }
  1254. }
  1255. // This method will sync the WIFI profiles from the device and the server, but does not care about profile priority.
  1256. // 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
  1257. // We may want to work on an alternate version that does do priority if requested.
  1258. function attemptWifiSync(dev, func) {
  1259. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1260. if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
  1261. if (dev.connType != 2) { func(dev); return; } // Only configure wireless over a CIRA-LMS link
  1262. //if (parent.config.domains[dev.domainid].amtmanager.wifiprofiles == null) { func(dev); return; } // No server WIFI profiles set, skip this.
  1263. //if ((dev.mpsConnection.tag.meiState == null) || (dev.mpsConnection.tag.meiState.net1 == null)) { func(dev); return; } // No WIFI on this device, skip this.
  1264. // Get the current list of WIFI profiles, wireless interface state and wired 802.1x profile
  1265. dev.taskCount = 1;
  1266. dev.taskCompleted = func;
  1267. const objQuery = ['CIM_WiFiEndpointSettings', '*CIM_WiFiPort', '*AMT_WiFiPortConfigurationService', 'CIM_IEEE8021xSettings', 'AMT_PublicKeyCertificate', 'AMT_PublicPrivateKeyPair'];
  1268. if (parent.config.domains[dev.domainid].amtmanager['802.1x'] != null) { objQuery.push('*AMT_8021XProfile'); }
  1269. dev.amtstack.BatchEnum(null, objQuery, function (stack, name, responses, status) {
  1270. const dev = stack.dev;
  1271. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1272. const domain = parent.config.domains[dev.domainid];
  1273. 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.
  1274. // See if we need to perform wired or wireless 802.1x configuration
  1275. var wiredConfig = ((parent.config.domains[dev.domainid].amtmanager['802.1x'] != null) && (responses['AMT_8021XProfile'] != null) && (responses['AMT_8021XProfile'].status == 200));
  1276. 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));
  1277. if (!wiredConfig && !wirelessConfig) { devTaskCompleted(dev); return; } // We can't get wired or wireless settings, ignore and carry on.
  1278. // Sort out the certificates
  1279. var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
  1280. var xxCertPrivateKeys = responses['AMT_PublicPrivateKeyPair'].responses;
  1281. for (var i in xxCertificates) {
  1282. xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
  1283. xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
  1284. xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
  1285. xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
  1286. }
  1287. amtcert_linkCertPrivateKey(xxCertificates, xxCertPrivateKeys); // This links all certificates and private keys
  1288. // Remove any unlinked private keys
  1289. for (var i in xxCertPrivateKeys) {
  1290. if (!xxCertPrivateKeys[i].XCert) {
  1291. dev.amtstack.Delete('AMT_PublicPrivateKeyPair', { 'InstanceID': xxCertPrivateKeys[i]['InstanceID'] }, function (stack, name, response, status) {
  1292. //if (status == 200) { dev.consoleMsg("Removed unassigned private key pair."); }
  1293. });
  1294. }
  1295. }
  1296. // Check if wired 802.1x needs updating
  1297. var newNetAuthProfileRequested = false;
  1298. var srvNetAuthProfile = domain.amtmanager['802.1x'];
  1299. var devNetAuthProfile = null;
  1300. var netAuthClientCertInstanceId = null;
  1301. if (wiredConfig) {
  1302. var wiredMatch = 0;
  1303. devNetAuthProfile = responses['AMT_8021XProfile'].response;
  1304. if ((srvNetAuthProfile === false) && (devNetAuthProfile != null)) {
  1305. // Remove the 802.1x profile
  1306. wiredMatch = 1;
  1307. } else if ((srvNetAuthProfile != null) && (devNetAuthProfile == null)) {
  1308. // Device has no 802.1x, add it
  1309. wiredMatch = 2;
  1310. } else if ((typeof srvNetAuthProfile == 'object') && (devNetAuthProfile != null)) {
  1311. // Check if the existing 802.1x profile look good
  1312. if (devNetAuthProfile.AuthenticationProtocol != srvNetAuthProfile.authenticationprotocol) { wiredMatch = 2; }
  1313. if (devNetAuthProfile.ServerCertificateName != srvNetAuthProfile.servercertificatename) { wiredMatch = 2; }
  1314. if (devNetAuthProfile.ServerCertificateNameComparison != srvNetAuthProfile.servercertificatenamecomparison) { wiredMatch = 2; }
  1315. if (devNetAuthProfile.ActiveInS0 != srvNetAuthProfile.availableins0) { wiredMatch = 2; }
  1316. if (typeof srvNetAuthProfile.satellitecredentials != 'string') {
  1317. // Credentials for this profile are in the config file
  1318. if (devNetAuthProfile.RoamingIdentity != srvNetAuthProfile.roamingidentity) { wiredMatch = 2; }
  1319. if (devNetAuthProfile.Username != srvNetAuthProfile.username) { wiredMatch = 2; }
  1320. if (devNetAuthProfile.Domain != srvNetAuthProfile.domain) { wiredMatch = 2; }
  1321. }
  1322. // If the existing 802.1x profile has a certificate, remember the client certificate instance id for later checking
  1323. if (devNetAuthProfile.ClientCertificate) { netAuthClientCertInstanceId = devNetAuthProfile.ClientCertificate.ReferenceParameters.SelectorSet.Selector.Value; }
  1324. }
  1325. if (wiredMatch == 2) { newNetAuthProfileRequested = true; }
  1326. }
  1327. if (wirelessConfig) {
  1328. // If we have server WIFI profiles to sync, do this now.
  1329. if (parent.config.domains[dev.domainid].amtmanager.wifiprofiles != null) {
  1330. // The server and device WIFI profiles, find profiles to add and remove
  1331. const sevProfiles = parent.config.domains[dev.domainid].amtmanager.wifiprofiles;
  1332. const devProfiles = responses['CIM_WiFiEndpointSettings'].responses;
  1333. const netAuthProfiles = responses['CIM_IEEE8021xSettings'].responses;
  1334. var profilesToAdd = [], profilesToRemove = [];
  1335. var profilesToAdd2 = [], profilesToRemove2 = [];
  1336. // Look at the WIFI profiles in the device
  1337. for (var i in sevProfiles) {
  1338. var sevProfile = sevProfiles[i], wirelessMatch = false;
  1339. for (var j in devProfiles) {
  1340. var devProfile = devProfiles[j];
  1341. if (
  1342. (devProfile.ElementName == sevProfile.name) &&
  1343. (devProfile.SSID == sevProfile.ssid) &&
  1344. (devProfile.AuthenticationMethod == sevProfile.authentication) &&
  1345. (devProfile.EncryptionMethod == sevProfile.encryption) &&
  1346. (devProfile.BSSType == sevProfile.type)
  1347. ) {
  1348. if (([5, 7, 32768, 32769].indexOf(sevProfile.authentication)) >= 0) {
  1349. // This is a 802.1x profile, do some extra matching.
  1350. // Start by finding the 802.1x profile for this WIFI profile
  1351. var netAuthProfile = null, netAuthMatch = false;
  1352. for (var k in netAuthProfiles) { if (netAuthProfiles[k].ElementName == devProfile.ElementName) { netAuthProfile = netAuthProfiles[k]; } }
  1353. if (netAuthProfile != null) {
  1354. netAuthMatch = true;
  1355. if (srvNetAuthProfile.authenticationprotocol != netAuthProfile['AuthenticationProtocol']) { netAuthMatch = false; }
  1356. if (srvNetAuthProfile.roamingidentity != netAuthProfile['RoamingIdentity']) { netAuthMatch = false; }
  1357. if (srvNetAuthProfile.servercertificatename != netAuthProfile['ServerCertificateName']) { netAuthMatch = false; }
  1358. if (srvNetAuthProfile.servercertificatenamecomparison != netAuthProfile['ServerCertificateNameComparison']) { netAuthMatch = false; }
  1359. if (typeof srvNetAuthProfile.satellitecredentials != 'string') {
  1360. // Credentials for this profile are in the config file
  1361. if (srvNetAuthProfile.username != netAuthProfile['Username']) { netAuthMatch = false; }
  1362. if (srvNetAuthProfile.domain != netAuthProfile['Domain']) { netAuthMatch = false; }
  1363. }
  1364. }
  1365. // TODO: If the existing 802.1x profile has a certificate, remember the client certificate instance id for later checking
  1366. if (netAuthMatch == true) {
  1367. // The 802.1x profile seems to match what we want, keep it.
  1368. wirelessMatch = true;
  1369. devProfile.match = true;
  1370. }
  1371. } else {
  1372. // Not a 802.1x profile, looks fine, keep it.
  1373. wirelessMatch = true;
  1374. devProfile.match = true;
  1375. }
  1376. }
  1377. }
  1378. if (wirelessMatch == false) { profilesToAdd.push(sevProfile); } // Add non-matching profile
  1379. if ((wirelessMatch == false) || (([5, 7, 32768, 32769].indexOf(sevProfile.authentication)) >= 0)) { profilesToAdd2.push(sevProfile); } // Add non-matching profile or 802.1x profile
  1380. }
  1381. for (var j in devProfiles) {
  1382. var devProfile = devProfiles[j];
  1383. if (devProfile.InstanceID != null) {
  1384. if (devProfile.match !== true) { profilesToRemove.push(devProfile); } // Missing profile to remove
  1385. if ((devProfile.match !== true) || (([5, 7, 32768, 32769].indexOf(devProfile.AuthenticationMethod)) >= 0)) { profilesToRemove2.push(devProfile); } // Missing profile to remove or 802.1x profile
  1386. }
  1387. }
  1388. // Compute what priorities are allowed
  1389. var prioritiesInUse = [];
  1390. for (var j in devProfiles) { if (devProfiles[j].match == true) { prioritiesInUse.push(devProfiles[j].Priority); } }
  1391. // Check if any other WIFI profiles require a 802.1x request to MeshCentral Satellite
  1392. if (dev.netAuthCredentials == null) {
  1393. for (var i in profilesToAdd) { if (([5, 7, 32768, 32769].indexOf(profilesToAdd[i].authentication)) >= 0) { newNetAuthProfileRequested = true; } }
  1394. }
  1395. // If we need to request a new 802.1x profile, remove all existing 802.1x WIFI profiles and re-add later.
  1396. if (newNetAuthProfileRequested) {
  1397. profilesToAdd = profilesToAdd2; // Just use the second list we built for this purpose.
  1398. profilesToRemove = profilesToRemove2;
  1399. }
  1400. // Notify of WIFI profile changes
  1401. if ((profilesToAdd.length > 0) || (profilesToRemove.length > 0)) { dev.consoleMsg("Changing WIFI profiles, adding " + profilesToAdd.length + ", removing " + profilesToRemove.length + "."); }
  1402. // Remove any extra WIFI profiles
  1403. for (var i in profilesToRemove) {
  1404. dev.amtstack.Delete('CIM_WiFiEndpointSettings', { InstanceID: 'Intel(r) AMT:WiFi Endpoint Settings ' + profilesToRemove[i].ElementName }, function (stack, name, responses, status) { }, 0, 1);
  1405. }
  1406. }
  1407. }
  1408. // Check the 802.1x client certificate expiration time
  1409. // TODO: We are only getting the client cert from the wired 802.1x profile, need to get it for wireless too.
  1410. var netAuthClientCert = null;
  1411. if (netAuthClientCertInstanceId != null) {
  1412. netAuthClientCert = getInstance(responses['AMT_PublicKeyCertificate'].responses, netAuthClientCertInstanceId);
  1413. if (netAuthClientCert) {
  1414. var cert = null;
  1415. try { cert = obj.parent.certificateOperations.forge.pki.certificateFromAsn1(obj.parent.certificateOperations.forge.asn1.fromDer(obj.parent.certificateOperations.forge.util.decode64(netAuthClientCert.X509Certificate))); } catch (ex) { }
  1416. if (cert != null) {
  1417. const certStart = new Date(cert.validity.notBefore).getTime();
  1418. const certEnd = new Date(cert.validity.notAfter).getTime();
  1419. const certMidPoint = certStart + ((certEnd - certStart) / 2);
  1420. if (Date.now() > certMidPoint) { newNetAuthProfileRequested = true; } // Past mid-point or expired, request a new 802.1x certificate & profile
  1421. }
  1422. }
  1423. }
  1424. // Figure out if there are no changes to 802.1x wired configuration
  1425. if ((wiredMatch == 0) && (newNetAuthProfileRequested == false)) { wiredConfig = false; }
  1426. // See if we need to ask MeshCentral Satellite for a new 802.1x profile
  1427. if (newNetAuthProfileRequested && (typeof srvNetAuthProfile.satellitecredentials == 'string')) {
  1428. // Credentials for this 802.1x profile are provided using MeshCentral Satellite
  1429. // Send a message to Satellite requesting a 802.1x profile for this device
  1430. dev.consoleMsg("Requesting 802.1x credentials for " + netAuthStrings[srvNetAuthProfile.authenticationprotocol] + " from MeshCentral Satellite...");
  1431. dev.netAuthSatReqId = Buffer.from(parent.crypto.randomBytes(16), 'binary').toString('base64'); // Generate a crypto-secure request id.
  1432. dev.netAuthSatReqData = { domain: domain, wiredConfig: wiredConfig, wirelessConfig: wirelessConfig, devNetAuthProfile: devNetAuthProfile, srvNetAuthProfile: srvNetAuthProfile, profilesToAdd: profilesToAdd, prioritiesInUse: prioritiesInUse, responses: responses, xxCertificates: xxCertificates, xxCertPrivateKeys: xxCertPrivateKeys }
  1433. 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 };
  1434. if (netAuthClientCert != null) { request.cert = netAuthClientCert.X509Certificate; request.certid = netAuthClientCertInstanceId; }
  1435. parent.DispatchEvent([srvNetAuthProfile.satellitecredentials], obj, request);
  1436. // Set a response timeout
  1437. const netAuthTimeoutFunc = function netAuthTimeout() {
  1438. if (isAmtDeviceValid(netAuthTimeout.dev) == false) return; // Device no longer exists, ignore this request.
  1439. if (dev.netAuthSatReqId != null) {
  1440. delete netAuthTimeout.dev.netAuthSatReqId;
  1441. delete netAuthTimeout.dev.netAuthSatReqData;
  1442. netAuthTimeout.dev.consoleMsg("MeshCentral Satellite did not respond in time, 802.1x profile will not be set.");
  1443. devTaskCompleted(netAuthTimeout.dev);
  1444. }
  1445. }
  1446. netAuthTimeoutFunc.dev = dev;
  1447. dev.netAuthSatReqTimer = setTimeout(netAuthTimeoutFunc, 20000);
  1448. return;
  1449. } else {
  1450. // No need to call MeshCentral Satellite for a 802.1x profile, so configure everything now.
  1451. attempt8021xSyncEx(dev, { domain: domain, wiredConfig: wiredConfig, wirelessConfig: wirelessConfig, devNetAuthProfile: devNetAuthProfile, srvNetAuthProfile: srvNetAuthProfile, profilesToAdd: profilesToAdd, prioritiesInUse: prioritiesInUse, responses: responses, xxCertificates: xxCertificates, xxCertPrivateKeys: xxCertPrivateKeys });
  1452. }
  1453. });
  1454. }
  1455. // Check 802.1x root certificate
  1456. function perform8021xRootCertCheck(dev) {
  1457. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1458. // Check if there is a root certificate to add, if we already have it, get the instance id.
  1459. if (dev.netAuthCredentials.rootcert) {
  1460. var matchingRootCertId = null;
  1461. for (var i in dev.netAuthSatReqData.xxCertificates) {
  1462. if ((dev.netAuthSatReqData.xxCertificates[i].X509Certificate == dev.netAuthCredentials.rootcert) && (dev.netAuthSatReqData.xxCertificates[i].TrustedRootCertficate)) {
  1463. matchingRootCertId = dev.netAuthSatReqData.xxCertificates[i].InstanceID;
  1464. }
  1465. }
  1466. if (matchingRootCertId == null) {
  1467. // Root certificate not found, add it
  1468. dev.consoleMsg("Setting up new 802.1x root certificate...");
  1469. const f = function perform8021xRootCertCheckResponse(stack, name, response, status) {
  1470. if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
  1471. // Failed to add the root certificate
  1472. dev.consoleMsg("Failed to sign the certificate request.");
  1473. } else {
  1474. // Root certificate added, move on to client certificate checking
  1475. perform8021xRootCertCheckResponse.dev.netAuthSatReqData.rootCertInstanceId = response.Body.CreatedCertificate.ReferenceParameters.SelectorSet.Selector.Value;
  1476. perform8021xClientCertCheck(perform8021xRootCertCheckResponse.dev);
  1477. }
  1478. }
  1479. f.dev = dev;
  1480. dev.amtstack.AMT_PublicKeyManagementService_AddTrustedRootCertificate(dev.netAuthCredentials.rootcert, f);
  1481. } else {
  1482. // Root certificate already present, move on to client certificate checking
  1483. dev.netAuthSatReqData.rootCertInstanceId = matchingRootCertId;
  1484. perform8021xClientCertCheck(dev);
  1485. }
  1486. } else {
  1487. // No root certificate to check, move on to client certificate checking
  1488. perform8021xClientCertCheck(dev);
  1489. }
  1490. }
  1491. // Check 802.1x client certificate
  1492. function perform8021xClientCertCheck(dev) {
  1493. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1494. if (dev.netAuthCredentials.certificate) {
  1495. // The new 802.1x profile includes a new certificate, add it now before adding the 802.1x profiles
  1496. // dev.netAuthCredentials.certificate must be in DER encoded format
  1497. dev.consoleMsg("Setting up new 802.1x client certificate...");
  1498. const f = function AddCertificateResponse(stack, name, response, status) {
  1499. if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
  1500. AddCertificateResponse.dev.consoleMsg("Unable to set 802.1x certificate.");
  1501. } else {
  1502. // Keep the certificate reference since we need it to add 802.1x profiles
  1503. const certInstanceId = response.Body.CreatedCertificate.ReferenceParameters.SelectorSet.Selector.Value;
  1504. // Set the 802.1x wired profile in the device
  1505. AddCertificateResponse.dev.consoleMsg("Setting MeshCentral Satellite 802.1x profile...");
  1506. const netAuthSatReqData = AddCertificateResponse.dev.netAuthSatReqData;
  1507. delete dev.netAuthSatReqData;
  1508. netAuthSatReqData.certInstanceId = certInstanceId;
  1509. attempt8021xSyncEx(AddCertificateResponse.dev, netAuthSatReqData);
  1510. }
  1511. }
  1512. f.dev = dev;
  1513. dev.amtstack.AMT_PublicKeyManagementService_AddCertificate(dev.netAuthCredentials.certificate, f);
  1514. } else {
  1515. // No 802.1x certificate, set the 802.1x wired profile in the device
  1516. dev.consoleMsg("Setting MeshCentral Satellite 802.1x profile...");
  1517. const netAuthSatReqData = dev.netAuthSatReqData;
  1518. delete dev.netAuthSatReqData;
  1519. if (dev.netAuthCredentials.certid) { netAuthSatReqData.certInstanceId = dev.netAuthCredentials.certid; } // If we are reusing an existing certificate, set that now.
  1520. attempt8021xSyncEx(dev, netAuthSatReqData);
  1521. }
  1522. }
  1523. // Set the 802.1x wired profile
  1524. function attempt8021xSyncEx(dev, devNetAuthData) {
  1525. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1526. // Unpack
  1527. const domain = devNetAuthData.domain;
  1528. const devNetAuthProfile = devNetAuthData.devNetAuthProfile;
  1529. const srvNetAuthProfile = devNetAuthData.srvNetAuthProfile;
  1530. const profilesToAdd = devNetAuthData.profilesToAdd;
  1531. const responses = devNetAuthData.responses;
  1532. const wiredConfig = devNetAuthData.wiredConfig;
  1533. const wirelessConfig = devNetAuthData.wirelessConfig;
  1534. if (wiredConfig) {
  1535. var netAuthProfile = Clone(devNetAuthProfile);
  1536. netAuthProfile['Enabled'] = ((srvNetAuthProfile != null) && (typeof srvNetAuthProfile == 'object'));
  1537. if (netAuthProfile['Enabled']) {
  1538. netAuthProfile['ActiveInS0'] = (srvNetAuthProfile.availableins0 !== false);
  1539. netAuthProfile['AuthenticationProtocol'] = srvNetAuthProfile.authenticationprotocol;
  1540. if (srvNetAuthProfile.roamingidentity && (srvNetAuthProfile.roamingidentity != '')) { netAuthProfile['RoamingIdentity'] = srvNetAuthProfile.roamingidentity; } else { delete netAuthProfile['RoamingIdentity']; }
  1541. if (srvNetAuthProfile.servercertificatename && (srvNetAuthProfile.servercertificatename != '')) {
  1542. netAuthProfile['ServerCertificateName'] = srvNetAuthProfile.servercertificatename;
  1543. netAuthProfile['ServerCertificateNameComparison'] = srvNetAuthProfile.servercertificatenamecomparison;
  1544. } else {
  1545. delete netAuthProfile['ServerCertificateName'];
  1546. delete netAuthProfile['ServerCertificateNameComparison'];
  1547. }
  1548. if (srvNetAuthProfile.username && (srvNetAuthProfile.username != '')) { netAuthProfile['Username'] = srvNetAuthProfile.username; } else { delete netAuthProfile['Username']; }
  1549. if (srvNetAuthProfile.password && (srvNetAuthProfile.password != '')) { netAuthProfile['Password'] = srvNetAuthProfile.password; } else { delete netAuthProfile['Password']; }
  1550. if (srvNetAuthProfile.domain && (srvNetAuthProfile.domain != '')) { netAuthProfile['Domain'] = srvNetAuthProfile.domain; } else { delete netAuthProfile['Domain']; }
  1551. if (srvNetAuthProfile.authenticationprotocol > 3) {
  1552. netAuthProfile['ProtectedAccessCredential'] = srvNetAuthProfile.protectedaccesscredentialhex;
  1553. netAuthProfile['PACPassword'] = srvNetAuthProfile.pacpassword;
  1554. } else {
  1555. delete netAuthProfile['ProtectedAccessCredential'];
  1556. delete netAuthProfile['PACPassword'];
  1557. }
  1558. // Setup Client Certificate
  1559. if (devNetAuthData.certInstanceId) {
  1560. 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>';
  1561. } else {
  1562. delete netAuthProfile['ClientCertificate'];
  1563. }
  1564. // Setup Server Certificate
  1565. if (devNetAuthData.rootCertInstanceId) {
  1566. 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>';
  1567. } else {
  1568. delete netAuthProfile['ServerCertificateIssuer'];
  1569. }
  1570. netAuthProfile['PxeTimeout'] = (typeof srvNetAuthProfile.pxetimeoutinseconds == 'number') ? srvNetAuthProfile.pxetimeoutinseconds : 120;
  1571. // If we have a MeshCentral Satellite profile, use that
  1572. if (dev.netAuthCredentials != null) {
  1573. const srvNetAuthProfile2 = dev.netAuthCredentials;
  1574. if (srvNetAuthProfile2.username && (srvNetAuthProfile2.username != '')) { netAuthProfile['Username'] = srvNetAuthProfile2.username; }
  1575. if (srvNetAuthProfile2.password && (srvNetAuthProfile2.password != '')) { netAuthProfile['Password'] = srvNetAuthProfile2.password; }
  1576. if (srvNetAuthProfile2.domain && (srvNetAuthProfile2.domain != '')) { netAuthProfile['Domain'] = srvNetAuthProfile2.domain; }
  1577. }
  1578. }
  1579. dev.amtstack.Put('AMT_8021XProfile', netAuthProfile, function (stack, name, responses, status) {
  1580. const dev = stack.dev;
  1581. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1582. if (status == 200) { dev.consoleMsg("802.1x wired profile set."); } else { dev.consoleMsg("Unable to set 802.1x wired profile."); }
  1583. attemptWifiSyncEx(dev, devNetAuthData);
  1584. });
  1585. } else {
  1586. // No wired interface, skip with WIFI config
  1587. attemptWifiSyncEx(dev, devNetAuthData);
  1588. }
  1589. }
  1590. function attemptWifiSyncEx(dev, devNetAuthData) {
  1591. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1592. // Unpack
  1593. const domain = devNetAuthData.domain;
  1594. const devNetAuthProfile = devNetAuthData.devNetAuthProfile;
  1595. const srvNetAuthProfile = devNetAuthData.srvNetAuthProfile;
  1596. const profilesToAdd = devNetAuthData.profilesToAdd;
  1597. const responses = devNetAuthData.responses;
  1598. const prioritiesInUse = devNetAuthData.prioritiesInUse;
  1599. const wiredConfig = devNetAuthData.wiredConfig;
  1600. const wirelessConfig = devNetAuthData.wirelessConfig;
  1601. var taskCounter = 0;
  1602. if (wirelessConfig) {
  1603. // Add missing WIFI profiles
  1604. var nextPriority = 1;
  1605. for (var i in profilesToAdd) {
  1606. while (prioritiesInUse.indexOf(nextPriority) >= 0) { nextPriority++; } // Figure out the next available priority slot.
  1607. var profileToAdd = profilesToAdd[i];
  1608. const wifiep = {
  1609. __parameterType: 'reference',
  1610. __resourceUri: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpoint',
  1611. Name: 'WiFi Endpoint 0'
  1612. };
  1613. const wifiepsettinginput = {
  1614. __parameterType: 'instance',
  1615. __namespace: 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_WiFiEndpointSettings',
  1616. ElementName: profileToAdd.name,
  1617. InstanceID: 'Intel(r) AMT:WiFi Endpoint Settings ' + profileToAdd.name,
  1618. AuthenticationMethod: profileToAdd.authentication,
  1619. EncryptionMethod: profileToAdd.encryption,
  1620. SSID: profileToAdd.ssid,
  1621. Priority: nextPriority,
  1622. }
  1623. var netAuthProfile, netAuthSettingsClientCert, netAuthSettingsServerCaCert;
  1624. if (([4, 6].indexOf(profileToAdd.authentication)) >= 0) { wifiepsettinginput['PSKPassPhrase'] = profileToAdd.password; }
  1625. if (([5, 7, 32768, 32769].indexOf(profileToAdd.authentication)) >= 0) {
  1626. netAuthProfile = {
  1627. '__parameterType': 'instance',
  1628. '__namespace': dev.amtstack.CompleteName('CIM_IEEE8021xSettings'),
  1629. 'ElementName': '8021x-' + profileToAdd.name,
  1630. 'InstanceID': '8021x-' + profileToAdd.name,
  1631. 'ActiveInS0': (domain.amtmanager['802.1x'].availableins0 !== false),
  1632. 'AuthenticationProtocol': domain.amtmanager['802.1x'].authenticationprotocol
  1633. };
  1634. if (domain.amtmanager['802.1x'].roamingidentity) { netAuthProfile['RoamingIdentity'] = domain.amtmanager['802.1x'].roamingidentity; }
  1635. if (domain.amtmanager['802.1x'].servercertificatename) { netAuthProfile['ServerCertificateName'] = domain.amtmanager['802.1x'].servercertificatename; netAuthProfile['ServerCertificateNameComparison'] = profileToAdd['802.1x'].servercertificatenamecomparison; }
  1636. if (domain.amtmanager['802.1x'].username) { netAuthProfile['Username'] = domain.amtmanager['802.1x'].username; }
  1637. if (domain.amtmanager['802.1x'].password) { netAuthProfile['Password'] = domain.amtmanager['802.1x'].password; }
  1638. if (domain.amtmanager['802.1x'].domain) { netAuthProfile['Domain'] = domain.amtmanager['802.1x'].domain; }
  1639. if (domain.amtmanager['802.1x'].authenticationprotocol > 3) { domain.amtmanager['ProtectedAccessCredential'] = profileToAdd['802.1x'].protectedaccesscredentialhex; netAuthProfile['PACPassword'] = profileToAdd['802.1x'].pacpassword; }
  1640. // Setup Client Certificate
  1641. if (devNetAuthData.certInstanceId) {
  1642. 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>';
  1643. }
  1644. // Setup Server Certificate
  1645. if (devNetAuthData.rootCertInstanceId) {
  1646. 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>';
  1647. }
  1648. // If we have credentials from MeshCentral Satelite, use that
  1649. if (dev.netAuthCredentials != null) {
  1650. const srvNetAuthProfile2 = dev.netAuthCredentials;
  1651. if (srvNetAuthProfile2.username && (srvNetAuthProfile2.username != '')) { netAuthProfile['Username'] = srvNetAuthProfile2.username; }
  1652. if (srvNetAuthProfile2.password && (srvNetAuthProfile2.password != '')) { netAuthProfile['Password'] = srvNetAuthProfile2.password; }
  1653. if (srvNetAuthProfile2.domain && (srvNetAuthProfile2.domain != '')) { netAuthProfile['Domain'] = srvNetAuthProfile2.domain; }
  1654. }
  1655. }
  1656. prioritiesInUse.push(nextPriority); // Occupy the priority slot and add the WIFI profile.
  1657. taskCounter++;
  1658. dev.amtstack.AMT_WiFiPortConfigurationService_AddWiFiSettings(wifiep, wifiepsettinginput, netAuthProfile, netAuthSettingsClientCert, netAuthSettingsServerCaCert, function (stack, name, response, status) {
  1659. if (status != 200) { dev.consoleMsg("Unable to set WIFI profile."); }
  1660. if (--taskCounter == 0) { attemptWifiSyncEx2(dev, devNetAuthData); } // All done, complete WIFI configuration
  1661. });
  1662. }
  1663. }
  1664. if (taskCounter == 0) { attemptWifiSyncEx2(dev, devNetAuthData); } // All done, complete WIFI configuration
  1665. }
  1666. function attemptWifiSyncEx2(dev, devNetAuthData) {
  1667. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1668. const responses = devNetAuthData.responses;
  1669. const wirelessConfig = devNetAuthData.wirelessConfig;
  1670. if (wirelessConfig) {
  1671. // Check if local WIFI profile sync is enabled, if not, enabled it.
  1672. if ((responses['AMT_WiFiPortConfigurationService'] != null) && (responses['AMT_WiFiPortConfigurationService'].response != null) && (responses['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] == 0)) {
  1673. responses['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] = 1;
  1674. dev.amtstack.Put('AMT_WiFiPortConfigurationService', responses['AMT_WiFiPortConfigurationService'].response, function (stack, name, response, status) {
  1675. if (status != 200) { dev.consoleMsg("Unable to enable local WIFI profile sync."); } else { dev.consoleMsg("Enabled local WIFI profile sync."); }
  1676. });
  1677. }
  1678. // Change the WIFI state if needed. Right now, we always enable it.
  1679. // WifiState = { 3: "Disabled", 32768: "Enabled in S0", 32769: "Enabled in S0, Sx/AC" };
  1680. var wifiState = 32769; // For now, always enable WIFI
  1681. if (responses['CIM_WiFiPort'].responses.Body.EnabledState != 32769) {
  1682. if (wifiState == 3) {
  1683. dev.amtstack.CIM_WiFiPort_RequestStateChange(wifiState, null, function (stack, name, responses, status) {
  1684. const dev = stack.dev;
  1685. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1686. if (status == 200) { dev.consoleMsg("Disabled WIFI."); }
  1687. });
  1688. } else {
  1689. dev.amtstack.CIM_WiFiPort_RequestStateChange(wifiState, null, function (stack, name, responses, status) {
  1690. const dev = stack.dev;
  1691. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1692. if (status == 200) { dev.consoleMsg("Enabled WIFI."); }
  1693. });
  1694. }
  1695. }
  1696. }
  1697. // Done
  1698. devTaskCompleted(dev);
  1699. }
  1700. // Request for a RSA key pair generation. This will be used to generate the 802.1x certificate
  1701. function attempt8021xKeyGeneration(dev) {
  1702. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1703. dev.amtstack.AMT_PublicKeyManagementService_GenerateKeyPair(0, 2048, function (stack, name, response, status) {
  1704. if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
  1705. // Failed to generate a key pair
  1706. dev.consoleMsg("Failed to generate the requested RSA key pair.");
  1707. } else {
  1708. dev.amtstack.Enum('AMT_PublicPrivateKeyPair', function (stack, name, xresponse, status, keyInstanceId) {
  1709. if (status != 200) {
  1710. // Failed to get the generated key pair
  1711. dev.consoleMsg("Failed to get the generated RSA key pair.");
  1712. } else {
  1713. // We got the key pair
  1714. var DERKey = null;
  1715. for (var i in xresponse) {
  1716. if (xresponse[i]['InstanceID'] == keyInstanceId) {
  1717. // We found our matching DER key
  1718. DERKey = xresponse[i]['DERKey'];
  1719. }
  1720. }
  1721. if (DERKey == null) { dev.consoleMsg("Failed to match the generated RSA key pair."); return; }
  1722. dev.consoleMsg("Generated a RSA key pair.");
  1723. var domain = parent.config.domains[dev.domainid];
  1724. 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 });
  1725. }
  1726. }, response.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']);
  1727. }
  1728. });
  1729. }
  1730. // 802.1x request to process a Certificate Signing Request, we ask Intel AMT to sign the request
  1731. function attempt8021xCRSRequest(dev, event) {
  1732. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1733. if ((event.response == null) || (event.response.keyInstanceId == null)) return;
  1734. 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
  1735. var signingAlgorithm = 1; // 0 = SHA1-RSA, 1 = SHA256-RSA
  1736. var nullSignedCertificateRequest = event.response.csr; // DEREncodedRequest
  1737. dev.amtstack.AMT_PublicKeyManagementService_GeneratePKCS10RequestEx(keyPair, signingAlgorithm, nullSignedCertificateRequest, function (stack, name, response, status) {
  1738. if ((status != 200) || (response.Body['ReturnValue'] != 0)) {
  1739. // Failed to get the generated key pair
  1740. dev.consoleMsg("Failed to sign the certificate request.");
  1741. } else {
  1742. // We got a signed certificate request, return that to the server
  1743. dev.consoleMsg("Generated a signed certificate request.");
  1744. var domain = parent.config.domains[dev.domainid];
  1745. 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 });
  1746. }
  1747. });
  1748. }
  1749. //
  1750. // Intel AMT Server Root Certificate
  1751. //
  1752. // Check if Intel AMT has the server root certificate
  1753. function attemptRootCertSync(dev, func, forced) {
  1754. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1755. if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
  1756. 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
  1757. if (parent.mpsserver.server == null) { func(dev); return; } // Root cert not needed if MPS is not active.
  1758. // Find the current TLS certificate & MeshCentral root certificate
  1759. var xxMeshCentralRoot = null;
  1760. if (dev.policy.tlsCredentialContext.length > 0) {
  1761. for (var i in dev.policy.certificates) { if (dev.policy.certificates[i]['X509Certificate'] == obj.rootCertBase64) { xxMeshCentralRoot = i; } }
  1762. }
  1763. // If the server root certificate is not present and we need to configure CIRA, add it
  1764. if (xxMeshCentralRoot == null) {
  1765. dev.taskCount = 1;
  1766. dev.taskCompleted = func;
  1767. dev.amtstack.AMT_PublicKeyManagementService_AddTrustedRootCertificate(obj.rootCertBase64, function (stack, name, responses, status) {
  1768. const dev = stack.dev;
  1769. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1770. if (status != 200) { dev.consoleMsg("Failed to add server root certificate (" + status + ")."); removeAmtDevice(dev, 28); return; }
  1771. dev.consoleMsg("Added server root certificate.");
  1772. devTaskCompleted(dev);
  1773. });
  1774. } else { func(dev); }
  1775. }
  1776. //
  1777. // Intel AMT CIRA Setup
  1778. //
  1779. // Check if Intel AMT has the server root certificate
  1780. // If deactivation policy is in effect, remove CIRA configuration
  1781. function attemptCiraSync(dev, func) {
  1782. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1783. 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.
  1784. // Get current CIRA settings
  1785. // TODO: We only deal with remote access starting with Intel AMT 6 and beyond
  1786. dev.taskCount = 1;
  1787. dev.taskCompleted = func;
  1788. dev.tryCount = 0;
  1789. var requests = ['*AMT_EnvironmentDetectionSettingData', 'AMT_ManagementPresenceRemoteSAP', 'AMT_RemoteAccessCredentialContext', 'AMT_RemoteAccessPolicyAppliesToMPS', 'AMT_RemoteAccessPolicyRule', '*AMT_UserInitiatedConnectionService', 'AMT_MPSUsernamePassword'];
  1790. if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 11)) { requests.push('*IPS_HTTPProxyService', 'IPS_HTTPProxyAccessPoint'); }
  1791. dev.amtstack.BatchEnum(null, requests, attemptCiraSyncResponse);
  1792. }
  1793. function attemptCiraSyncResponse(stack, name, responses, status) {
  1794. const dev = stack.dev;
  1795. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1796. if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 11) && (status == 400)) {
  1797. // Check if only the HTTP proxy objects failed
  1798. status = 200;
  1799. if (responses['IPS_HTTPProxyAccessPoint'].status == 400) { delete responses['IPS_HTTPProxyAccessPoint']; }
  1800. if (responses['IPS_HTTPProxyService'].status == 400) { delete responses['IPS_HTTPProxyService']; }
  1801. for (var i in responses) { if (responses[i].status != 200) { status = responses[i].status; } }
  1802. }
  1803. // If batch enumeration was not succesful, try again.
  1804. if (status != 200) {
  1805. // If we failed to get the CIRA state, try again up to 5 times.
  1806. if (dev.tryCount <= 5) {
  1807. dev.tryCount++;
  1808. var requests = ['*AMT_EnvironmentDetectionSettingData', 'AMT_ManagementPresenceRemoteSAP', 'AMT_RemoteAccessCredentialContext', 'AMT_RemoteAccessPolicyAppliesToMPS', 'AMT_RemoteAccessPolicyRule', '*AMT_UserInitiatedConnectionService', 'AMT_MPSUsernamePassword'];
  1809. if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 11)) { requests.push('*IPS_HTTPProxyService', 'IPS_HTTPProxyAccessPoint'); }
  1810. dev.amtstack.BatchEnum(null, requests, attemptCiraSyncResponse);
  1811. return;
  1812. }
  1813. // We tried 5 times, give up.
  1814. dev.consoleMsg("Failed to get CIRA state (" + status + ").");
  1815. removeAmtDevice(dev, 29);
  1816. return;
  1817. }
  1818. // Check if CIRA is supported
  1819. if ((responses['AMT_UserInitiatedConnectionService'] == null) || (responses['AMT_UserInitiatedConnectionService'].response == null)) {
  1820. dev.consoleMsg("This device does not support CIRA.");
  1821. devTaskCompleted(dev);
  1822. return;
  1823. }
  1824. dev.cira = {};
  1825. dev.cira.xxRemoteAccess = responses;
  1826. dev.cira.xxEnvironementDetection = responses['AMT_EnvironmentDetectionSettingData'].response;
  1827. dev.cira.xxEnvironementDetection['DetectionStrings'] = MakeToArray(dev.cira.xxEnvironementDetection['DetectionStrings']);
  1828. dev.cira.xxCiraServers = responses['AMT_ManagementPresenceRemoteSAP'].responses;
  1829. dev.cira.xxUserInitiatedCira = responses['AMT_UserInitiatedConnectionService'].response;
  1830. dev.cira.xxRemoteAccessCredentiaLinks = responses['AMT_RemoteAccessCredentialContext'].responses;
  1831. dev.cira.xxMPSUserPass = responses['AMT_MPSUsernamePassword'].responses;
  1832. // Set CIRA initiation to BIOS & OS enabled
  1833. if (dev.cira.xxUserInitiatedCira['EnabledState'] != 32771) { // 32768: "Disabled", 32769: "BIOS enabled", 32770: "OS enable", 32771: "BIOS & OS enabled"
  1834. dev.amtstack.AMT_UserInitiatedConnectionService_RequestStateChange(32771, null, function (stack, name, responses, status) { }); // This is not a critical call.
  1835. }
  1836. // Figure out policies attached to servers. Create a policy type to server table.
  1837. dev.cira.xxPolicies = { 'User': [], 'Alert': [], 'Periodic': [] };
  1838. for (var i in responses['AMT_RemoteAccessPolicyAppliesToMPS'].responses) {
  1839. var policy = responses['AMT_RemoteAccessPolicyAppliesToMPS'].responses[i];
  1840. var server = Clone(getItem(dev.cira.xxCiraServers, 'Name', getItem(policy['ManagedElement']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'Name')['Value']));
  1841. server.MpsType = policy['MpsType']; // MpsType was added in Intel AMT 11.6
  1842. var ptype = (getItem(policy['PolicySet']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'PolicyRuleName')['Value']).split(' ')[0];
  1843. dev.cira.xxPolicies[ptype].push(server);
  1844. }
  1845. // Fetch the server's CIRA settings
  1846. dev.cira.mpsPresent = null;
  1847. dev.cira.mpsPolicy = false;
  1848. 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
  1849. dev.cira.meshidx = dev.meshid.split('/')[2].replace(/\@/g, 'X').replace(/\$/g, 'X').substring(0, 16);
  1850. dev.cira.mpsName = parent.webserver.certificates.AmtMpsName;
  1851. var serverNameSplit = dev.cira.mpsName.split('.');
  1852. dev.cira.mpsPort = ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport);
  1853. dev.cira.mpsAddressFormat = 201; // 201 = FQDN, 3 = IPv4
  1854. dev.cira.mpsPass = getRandomAmtPassword();
  1855. 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; }
  1856. // Check if our server is already present
  1857. if ((dev.cira.xxCiraServers != null) && (dev.cira.xxCiraServers.length > 0)) {
  1858. for (var i = 0; i < dev.cira.xxCiraServers.length; i++) {
  1859. var mpsServer = dev.cira.xxCiraServers[i];
  1860. if ((mpsServer.AccessInfo == dev.cira.mpsName) && (mpsServer.Port == dev.cira.mpsPort) && (mpsServer.InfoFormat == dev.cira.mpsAddressFormat)) { dev.cira.mpsPresent = mpsServer['Name']; }
  1861. }
  1862. }
  1863. // Check if our server is already present
  1864. if ((dev.cira.xxPolicies != null) && (dev.cira.xxPolicies['Periodic'].length > 0)) {
  1865. var mpsServer = dev.cira.xxPolicies['Periodic'][0];
  1866. if ((mpsServer.AccessInfo == dev.cira.mpsName) && (mpsServer.Port == dev.cira.mpsPort) && (mpsServer.InfoFormat == dev.cira.mpsAddressFormat)) { dev.cira.mpsPolicy = true; }
  1867. }
  1868. }
  1869. // Remove all MPS policies that are not ours
  1870. if (dev.cira.xxPolicies != null) {
  1871. 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) { }); }
  1872. 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) { }); }
  1873. 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) { }); }
  1874. }
  1875. // Remove all MPS servers that are not ours
  1876. if ((dev.cira.xxCiraServers != null) && (dev.cira.xxCiraServers.length > 0)) {
  1877. for (var i = 0; i < dev.cira.xxCiraServers.length; i++) {
  1878. var mpsServer = dev.cira.xxCiraServers[i];
  1879. if ((mpsServer.AccessInfo != dev.cira.mpsName) || (mpsServer.Port != dev.cira.mpsPort) || (mpsServer.InfoFormat != dev.cira.mpsAddressFormat)) {
  1880. dev.consoleMsg("Removing MPS server.");
  1881. dev.amtstack.Delete('AMT_ManagementPresenceRemoteSAP', { 'Name': mpsServer['Name'] }, function (stack, name, responses, status) { });
  1882. }
  1883. }
  1884. }
  1885. // If we need to setup CIRA, start by checking the MPS server
  1886. // parent.mpsserver.server is not null if the MPS server is listening for TCP/TLS connections
  1887. if ((dev.policy.ciraPolicy == 2) && (parent.mpsserver.server != null)) { addMpsServer(dev); } else { checkEnvironmentDetection(dev); }
  1888. }
  1889. function addMpsServer(dev) {
  1890. // Add the MPS server if not present
  1891. if (dev.cira.mpsPresent == null) {
  1892. 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) {
  1893. const dev = stack.dev;
  1894. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1895. if (status != 200) { dev.consoleMsg("Failed to create new MPS server (" + status + ")."); removeAmtDevice(dev, 31); return; }
  1896. 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; }
  1897. dev.cira.mpsPresent = getItem(response.Body.MpServer.ReferenceParameters.SelectorSet.Selector, '@Name', 'Name').Value;
  1898. dev.consoleMsg("Created new MPS server.");
  1899. addMpsPolicy(dev);
  1900. // Update the device with the MPS password
  1901. dev.aquired.mpspass = dev.cira.mpsPass;
  1902. UpdateDevice(dev);
  1903. });
  1904. } else {
  1905. // MPS server is present, check MPS trigger policy
  1906. addMpsPolicy(dev);
  1907. }
  1908. }
  1909. function addMpsPolicy(dev) {
  1910. if (dev.cira.mpsPolicy == false) {
  1911. var cilaSupport = ((dev.aquired.majorver != null) && (dev.aquired.minorver != null)) && ((dev.aquired.majorver > 11) || ((dev.aquired.majorver == 11) && (dev.aquired.minorver >= 6)));
  1912. var trigger = 2; // 1 = Alert, 2 = Periodic
  1913. // Setup extended data
  1914. var extendedData = null;
  1915. if (trigger == 2) {
  1916. var timertype = 0; // 0 = Periodic, 1 = Time of day
  1917. var exdata = IntToStr(10); // Interval trigger, 10 seconds
  1918. extendedData = Buffer.from(IntToStr(timertype) + exdata, 'binary').toString('base64');
  1919. }
  1920. // Create the MPS server references
  1921. 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>';
  1922. var server2 = null;
  1923. // Put the CIRA/CILA servers in the right bins.
  1924. var ciraServers = [], cilaServers = [];
  1925. if (server1) { ciraServers.push(server1); if (server2) { ciraServers.push(server2); } }
  1926. // Go ahead and create the new CIRA/CILA policy.
  1927. dev.amtstack.AMT_RemoteAccessService_AddRemoteAccessPolicyRule(trigger, 0, extendedData, ciraServers, cilaServers, function (stack, name, responses, status) {
  1928. const dev = stack.dev;
  1929. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1930. if (status != 200) { dev.consoleMsg("Failed to create new MPS policy (" + status + ")."); removeAmtDevice(dev, 33); return; }
  1931. dev.consoleMsg("Created new MPS policy.");
  1932. checkEnvironmentDetection(dev);
  1933. });
  1934. } else {
  1935. checkEnvironmentDetection(dev);
  1936. }
  1937. }
  1938. function checkEnvironmentDetection(dev) {
  1939. var changes = false;
  1940. var editEnvironmentDetectionTmp = [];
  1941. var currentEnvDetect = dev.cira.xxEnvironementDetection['DetectionStrings'];
  1942. if (currentEnvDetect == null) { currentEnvDetect = []; }
  1943. if ((dev.policy.ciraPolicy == 2) && (parent.mpsserver.server != null)) { // ciraPolicy: 0 = Do Nothing, 1 = Clear, 2 = Set
  1944. const newEnvDetect = parent.config.domains[dev.domainid].amtmanager.environmentdetection;
  1945. if (newEnvDetect == null) {
  1946. // If no environment detection is specified in the config.json, check that we have a random environment detection
  1947. if (currentEnvDetect.length == 0) { editEnvironmentDetectionTmp = [ Buffer.from(parent.crypto.randomBytes(6), 'binary').toString('hex') ]; changes = true; }
  1948. } else {
  1949. // Check that we have exactly the correct environement detection suffixes
  1950. var mismatch = false;
  1951. if (currentEnvDetect.length != newEnvDetect.length) {
  1952. mismatch = true;
  1953. } else {
  1954. // Check if everything matches
  1955. for (var i in currentEnvDetect) { if (newEnvDetect.indexOf(currentEnvDetect[i]) == -1) { mismatch = true; } }
  1956. for (var i in newEnvDetect) { if (currentEnvDetect.indexOf(newEnvDetect[i]) == -1) { mismatch = true; } }
  1957. }
  1958. // If not, we need to set the new ones
  1959. if (mismatch == true) { editEnvironmentDetectionTmp = newEnvDetect; changes = true; }
  1960. }
  1961. } else if ((dev.policy.ciraPolicy == 1) || (parent.mpsserver.server == null)) {
  1962. // Check environment detection is clear
  1963. if (currentEnvDetect.length != 0) { editEnvironmentDetectionTmp = []; changes = true; }
  1964. }
  1965. // If we need to change the environment detection on the remote device, do it now.
  1966. if (changes == true) {
  1967. var t = Clone(dev.cira.xxEnvironementDetection);
  1968. t['DetectionStrings'] = editEnvironmentDetectionTmp;
  1969. dev.cira.envclear = (editEnvironmentDetectionTmp.length == 0);
  1970. dev.amtstack.Put('AMT_EnvironmentDetectionSettingData', t, function (stack, name, responses, status) {
  1971. const dev = stack.dev;
  1972. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1973. if (status != 200) { dev.consoleMsg("Failed to set environement detection (" + status + ")."); removeAmtDevice(dev, 34); return; }
  1974. if (dev.cira.envclear) { dev.consoleMsg("Environment detection cleared."); } else { dev.consoleMsg("Environment detection set."); }
  1975. devTaskCompleted(dev);
  1976. }, 0, 1);
  1977. } else {
  1978. devTaskCompleted(dev);
  1979. }
  1980. }
  1981. //
  1982. // Intel AMT Settings
  1983. //
  1984. function attemptSettingsSync(dev, func) {
  1985. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1986. if (dev.policy.amtPolicy == 0) { func(dev); return; } // If there is no Intel AMT policy, skip this operation.
  1987. dev.taskCount = 1;
  1988. dev.taskCompleted = func;
  1989. // Query the things we are going to be checking
  1990. var query = ['*AMT_GeneralSettings', '*AMT_RedirectionService'];
  1991. if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 5)) { query.push('*CIM_KVMRedirectionSAP', '*IPS_OptInService'); }
  1992. dev.amtstack.BatchEnum('', query, attemptSettingsSyncResponse);
  1993. }
  1994. function attemptSettingsSyncResponse(stack, name, responses, status) {
  1995. const dev = stack.dev;
  1996. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  1997. if (status != 200) { devTaskCompleted(dev); return; }
  1998. // If this device does not have KVM, ignore the response. This can happen for Intel Standard Manageability (Intel(R) SM).
  1999. if ((responses['CIM_KVMRedirectionSAP'] == null) || (responses['CIM_KVMRedirectionSAP'].status == 400)) { responses['CIM_KVMRedirectionSAP'] = null; }
  2000. // Set user consent requirement to match device group user consent
  2001. const mesh = parent.webserver.meshes[dev.meshid];
  2002. if (mesh == null) { removeAmtDevice(dev, 35); return; }
  2003. 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.
  2004. // Check user consent requirements
  2005. if ((responses['IPS_OptInService'] != null) && (responses['IPS_OptInService'].response['OptInRequired'] != userConsentRequirement)) {
  2006. responses['IPS_OptInService'].response['OptInRequired'] = userConsentRequirement; // 0 = Not Required, 1 = Required for KVM only, 0xFFFFFFFF = Always Required
  2007. dev.amtstack.Put('IPS_OptInService', responses['IPS_OptInService'].response, function (stack, name, responses, status) {
  2008. const dev = stack.dev;
  2009. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2010. if (status == 200) {
  2011. if (userConsentRequirement == 0) {
  2012. dev.consoleMsg("Cleared user consent requirements.");
  2013. } else if (userConsentRequirement == 1) {
  2014. dev.consoleMsg("Enabled KVM user consent requirement.");
  2015. } else if (userConsentRequirement == 0xFFFFFFFF) {
  2016. dev.consoleMsg("Enabled all user consent requirement.");
  2017. }
  2018. }
  2019. }, 0, 1);
  2020. }
  2021. // Enable SOL & IDER
  2022. if ((responses['AMT_RedirectionService'].response['EnabledState'] != 32771) || (responses['AMT_RedirectionService'].response['ListenerEnabled'] == false)) {
  2023. dev.redirObj = responses['AMT_RedirectionService'].response;
  2024. dev.redirObj['ListenerEnabled'] = true;
  2025. dev.redirObj['EnabledState'] = 32771;
  2026. dev.taskCount++;
  2027. dev.amtstack.AMT_RedirectionService_RequestStateChange(32771,
  2028. function (stack, name, response, status) {
  2029. const dev = stack.dev;
  2030. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2031. dev.amtstack.Put('AMT_RedirectionService', dev.redirObj, function (stack, name, response, status) {
  2032. const dev = stack.dev;
  2033. delete dev.redirObj;
  2034. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2035. if (status == 200) { dev.consoleMsg("Enabled redirection features."); }
  2036. devTaskCompleted(dev);
  2037. }, 0, 1);
  2038. }
  2039. );
  2040. }
  2041. // Check KVM state
  2042. if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 5) && (responses['CIM_KVMRedirectionSAP'] != null)) {
  2043. const kvm = ((responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 2) || (responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 6));
  2044. if (kvm == false) {
  2045. // Enable KVM
  2046. dev.taskCount++;
  2047. dev.amtstack.CIM_KVMRedirectionSAP_RequestStateChange(2, 0,
  2048. function (stack, name, response, status) {
  2049. const dev = stack.dev;
  2050. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2051. if (status == 200) { dev.consoleMsg("Enabled KVM."); }
  2052. devTaskCompleted(dev);
  2053. }
  2054. );
  2055. }
  2056. }
  2057. // Check device name and domain name
  2058. 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')) {
  2059. const generalSettings = responses['AMT_GeneralSettings'].response;
  2060. if ((generalSettings['HostName'] != dev.mpsConnection.tag.meiState.OsHostname) || (generalSettings['DomainName'] != dev.mpsConnection.tag.meiState.OsDnsSuffix)) {
  2061. // Change the computer and domain name
  2062. generalSettings['HostName'] = dev.mpsConnection.tag.meiState.OsHostname;
  2063. generalSettings['DomainName'] = dev.mpsConnection.tag.meiState.OsDnsSuffix;
  2064. dev.taskCount++;
  2065. dev.xname = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
  2066. dev.amtstack.Put('AMT_GeneralSettings', generalSettings, function () {
  2067. const dev = stack.dev;
  2068. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2069. if (status == 200) { dev.consoleMsg("Changed device name: " + dev.xname); }
  2070. delete dev.xname;
  2071. devTaskCompleted(dev);
  2072. }, 0, 1);
  2073. }
  2074. }
  2075. // Done
  2076. devTaskCompleted(dev);
  2077. }
  2078. //
  2079. // Intel AMT Certificate cleanup
  2080. //
  2081. // Remove any unused, non-trusted certificates
  2082. function attemptCleanCertsSync(dev, func) {
  2083. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2084. dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', 'AMT_PublicPrivateKeyPair'], function (stack, name, responses, status) {
  2085. const dev = stack.dev;
  2086. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2087. const domain = parent.config.domains[dev.domainid];
  2088. 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.
  2089. if ((responses['AMT_PublicKeyCertificate'].responses.length == 0) || (responses['AMT_PublicPrivateKeyPair'].responses.length == 0)) { func(dev); return; } // Empty certificate list, fail and carry on.
  2090. // Sort out the certificates
  2091. var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
  2092. var xxCertPrivateKeys = responses['AMT_PublicPrivateKeyPair'].responses;
  2093. for (var i in xxCertificates) {
  2094. xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
  2095. xxCertificates[i].X509CertificateBin = Buffer.from(xxCertificates[i]['X509Certificate'], 'base64').toString('binary');
  2096. xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
  2097. xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
  2098. }
  2099. amtcert_linkCertPrivateKey(xxCertificates, xxCertPrivateKeys); // This links all certificates and private keys
  2100. dev.certDeleteTasks = 0;
  2101. // Remove any unlinked private keys
  2102. for (var i in xxCertPrivateKeys) {
  2103. if (!xxCertPrivateKeys[i].XCert) {
  2104. dev.certDeleteTasks++;
  2105. dev.amtstack.Delete('AMT_PublicPrivateKeyPair', { 'InstanceID': xxCertPrivateKeys[i]['InstanceID'] }, function (stack, name, response, status) {
  2106. //if (status == 200) { dev.consoleMsg("Removed unassigned private key pair."); }
  2107. if (--dev.certDeleteTasks == 0) { delete dev.certDeleteTasks; func(dev); }
  2108. });
  2109. }
  2110. }
  2111. // Try to remove all untrusted certificates
  2112. for (var i in xxCertificates) {
  2113. if (xxCertificates[i].TrustedRootCertficate == false) {
  2114. var privateKeyInstanceId = null;
  2115. if (xxCertificates[i].XPrivateKey) { privateKeyInstanceId = { 'InstanceID': xxCertificates[i].XPrivateKey['InstanceID'] }; }
  2116. dev.certDeleteTasks++;
  2117. dev.amtstack.Delete('AMT_PublicKeyCertificate', { 'InstanceID': xxCertificates[i]['InstanceID'] }, function (stack, name, response, status, tag) {
  2118. if ((status == 200) && (tag != null)) {
  2119. // If there is a private key, delete it.
  2120. dev.amtstack.Delete('AMT_PublicPrivateKeyPair', tag, function () {
  2121. if (--dev.certDeleteTasks == 0) { delete dev.certDeleteTasks; func(dev); }
  2122. }, 0, 1);
  2123. } else {
  2124. if (--dev.certDeleteTasks == 0) { delete dev.certDeleteTasks; func(dev); }
  2125. }
  2126. }, privateKeyInstanceId);
  2127. }
  2128. }
  2129. });
  2130. }
  2131. //
  2132. // Intel AMT Hardware Inventory and Networking
  2133. //
  2134. function attemptFetchHardwareInventory(dev, func) {
  2135. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2136. const mesh = parent.webserver.meshes[dev.meshid];
  2137. if (mesh == null) { removeAmtDevice(dev, 35); return; }
  2138. if (mesh.mtype == 1) { // If this is a Intel AMT only device group, pull the hardware inventory and network information for this device
  2139. dev.consoleMsg("Fetching hardware inventory.");
  2140. dev.taskCount = 2;
  2141. dev.taskCompleted = func;
  2142. dev.amtstack.BatchEnum('', ['*CIM_ComputerSystemPackage', 'CIM_SystemPackaging', '*CIM_Chassis', 'CIM_Chip', '*CIM_Card', '*CIM_BIOSElement', 'CIM_Processor', 'CIM_PhysicalMemory', 'CIM_MediaAccessDevice', 'CIM_PhysicalPackage'], attemptFetchHardwareInventoryResponse);
  2143. dev.amtstack.BatchEnum('', ['AMT_EthernetPortSettings'], attemptFetchNetworkResponse);
  2144. } else {
  2145. if (func) { func(dev); }
  2146. }
  2147. }
  2148. function attemptFetchNetworkResponse(stack, name, responses, status) {
  2149. const dev = stack.dev;
  2150. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2151. if (status != 200) { devTaskCompleted(dev); return; }
  2152. //console.log(JSON.stringify(responses, null, 2));
  2153. if ((responses['AMT_EthernetPortSettings'] == null) || (responses['AMT_EthernetPortSettings'].responses == null)) { devTaskCompleted(dev); return; }
  2154. // Find the wired and wireless interfaces
  2155. var wired = null, wireless = null;
  2156. for (var i in responses['AMT_EthernetPortSettings'].responses) {
  2157. var netif = responses['AMT_EthernetPortSettings'].responses[i];
  2158. if ((netif.MACAddress != null) && (netif.MACAddress != '00-00-00-00-00-00')) {
  2159. if (netif.WLANLinkProtectionLevel != null) { wireless = netif; } else { wired = netif; }
  2160. }
  2161. }
  2162. if ((wired == null) && (wireless == null)) { devTaskCompleted(dev); return; }
  2163. // Sent by the agent to update agent network interface information
  2164. var net = { netif2: {} };
  2165. if (wired != null) {
  2166. var x = {};
  2167. x.family = 'IPv4';
  2168. x.type = 'ethernet';
  2169. x.address = wired.IPAddress;
  2170. x.netmask = wired.SubnetMask;
  2171. x.mac = wired.MACAddress.split('-').join(':').toUpperCase();
  2172. x.gateway = wired.DefaultGateway;
  2173. net.netif2['Ethernet'] = [x];
  2174. }
  2175. if (wireless != null) {
  2176. var x = {};
  2177. x.family = 'IPv4';
  2178. x.type = 'wireless';
  2179. x.address = wireless.IPAddress;
  2180. x.netmask = wireless.SubnetMask;
  2181. x.mac = wireless.MACAddress.split('-').join(':').toUpperCase();
  2182. x.gateway = wireless.DefaultGateway;
  2183. net.netif2['Wireless'] = [x];
  2184. }
  2185. net.updateTime = Date.now();
  2186. net._id = 'if' + dev.nodeid;
  2187. net.type = 'ifinfo';
  2188. parent.db.Set(net);
  2189. // Event the node interface information change
  2190. parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, { action: 'ifchange', nodeid: dev.nodeid, domain: dev.nodeid.split('/')[1], nolog: 1 });
  2191. devTaskCompleted(dev);
  2192. }
  2193. /*
  2194. // http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
  2195. const DMTFCPUStatus = ["Unknown", "Enabled", "Disabled by User", "Disabled By BIOS (POST Error)", "Idle", "Other"];
  2196. 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"];
  2197. const DMTFMemFormFactor = ['', "Other", "Unknown", "SIMM", "SIP", "Chip", "DIP", "ZIP", "Proprietary Card", "DIMM", "TSOP", "Row of chips", "RIMM", "SODIMM", "SRIMM", "FB-DIM"];
  2198. const DMTFProcFamilly = { // Page 46 of DMTF document
  2199. 191: "Intel&reg; Core&trade; 2 Duo Processor",
  2200. 192: "Intel&reg; Core&trade; 2 Solo processor",
  2201. 193: "Intel&reg; Core&trade; 2 Extreme processor",
  2202. 194: "Intel&reg; Core&trade; 2 Quad processor",
  2203. 195: "Intel&reg; Core&trade; 2 Extreme mobile processor",
  2204. 196: "Intel&reg; Core&trade; 2 Duo mobile processor",
  2205. 197: "Intel&reg; Core&trade; 2 Solo mobile processor",
  2206. 198: "Intel&reg; Core&trade; i7 processor",
  2207. 199: "Dual-Core Intel&reg; Celeron&reg; processor"
  2208. };
  2209. */
  2210. function attemptFetchHardwareInventoryResponse(stack, name, responses, status) {
  2211. const dev = stack.dev;
  2212. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2213. if (status != 200) { devTaskCompleted(dev); return; }
  2214. // Extract basic data
  2215. var hw = {}
  2216. hw.PlatformGUID = responses['CIM_ComputerSystemPackage'].response.PlatformGUID;
  2217. hw.Chassis = responses['CIM_Chassis'].response;
  2218. hw.Chips = responses['CIM_Chip'].responses;
  2219. hw.Card = responses['CIM_Card'].response;
  2220. hw.Bios = responses['CIM_BIOSElement'].response;
  2221. hw.Processors = responses['CIM_Processor'].responses;
  2222. hw.PhysicalMemory = responses['CIM_PhysicalMemory'].responses;
  2223. hw.MediaAccessDevice = responses['CIM_MediaAccessDevice'].responses;
  2224. hw.PhysicalPackage = responses['CIM_PhysicalPackage'].responses;
  2225. // Convert the hardware data into the same structure as we get from Windows
  2226. var hw2 = { hardware: { windows: {}, identifiers: {} } };
  2227. hw2.hardware.identifiers.product_uuid = guidToStr(hw.PlatformGUID);
  2228. if ((hw.PhysicalMemory != null) && (hw.PhysicalMemory.length > 0)) {
  2229. var memory = [];
  2230. for (var i in hw.PhysicalMemory) {
  2231. var m2 = {}, m = hw.PhysicalMemory[i];
  2232. m2.BankLabel = m.BankLabel;
  2233. m2.Capacity = m.Capacity;
  2234. if (typeof m.PartNumber == 'string') { m2.PartNumber = m.PartNumber.trim(); }
  2235. if (typeof m.PartNumber == 'number') { m2.PartNumber = m.PartNumber; }
  2236. if (typeof m.SerialNumber == 'string') { m2.SerialNumber = m.SerialNumber.trim(); }
  2237. if (typeof m.SerialNumber == 'number') { m2.SerialNumber = m.SerialNumber; }
  2238. if (typeof m.Manufacturer == 'string') { m2.Manufacturer = m.Manufacturer.trim(); }
  2239. if (typeof m.Manufacturer == 'number') { m2.Manufacturer = m.Manufacturer; }
  2240. memory.push(m2);
  2241. }
  2242. hw2.hardware.windows.memory = memory;
  2243. }
  2244. if ((hw.MediaAccessDevice != null) && (hw.MediaAccessDevice.length > 0)) {
  2245. var drives = [];
  2246. for (var i in hw.MediaAccessDevice) {
  2247. var m2 = {}, m = hw.MediaAccessDevice[i];
  2248. m2.Caption = m.DeviceID;
  2249. if (m.MaxMediaSize) { m2.Size = (m.MaxMediaSize * 1000); }
  2250. drives.push(m2);
  2251. }
  2252. hw2.hardware.identifiers.storage_devices = drives;
  2253. }
  2254. if (hw.Bios != null) {
  2255. if (typeof hw.Bios.Manufacturer == 'string') { hw2.hardware.identifiers.bios_vendor = hw.Bios.Manufacturer.trim(); }
  2256. if (typeof hw.Bios.Manufacturer == 'number') { hw2.hardware.identifiers.bios_vendor = hw.Bios.Manufacturer; }
  2257. hw2.hardware.identifiers.bios_version = hw.Bios.Version;
  2258. if (hw.Bios.ReleaseDate && hw.Bios.ReleaseDate.Datetime) { hw2.hardware.identifiers.bios_date = hw.Bios.ReleaseDate.Datetime; }
  2259. }
  2260. if (hw.PhysicalPackage != null) {
  2261. if (typeof hw.Card.Model == 'string') { hw2.hardware.identifiers.board_name = hw.Card.Model.trim(); }
  2262. if (typeof hw.Card.Model == 'number') { hw2.hardware.identifiers.board_name = hw.Card.Model; }
  2263. if (typeof hw.Card.Manufacturer == 'string') { hw2.hardware.identifiers.board_vendor = hw.Card.Manufacturer.trim(); }
  2264. if (typeof hw.Card.Manufacturer == 'number') { hw2.hardware.identifiers.board_vendor = hw.Card.Manufacturer; }
  2265. if (typeof hw.Card.Version == 'string') { hw2.hardware.identifiers.board_version = hw.Card.Version.trim(); }
  2266. if (typeof hw.Card.Version == 'number') { hw2.hardware.identifiers.board_version = hw.Card.Version; }
  2267. if (typeof hw.Card.SerialNumber == 'string') { hw2.hardware.identifiers.board_serial = hw.Card.SerialNumber.trim(); }
  2268. if (typeof hw.Card.SerialNumber == 'number') { hw2.hardware.identifiers.board_serial = hw.Card.SerialNumber; }
  2269. }
  2270. if ((hw.Chips != null) && (hw.Chips.length > 0)) {
  2271. for (var i in hw.Chips) {
  2272. if ((hw.Chips[i].ElementName == 'Managed System Processor Chip') && (hw.Chips[i].Version)) {
  2273. hw2.hardware.identifiers.cpu_name = hw.Chips[i].Version;
  2274. }
  2275. }
  2276. }
  2277. // Compute the hash of the document
  2278. hw2.hash = parent.crypto.createHash('sha384').update(JSON.stringify(hw2)).digest().toString('hex');
  2279. // Fetch system information
  2280. parent.db.GetHash('si' + dev.nodeid, function (err, results) {
  2281. var sysinfohash = null;
  2282. if ((results != null) && (results.length == 1)) { sysinfohash = results[0].hash; }
  2283. if (sysinfohash != hw2.hash) {
  2284. // Hardware information has changed, update the database
  2285. hw2._id = 'si' + dev.nodeid;
  2286. hw2.domain = dev.nodeid.split('/')[1];
  2287. hw2.time = Date.now();
  2288. hw2.type = 'sysinfo';
  2289. parent.db.Set(hw2);
  2290. // Event the new sysinfo hash, this will notify everyone that the sysinfo document was changed
  2291. var event = { etype: 'node', action: 'sysinfohash', nodeid: dev.nodeid, domain: hw2.domain, hash: hw2.hash, nolog: 1 };
  2292. parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, event);
  2293. }
  2294. });
  2295. devTaskCompleted(dev);
  2296. }
  2297. //
  2298. // Intel AMT Activation
  2299. //
  2300. function activateIntelAmt(dev) {
  2301. // Find the Intel AMT policy
  2302. const mesh = parent.webserver.meshes[dev.meshid];
  2303. if (mesh == null) { dev.consoleMsg("Unable to find device group (" + dev.meshid + ")."); removeAmtDevice(dev, 36); return false; }
  2304. var amtPolicy = 0; // 0 = Do nothing, 1 = Deactivate CCM, 2 = CCM, 3 = ACM
  2305. var ccmPolicy = 0; // Only used when in ACM policy: 0 = Do nothing, 1 = Deactivate CCM, 2 = CCM is ACM fails
  2306. if (mesh.amt != null) { if (typeof mesh.amt.type == 'number') { amtPolicy = mesh.amt.type; } if (typeof mesh.amt.ccm == 'number') { ccmPolicy = mesh.amt.ccm; } }
  2307. 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; }
  2308. if (amtPolicy == 0) { removeAmtDevice(dev, 37); return false; } // Do nothing, we should not have gotten this CIRA-LMS connection.
  2309. if (amtPolicy == 2) { activateIntelAmtCcm(dev, mesh.amt.password); } // Activate to CCM policy
  2310. if ((amtPolicy == 3) || (amtPolicy == 4)) { // Activate to ACM policy
  2311. var acminfo = checkAcmActivation(dev);
  2312. if ((acminfo == null) || (acminfo.err != null)) {
  2313. // No opportunity to activate to ACM, check if we are in CCM
  2314. if ((dev.mpsConnection.tag.meiState.Flags & 2) != 0) {
  2315. if ((amtPolicy == 3) && (ccmPolicy == 1)) { deactivateIntelAmtCCM(dev); } // If we are in ACM policy and CCM is not allowed, deactivate it now.
  2316. else { return true; } // We are in CCM, keep going
  2317. } else {
  2318. // We are not in CCM, go to CCM now
  2319. 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.
  2320. else {
  2321. // Unable to find an activation match.
  2322. if (acminfo == null) { dev.consoleMsg("No opportunity for ACM activation."); } else { dev.consoleMsg("No opportunity for ACM activation: " + acminfo.err); }
  2323. removeAmtDevice(dev, 38);
  2324. return false; // We are not in CCM and policy restricts use of CCM, so exit now.
  2325. }
  2326. }
  2327. } else {
  2328. // Found a certificate to activate to ACM.
  2329. if ((dev.mpsConnection.tag.meiState.Flags & 2) != 0) {
  2330. // We are in CCM, deactivate CCM first.
  2331. deactivateIntelAmtCCM(dev);
  2332. } else {
  2333. // We are not activated now, go to ACM directly.
  2334. // Check if we are allowed to perform TLS ACM activation
  2335. var TlsAcmActivation = false;
  2336. var domain = parent.config.domains[dev.domainid];
  2337. if (domain && domain.amtmanager && (domain.amtmanager.tlsacmactivation == true)) { TlsAcmActivation = true; }
  2338. // Check Intel AMT version
  2339. if (typeof dev.intelamt.ver == 'string') {
  2340. var verSplit = dev.intelamt.ver.split('.');
  2341. if (verSplit.length >= 2) {
  2342. dev.aquired.majorver = parseInt(verSplit[0]);
  2343. dev.aquired.minorver = parseInt(verSplit[1]);
  2344. if (verSplit.length >= 3) { dev.aquired.maintenancever = parseInt(verSplit[2]); }
  2345. }
  2346. }
  2347. // If this is Intel AMT 14 or better and allowed, we are going to attempt a host-based end-to-end TLS activation.
  2348. if (TlsAcmActivation && (dev.aquired.majorver >= 14)) {
  2349. // Perform host-based TLS ACM activation
  2350. activateIntelAmtTlsAcm(dev, mesh.amt.password, acminfo);
  2351. } else {
  2352. // Perform host-based ACM activation
  2353. activateIntelAmtAcm(dev, mesh.amt.password, acminfo);
  2354. }
  2355. }
  2356. }
  2357. }
  2358. return false;
  2359. }
  2360. function activateIntelAmtCcm(dev, password) {
  2361. // Generate a random Intel AMT password if needed
  2362. if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
  2363. dev.temp = { pass: password };
  2364. // Setup the WSMAN stack, no TLS
  2365. var comm = CreateWsmanComm(dev.nodeid, 16992, dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass, 0, null, dev.mpsConnection); // No TLS
  2366. var wsstack = WsmanStackCreateService(comm);
  2367. dev.amtstack = AmtStackCreateService(wsstack);
  2368. dev.amtstack.dev = dev;
  2369. dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtCcmEx1);
  2370. }
  2371. function activateIntelAmtCcmEx1(stack, name, responses, status) {
  2372. const dev = stack.dev;
  2373. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2374. if (status != 200) { dev.consoleMsg("Failed to get Intel AMT state."); removeAmtDevice(dev, 39); return; }
  2375. if (responses['IPS_HostBasedSetupService'].response['AllowedControlModes'].length != 2) { dev.consoleMsg("Client control mode activation not allowed."); removeAmtDevice(dev, 40); return; }
  2376. // Log the activation request, logging is a required step for activation.
  2377. var domain = parent.config.domains[dev.domainid];
  2378. if (domain == null) { dev.consoleMsg("Invalid domain."); removeAmtDevice(dev, 41); return; }
  2379. 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) {
  2380. dev.consoleMsg("Unable to log operation."); removeAmtDevice(dev, 42); return;
  2381. }
  2382. // Perform CCM activation
  2383. 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);
  2384. }
  2385. function activateIntelAmtCcmEx2(stack, name, responses, status) {
  2386. const dev = stack.dev;
  2387. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2388. if (status != 200) { dev.consoleMsg("Failed to activate Intel AMT to CCM."); removeAmtDevice(dev, 43); return; }
  2389. // Update the device
  2390. dev.aquired = {};
  2391. dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM
  2392. if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') {
  2393. var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
  2394. if (verSplit.length >= 2) {
  2395. dev.aquired.version = verSplit[0] + '.' + verSplit[1];
  2396. dev.aquired.majorver = parseInt(verSplit[0]);
  2397. dev.aquired.minorver = parseInt(verSplit[1]);
  2398. if (verSplit.length >= 3) {
  2399. dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
  2400. dev.aquired.maintenancever = parseInt(verSplit[2]);
  2401. }
  2402. }
  2403. }
  2404. if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
  2405. dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
  2406. }
  2407. dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm;
  2408. dev.intelamt.user = dev.aquired.user = 'admin';
  2409. dev.intelamt.pass = dev.aquired.pass = dev.temp.pass;
  2410. dev.intelamt.tls = dev.aquired.tls = 0;
  2411. dev.aquired.lastContact = Date.now();
  2412. dev.aquired.state = 2; // Activated
  2413. dev.aquired.warn = 0; // Clear all warnings
  2414. delete dev.acctry;
  2415. delete dev.temp;
  2416. UpdateDevice(dev);
  2417. // Success, switch to managing this device
  2418. obj.parent.mpsserver.SendJsonControl(dev.mpsConnection, { action: 'mestate' }); // Request an MEI state refresh
  2419. dev.consoleMsg("Succesfully activated in CCM mode, holding 10 seconds...");
  2420. // Wait 10 seconds before attempting to manage this device in CCM
  2421. var f = function doManage() { if (isAmtDeviceValid(dev)) { attemptInitialContact(doManage.dev); } }
  2422. f.dev = dev;
  2423. setTimeout(f, 10000);
  2424. }
  2425. // Check if this device has any way to be activated in ACM using our server certificates.
  2426. function checkAcmActivation(dev) {
  2427. var domain = parent.config.domains[dev.domainid];
  2428. 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." };
  2429. const activationCerts = domain.amtacmactivation.certs;
  2430. 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." };
  2431. const deviceHashes = dev.mpsConnection.tag.meiState.Hashes;
  2432. // Get the trusted FQDN of the device
  2433. var trustedFqdn = null;
  2434. if (dev.mpsConnection.tag.meiState.OsDnsSuffix != null) { trustedFqdn = dev.mpsConnection.tag.meiState.OsDnsSuffix; }
  2435. if (dev.mpsConnection.tag.meiState.DnsSuffix != null) { trustedFqdn = dev.mpsConnection.tag.meiState.DnsSuffix; }
  2436. if (trustedFqdn == null) return { err: "No trusted DNS suffix reported" };
  2437. // Find a matching certificate
  2438. var gotSuffixMatch = false;
  2439. var devValidHash = false;
  2440. for (var i in activationCerts) {
  2441. var cert = activationCerts[i];
  2442. var certDnsMatch = checkAcmActivationCertName(cert.cn, trustedFqdn);
  2443. if (certDnsMatch == true) { gotSuffixMatch = true; }
  2444. if ((cert.cn == '*') || certDnsMatch) {
  2445. for (var j in deviceHashes) {
  2446. var hashInfo = deviceHashes[j];
  2447. if ((hashInfo != null) && (hashInfo.isActive == 1)) {
  2448. devValidHash = true;
  2449. if ((hashInfo.hashAlgorithmStr == 'SHA256') && (hashInfo.certificateHash.toLowerCase() == cert.sha256)) { return { cert: cert, fqdn: trustedFqdn, hash: cert.sha256 }; } // Found a match
  2450. else if ((hashInfo.hashAlgorithmStr == 'SHA1') && (hashInfo.certificateHash.toLowerCase() == cert.sha1)) { return { cert: cert, fqdn: trustedFqdn, hash: cert.sha1 }; } // Found a match
  2451. }
  2452. }
  2453. }
  2454. }
  2455. if (!devValidHash) { return { err: "Intel AMT has no trusted root hashes for \"" + trustedFqdn + "\"." }; } // Found no trusted root hashes
  2456. if (gotSuffixMatch) { return { err: "Certificate root hash matching failed for \"" + trustedFqdn + "\"." }; } // Found a DNS suffix match, but root hash failed to match.
  2457. return { err: "No matching ACM activation certificate for \"" + trustedFqdn + "\"." }; // Did not find a match
  2458. }
  2459. // Return true if the trusted FQDN matched the certificate common name
  2460. function checkAcmActivationCertName(commonName, trustedFqdn) {
  2461. commonName = commonName.toLowerCase();
  2462. trustedFqdn = trustedFqdn.toLowerCase();
  2463. if (commonName.startsWith('*.') && (commonName.length > 2)) { commonName = commonName.substring(2); }
  2464. return ((commonName == trustedFqdn) || (trustedFqdn.endsWith('.' + commonName)));
  2465. }
  2466. // Attempt Intel AMT TLS ACM activation
  2467. function activateIntelAmtTlsAcm(dev, password, acminfo) {
  2468. // Check if MeshAgent/MeshCMD can support the startConfigurationhostB() call.
  2469. 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)) {
  2470. // Generate a random Intel AMT password if needed
  2471. if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
  2472. dev.temp = { pass: password, acminfo: acminfo };
  2473. // Get our ACM activation certificate chain
  2474. var acmTlsInfo = parent.certificateOperations.getAcmCertChain(parent.config.domains[dev.domainid], dev.temp.acminfo.fqdn, dev.temp.acminfo.hash);
  2475. if (acmTlsInfo.error == 1) { dev.consoleMsg(acmTlsInfo.errorText); removeAmtDevice(dev, 44); return; }
  2476. dev.acmTlsInfo = acmTlsInfo;
  2477. // Send the MEI command to enable TLS connections
  2478. dev.consoleMsg("Performing TLS ACM activation...");
  2479. dev.controlMsg({ action: 'startTlsHostConfig', hash: acmTlsInfo.hash256, hostVpn: false, dnsSuffixList: null }); // TODO: Use SHA384 is possible.
  2480. } else {
  2481. // MeshCore or MeshCMD is to old
  2482. dev.consoleMsg("This software is to old to support ACM activation, pleasse update and try again.");
  2483. removeAmtDevice(dev);
  2484. }
  2485. }
  2486. // Attempt Intel AMT TLS ACM activation after startConfiguration() is called on remote device
  2487. function activateIntelAmtTlsAcmEx(dev, startConfigData) {
  2488. if ((startConfigData == null) || (startConfigData.status != 0) || (typeof startConfigData.hash != 'string')) {
  2489. // Unable to call startTlsHostConfig on remote host.
  2490. dev.consoleMsg("Failed to startConfigurationHBased(), status = " + startConfigData.status);
  2491. removeAmtDevice(dev);
  2492. } else {
  2493. // Setup the WSMAN stack, no TLS
  2494. dev.consoleMsg("Attempting TLS connection...");
  2495. 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.
  2496. comm.xtlsFingerprint = startConfigData.hash.toLowerCase(); // Intel AMT leaf TLS cert need to match this hash (SHA256 or SHA384)
  2497. var wsstack = WsmanStackCreateService(comm);
  2498. dev.amtstack = AmtStackCreateService(wsstack);
  2499. dev.amtstack.dev = dev;
  2500. dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', 'CIM_SoftwareIdentity', '*AMT_SetupAndConfigurationService'], activateIntelAmtTlsAcmEx1);
  2501. }
  2502. }
  2503. function activateIntelAmtTlsAcmEx1(stack, name, responses, status) {
  2504. const dev = stack.dev;
  2505. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2506. // Check if we succesfully connected
  2507. if (status != 200) {
  2508. dev.consoleMsg("Failed to perform ACM TLS connection, status " + status + ".");
  2509. //activateIntelAmtAcm(dev); // It's possible to fallback to legacy WSMAN ACM activation here if we needed to..
  2510. removeAmtDevice(dev);
  2511. return;
  2512. }
  2513. // Fetch the Intel AMT version from WSMAN
  2514. if ((responses != null) && (responses['CIM_SoftwareIdentity'] != null) && (responses['CIM_SoftwareIdentity'].responses != null)) {
  2515. var amtlogicalelements = [];
  2516. amtlogicalelements = responses['CIM_SoftwareIdentity'].responses;
  2517. if (responses['AMT_SetupAndConfigurationService'] != null && responses['AMT_SetupAndConfigurationService'].response != null) {
  2518. amtlogicalelements.push(responses['AMT_SetupAndConfigurationService'].response);
  2519. }
  2520. if (amtlogicalelements.length > 0) {
  2521. var vs = getInstance(amtlogicalelements, 'AMT')['VersionString'];
  2522. if (vs != null) {
  2523. dev.aquired.version = vs;
  2524. version = dev.aquired.version.split('.')
  2525. dev.aquired.versionmajor = parseInt(version[0]);
  2526. dev.aquired.versionminor = parseInt(version[1]);
  2527. if (version.length > 2) { dev.aquired.versionmaintenance = parseInt(version[2]); }
  2528. }
  2529. }
  2530. }
  2531. // Fetch the Intel AMT version from HTTP stack
  2532. if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) {
  2533. var s = stack.wsman.comm.amtVersion.split('.');
  2534. if (s.length >= 2) {
  2535. dev.aquired.version = s[0] + '.' + s[1] + '.';
  2536. dev.aquired.versionmajor = parseInt(s[0]);
  2537. dev.aquired.versionminor = parseInt(s[1]);
  2538. if (s.length >= 3) {
  2539. dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
  2540. dev.aquired.versionmaintenance = parseInt(s[2]);
  2541. }
  2542. }
  2543. }
  2544. // If we can't get the Intel AMT version, stop here.
  2545. if (dev.aquired.version == null) { dev.consoleMsg('Could not get Intel AMT version.'); removeAmtDevice(dev); return; } // Could not get Intel AMT version, disconnect();
  2546. // Get the digest realm
  2547. if (responses['AMT_GeneralSettings'] && responses['AMT_GeneralSettings'].response && (typeof responses['AMT_GeneralSettings'].response['DigestRealm'] == 'string')) {
  2548. // Set the realm in the stack since we are not doing HTTP digest and this will be checked later by different code.
  2549. dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm = responses['AMT_GeneralSettings'].response['DigestRealm'];
  2550. } else {
  2551. dev.consoleMsg('Could not get Intel AMT digest realm.'); removeAmtDevice(dev); return;
  2552. }
  2553. // Looks like we are doing well.
  2554. dev.consoleMsg('Succesful TLS connection, Intel AMT v' + dev.aquired.version);
  2555. // Log this activation event
  2556. 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 };
  2557. 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.
  2558. parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, event);
  2559. // Log the activation request, logging is a required step for activation.
  2560. var domain = parent.config.domains[dev.domainid];
  2561. if (domain == null) { dev.consoleMsg("Invalid domain."); removeAmtDevice(dev, 41); return; }
  2562. 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) {
  2563. dev.consoleMsg("Unable to log operation."); removeAmtDevice(dev, 42); return;
  2564. }
  2565. // See what admin password to use
  2566. dev.aquired.user = 'admin';
  2567. dev.aquired.pass = dev.temp.password;
  2568. // Set the account password
  2569. if (typeof dev.temp.mebxpass == 'string') {
  2570. // Set the new MEBx password
  2571. dev.consoleMsg('Setting MEBx password...');
  2572. dev.amtstack.AMT_SetupAndConfigurationService_SetMEBxPassword(dev.temp.mebxpass, activateIntelAmtTlsAcmEx2);
  2573. } else {
  2574. // Set the admin password
  2575. dev.consoleMsg('Setting admin password...');
  2576. dev.amtstack.AMT_AuthorizationService_SetAdminAclEntryEx(dev.aquired.user, hex_md5(dev.aquired.user + ':' + dev.aquired.realm + ':' + dev.aquired.pass), activateIntelAmtTlsAcmEx3);
  2577. }
  2578. }
  2579. // Response from setting MEBx password
  2580. function activateIntelAmtTlsAcmEx2(stack, name, responses, status) {
  2581. const dev = stack.dev;
  2582. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2583. if (status != 200) { dev.consoleMsg('Failed to set MEBx password, status=' + status + '.'); destroyDevice(dev); return; }
  2584. dev.consoleMsg('MEBx password set. Setting admin password...');
  2585. // Set the admin password
  2586. dev.amtstack.AMT_AuthorizationService_SetAdminAclEntryEx(dev.aquired.user, hex_md5(dev.aquired.user + ':' + dev.aquired.realm + ':' + dev.aquired.pass), activateIntelAmtTlsAcmEx3);
  2587. }
  2588. // Response from setting admin password
  2589. function activateIntelAmtTlsAcmEx3(stack, name, responses, status) {
  2590. const dev = stack.dev;
  2591. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2592. if (status != 200) { dev.consoleMsg('Failed to set admin password, status=' + status + '.'); removeAmtDevice(dev); return; }
  2593. dev.consoleMsg('Admin password set.');
  2594. // Switch the state of Intel AMT.
  2595. if ((dev.mpsConnection != null) && (dev.mpsConnection.tag != null) && (dev.mpsConnection.tag.meiState != null)) { dev.mpsConnection.tag.meiState.ProvisioningState = 2; }
  2596. dev.aquired.controlMode = 2; // 1 = CCM, 2 = ACM
  2597. dev.aquired.state = 2; // Activated
  2598. dev.hbacmtls = 1; // Indicate that we are doing a Host
  2599. // Proceed to going the normal Intel AMT sync. This will trigger a commit when the TLS cert is setup.
  2600. dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
  2601. }
  2602. // Attempt Intel AMT ACM activation
  2603. function activateIntelAmtAcm(dev, password, acminfo) {
  2604. // Check if MeshAgent/MeshCMD can support the stopConfiguration() call.
  2605. 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)) {
  2606. // Generate a random Intel AMT password if needed
  2607. if (acminfo != null) {
  2608. if ((password == null) || (password == '')) { password = getRandomAmtPassword(); }
  2609. dev.temp = { pass: password, acminfo: acminfo };
  2610. }
  2611. dev.acmactivate = 1;
  2612. // Send the MEI command to stop configuration.
  2613. // If Intel AMT is "in-provisioning" mode, the WSMAN ACM activation will not work, so we need to do this first.
  2614. dev.consoleMsg("Getting ready for ACM activation...");
  2615. dev.controlMsg({ action: 'stopConfiguration' });
  2616. } else {
  2617. // MeshCore or MeshCMD is to old
  2618. dev.consoleMsg("This software is to old to support ACM activation, pleasse update and try again.");
  2619. removeAmtDevice(dev);
  2620. }
  2621. }
  2622. function activateIntelAmtAcmEx0(dev) {
  2623. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2624. // Setup the WSMAN stack, no TLS
  2625. var comm = CreateWsmanComm(dev.nodeid, 16992, dev.mpsConnection.tag.meiState.OsAdmin.user, dev.mpsConnection.tag.meiState.OsAdmin.pass, 0, null, dev.mpsConnection); // No TLS
  2626. var wsstack = WsmanStackCreateService(comm);
  2627. dev.amtstack = AmtStackCreateService(wsstack);
  2628. dev.amtstack.dev = dev;
  2629. dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activateIntelAmtAcmEx1);
  2630. }
  2631. function activateIntelAmtAcmEx1(stack, name, responses, status) {
  2632. const dev = stack.dev;
  2633. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2634. if (status != 200) { dev.consoleMsg("Failed to get Intel AMT state."); removeAmtDevice(dev, 46); return; }
  2635. // Sign the Intel AMT ACM activation request
  2636. 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 };
  2637. 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);
  2638. if (acmdata == null) { dev.consoleMsg("Failed to sign ACM nonce."); removeAmtDevice(dev, 47); return; }
  2639. if (acmdata.error != null) { dev.consoleMsg(acmdata.errorText); removeAmtDevice(dev, 48); return; }
  2640. // Log this activation event
  2641. 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 };
  2642. 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.
  2643. parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, event);
  2644. // Start the activation process
  2645. dev.temp.acmdata = acmdata;
  2646. dev.temp.acmdata.index = 0;
  2647. dev.consoleMsg("Performing ACM activation...");
  2648. activateIntelAmtAcmEx2(dev);
  2649. }
  2650. // Recursive function to inject the provisioning certificates into AMT in the proper order and completes ACM activation
  2651. function activateIntelAmtAcmEx2(dev) {
  2652. var acmdata = dev.temp.acmdata;
  2653. var leaf = (acmdata.index == 0), root = (acmdata.index == (acmdata.certs.length - 1));
  2654. if ((acmdata.index < acmdata.certs.length) && (acmdata.certs[acmdata.index] != null)) {
  2655. dev.amtstack.IPS_HostBasedSetupService_AddNextCertInChain(acmdata.certs[acmdata.index], leaf, root,
  2656. function (stack, name, responses, status) {
  2657. const dev = stack.dev;
  2658. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2659. if (status != 200) { dev.consoleMsg("Failed to set ACM certificate chain (" + status + ")."); removeAmtDevice(dev, 49); return; }
  2660. if (responses['Body']['ReturnValue'] != 0) { dev.consoleMsg("Failed to set ACM certificate chain (ERR/" + responses['Body']['ReturnValue'] + ")."); removeAmtDevice(dev, 50); return; }
  2661. // Move to the next activation operation
  2662. dev.temp.acmdata.index++;
  2663. activateIntelAmtAcmEx2(dev);
  2664. }
  2665. );
  2666. } else {
  2667. dev.amtstack.IPS_HostBasedSetupService_AdminSetup(2, acmdata.password, acmdata.nonce, 2, acmdata.signature,
  2668. function (stack, name, responses, status) {
  2669. const dev = stack.dev;
  2670. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
  2671. if (status != 200) { dev.consoleMsg("Failed to complete ACM activation (" + status + ")."); removeAmtDevice(dev, 51); return; }
  2672. if (responses['Body']['ReturnValue'] != 0) { dev.consoleMsg("Failed to complete ACM activation (ERR/" + responses['Body']['ReturnValue'] + ")."); removeAmtDevice(dev, 52); return; }
  2673. // Success, switch to managing this device
  2674. obj.parent.mpsserver.SendJsonControl(dev.mpsConnection, { action: 'mestate' }); // Request an MEI state refresh
  2675. dev.consoleMsg("Succesfully activated in ACM mode, holding 10 seconds...");
  2676. // Update the device
  2677. dev.aquired = {};
  2678. dev.aquired.controlMode = 2; // 1 = CCM, 2 = ACM
  2679. if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') {
  2680. var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
  2681. 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]); }
  2682. }
  2683. if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
  2684. dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
  2685. }
  2686. dev.aquired.realm = dev.amtstack.wsman.comm.digestRealm;
  2687. dev.intelamt.user = dev.aquired.user = 'admin';
  2688. dev.intelamt.pass = dev.aquired.pass = dev.temp.pass;
  2689. dev.intelamt.tls = dev.aquired.tls = 0;
  2690. dev.aquired.lastContact = Date.now();
  2691. dev.aquired.state = 2; // Activated
  2692. delete dev.acctry;
  2693. delete dev.temp;
  2694. UpdateDevice(dev);
  2695. // Wait 10 seconds before attempting to manage this device in ACM
  2696. var f = function doManage() { if (isAmtDeviceValid(dev)) { attemptInitialContact(doManage.dev); } }
  2697. f.dev = dev;
  2698. setTimeout(f, 10000);
  2699. }
  2700. );
  2701. }
  2702. }
  2703. //
  2704. // Intel AMT CCM deactivation
  2705. //
  2706. function deactivateIntelAmtCCM(dev) {
  2707. dev.consoleMsg("Deactivating CCM...");
  2708. dev.deactivateCcmPending = 1;
  2709. dev.controlMsg({ action: 'deactivate' });
  2710. }
  2711. // This is called after the deactivation call
  2712. function deactivateIntelAmtCCMEx(dev, state) {
  2713. if (state != 0) {
  2714. dev.consoleMsg("Failed to deactivate Intel AMT CCM.");
  2715. removeAmtDevice(dev, 53);
  2716. } else {
  2717. // Update the device
  2718. dev.aquired = {};
  2719. dev.aquired.controlMode = 0; // 1 = CCM, 2 = ACM
  2720. dev.aquired.state = 0; // Not activated
  2721. delete dev.acctry;
  2722. delete dev.amtstack;
  2723. UpdateDevice(dev);
  2724. if (dev.policy.amtPolicy == 1) { // Deactivation policy, we are done.
  2725. dev.consoleMsg("Deactivation successful.");
  2726. dev.consoleMsg("Done.");
  2727. removeAmtDevice(dev, 54);
  2728. } else {
  2729. // Wait 20 seconds before attempting any operation on this device
  2730. dev.consoleMsg("Deactivation successful, holding for 1 minute...");
  2731. var f = function askMeiState() {
  2732. askMeiState.dev.pendingUpdatedMeiState = 1;
  2733. askMeiState.dev.controlMsg({ action: 'mestate' });
  2734. }
  2735. f.dev = dev;
  2736. setTimeout(f, 60000);
  2737. }
  2738. }
  2739. }
  2740. //
  2741. // General Methods
  2742. //
  2743. // Called this when a task is completed, when all tasks are completed the call back function will be called.
  2744. function devTaskCompleted(dev) {
  2745. dev.taskCount--;
  2746. if (dev.taskCount == 0) { var f = dev.taskCompleted; delete dev.taskCount; delete dev.taskCompleted; if (f != null) { f(dev); } }
  2747. }
  2748. 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); }
  2749. // Base64 to string conversion utility functions
  2750. function atob(x) { return Buffer.from(x, 'base64').toString('binary'); }
  2751. function btoa(x) { return Buffer.from(x, 'binary').toString('base64'); }
  2752. // Check which key pair matches the public key in the certificate
  2753. function amtcert_linkCertPrivateKey(certs, keys) {
  2754. if ((keys == null) || (keys.length == 0)) return;
  2755. for (var i in certs) {
  2756. var cert = certs[i];
  2757. try {
  2758. 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, "");
  2759. publicKeyPEM = publicKeyPEM.substring(0, publicKeyPEM.length - 24); // Remove the PEM footer
  2760. for (var j = 0; j < keys.length; j++) {
  2761. 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.
  2762. keys[j].XCert = cert; // Link the key pair to the certificate
  2763. cert.XPrivateKey = keys[j]; // Link the certificate to the key pair
  2764. }
  2765. }
  2766. } catch (ex) { console.log(ex); }
  2767. }
  2768. }
  2769. // Generate a random Intel AMT password
  2770. function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
  2771. function getRandomAmtPassword() { var p; do { p = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
  2772. function getRandomPassword() { return Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
  2773. 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; }
  2774. function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
  2775. function hex_md5(str) { return parent.crypto.createHash('md5').update(str).digest('hex'); }
  2776. function Clone(v) { return JSON.parse(JSON.stringify(v)); }
  2777. function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
  2778. function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
  2779. function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
  2780. // Returns a UEFI boot parameter in binary
  2781. function makeUefiBootParam(type, data, len) {
  2782. 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); } }
  2783. return parent.common.ShortToStrX(0x8086) + parent.common.ShortToStrX(type) + parent.common.IntToStrX(data.length) + data;
  2784. }
  2785. function parseCertName(x) {
  2786. var j, r = {}, xx = x.split(',');
  2787. for (var i in xx) { j = xx[i].indexOf('='); r[xx[i].substring(0, j)] = xx[i].substring(j + 1); }
  2788. return r;
  2789. }
  2790. /*
  2791. function amtcert_signWithCaKey(DERKey, caPrivateKey, certAttributes, issuerAttributes, extKeyUsage) {
  2792. return obj.amtcert_createCertificate(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage);
  2793. }
  2794. */
  2795. // --- Extended Key Usage OID's ---
  2796. // 1.3.6.1.5.5.7.3.1 = TLS Server certificate
  2797. // 1.3.6.1.5.5.7.3.2 = TLS Client certificate
  2798. // 2.16.840.1.113741.1.2.1 = Intel AMT Remote Console
  2799. // 2.16.840.1.113741.1.2.2 = Intel AMT Local Console
  2800. // 2.16.840.1.113741.1.2.3 = Intel AMT Client Setup Certificate (Zero-Touch)
  2801. // Generate a certificate with a set of attributes signed by a rootCert. If the rootCert is obmitted, the generated certificate is self-signed.
  2802. obj.amtcert_createCertificate = function(certAttributes, caPrivateKey, DERKey, issuerAttributes, extKeyUsage) {
  2803. // Generate a keypair and create an X.509v3 certificate
  2804. var keys, cert = obj.parent.certificateOperations.forge.pki.createCertificate();
  2805. cert.publicKey = obj.parent.certificateOperations.forge.pki.publicKeyFromPem('-----BEGIN PUBLIC KEY-----' + DERKey + '-----END PUBLIC KEY-----');
  2806. cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1);
  2807. cert.validity.notBefore = new Date(2018, 0, 1);
  2808. //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.
  2809. cert.validity.notAfter = new Date(2049, 11, 31);
  2810. //cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20);
  2811. var attrs = [];
  2812. if (certAttributes['CN']) attrs.push({ name: 'commonName', value: certAttributes['CN'] });
  2813. if (certAttributes['C']) attrs.push({ name: 'countryName', value: certAttributes['C'] });
  2814. if (certAttributes['ST']) attrs.push({ shortName: 'ST', value: certAttributes['ST'] });
  2815. if (certAttributes['O']) attrs.push({ name: 'organizationName', value: certAttributes['O'] });
  2816. cert.setSubject(attrs);
  2817. // Use root attributes
  2818. var rootattrs = [];
  2819. if (issuerAttributes['CN']) rootattrs.push({ name: 'commonName', value: issuerAttributes['CN'] });
  2820. if (issuerAttributes['C']) rootattrs.push({ name: 'countryName', value: issuerAttributes['C'] });
  2821. if (issuerAttributes['ST']) rootattrs.push({ shortName: 'ST', value: issuerAttributes['ST'] });
  2822. if (issuerAttributes['O']) rootattrs.push({ name: 'organizationName', value: issuerAttributes['O'] });
  2823. cert.setIssuer(rootattrs);
  2824. if (extKeyUsage == null) { extKeyUsage = { name: 'extKeyUsage', serverAuth: true, } } else { extKeyUsage.name = 'extKeyUsage'; }
  2825. /*
  2826. {
  2827. name: 'extKeyUsage',
  2828. serverAuth: true,
  2829. clientAuth: true,
  2830. codeSigning: true,
  2831. emailProtection: true,
  2832. timeStamping: true,
  2833. '2.16.840.1.113741.1.2.1': true
  2834. }
  2835. */
  2836. // Create a leaf certificate
  2837. cert.setExtensions([{
  2838. name: 'basicConstraints'
  2839. }, {
  2840. name: 'keyUsage',
  2841. keyCertSign: true,
  2842. digitalSignature: true,
  2843. nonRepudiation: true,
  2844. keyEncipherment: true,
  2845. dataEncipherment: true
  2846. }, extKeyUsage, {
  2847. name: 'nsCertType',
  2848. client: true,
  2849. server: true,
  2850. email: true,
  2851. objsign: true,
  2852. }, {
  2853. name: 'subjectKeyIdentifier'
  2854. }]);
  2855. // Self-sign certificate
  2856. var privatekey = obj.parent.certificateOperations.forge.pki.privateKeyFromPem(caPrivateKey);
  2857. cert.sign(privatekey, obj.parent.certificateOperations.forge.md.sha256.create());
  2858. return cert;
  2859. }
  2860. return obj;
  2861. };