Added provisioning to ACM flow and unconfiguring from ACM flows to MeshCMD. Provisioning to ACM requires amt-rcs service
mprimros committed
May 24, 2019 at 11:33 UTC
d9ff504676fb743a5845de9c4afc45aed7fd2d48
1 file changed
+245
-19
agents/meshcmd.js
+245
-19
@@ -95,7 +95,7 @@ function run(argv) {
95
//console.log('addedModules = ' + JSON.stringify(addedModules));
96
var actionpath = 'meshaction.txt';
97
if (args.actionfile != null) { actionpath = args.actionfile; }
98
- var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTSCRIPT', 'AMTUUID', 'AMTCCM', 'AMTDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTPRESENCE'];
98
+ var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTSCRIPT', 'AMTUUID', 'AMTCCM', 'AMTACM', 'AMTDEACTIVATE', 'AMTACMDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTPRESENCE'];
99
100
// Load the action file
101
var actionfile = null;
@@ -111,6 +111,8 @@ function run(argv) {
111
if ((typeof args.remotenodeid) == 'string') { settings.remotenodeid = args.remotenodeid; }
112
if ((typeof args.username) == 'string') { settings.username = args.username; }
113
if ((typeof args.password) == 'string') { settings.password = args.password; }
114
+ if ((typeof args.wss) == 'string') { settings.wss = args.wss; }
115
+ if ((typeof args.type) == 'string') { settings.type = args.type; }
116
if ((typeof args.user) == 'string') { settings.username = args.user; }
117
if ((typeof args.pass) == 'string') { settings.password = args.pass; }
118
if ((typeof args.host) == 'string') { settings.hostname = args.host; }
@@ -140,24 +142,26 @@ function run(argv) {
142
console.log('Valid MeshCentral actions:');
143
console.log(' Route - Map a local TCP port to a remote computer.');
144
console.log('\r\nValid local actions:');
143
- console.log(' SMBios - Display System Management BIOS tables for this computer.');
144
- console.log(' RawSMBios - Display RAW System Management BIOS tables for this computer.');
145
- console.log(' MicroLMS - Run MicroLMS, allowing local access to Intel AMT.');
146
- console.log(' AmtInfo - Show Intel AMT version and activation state.');
147
- console.log(' AmtVersions - Show all Intel ME version information.');
148
- console.log(' AmtHashes - Show all Intel AMT trusted activation hashes.');
149
- console.log(' AmtCCM - Activate Intel AMT into Client Control Mode.');
150
- console.log(' AmtDeactivate - Deactivate Intel AMT if activated in Client Control mode.');
145
+ console.log(' SMBios - Display System Management BIOS tables for this computer.');
146
+ console.log(' RawSMBios - Display RAW System Management BIOS tables for this computer.');
147
+ console.log(' MicroLMS - Run MicroLMS, allowing local access to Intel AMT.');
148
+ console.log(' AmtInfo - Show Intel AMT version and activation state.');
149
+ console.log(' AmtVersions - Show all Intel ME version information.');
150
+ console.log(' AmtHashes - Show all Intel AMT trusted activation hashes.');
151
+ console.log(' AmtCCM - Activate Intel AMT into Client Control Mode.');
152
+ console.log(' AmtACM - Activate Intel AMT into Admin Control Mode.');
153
+ console.log(' AmtDeactivate - Deactivate Intel AMT if activated in Client Control mode.');
154
+ console.log(' AmtAcmDeactivate - Deactivate Intel AMT if activated in Admin Control mode.');
155
console.log('\r\nValid local or remote actions:');
152
- console.log(' MeshCommander - Launch a local MeshCommander web server.');
153
- console.log(' AmtUUID - Show Intel AMT unique identifier.');
154
- console.log(' AmtAuditLog - Show the Intel AMT audit log.');
155
- console.log(' AmtLoadWebApp - Load MeshCommander in Intel AMT 11.6+ firmware.');
156
- console.log(' AmtClearWebApp - Clear everything from Intel AMT web storage.');
157
- console.log(' AmtStorageState - Show contents of the Intel AMT web storage.');
158
- console.log(' AmtSaveState - Save all Intel AMT WSMAN object to file.');
159
- console.log(' AmtPresence - Heartbeat a local Intel AMT watchdog agent.');
160
- console.log(' AmtScript - Run .mescript on Intel AMT.');
156
+ console.log(' MeshCommander - Launch a local MeshCommander web server.');
157
+ console.log(' AmtUUID - Show Intel AMT unique identifier.');
158
+ console.log(' AmtAuditLog - Show the Intel AMT audit log.');
159
+ console.log(' AmtLoadWebApp - Load MeshCommander in Intel AMT 11.6+ firmware.');
160
+ console.log(' AmtClearWebApp - Clear everything from Intel AMT web storage.');
161
+ console.log(' AmtStorageState - Show contents of the Intel AMT web storage.');
162
+ console.log(' AmtSaveState - Save all Intel AMT WSMAN object to file.');
163
+ console.log(' AmtPresence - Heartbeat a local Intel AMT watchdog agent.');
164
+ console.log(' AmtScript - Run .mescript on Intel AMT.');
165
console.log('\r\nHelp on a specific action using:\r\n');
166
console.log(' meshcmd help [action]');
167
exit(1); return;
@@ -193,8 +197,18 @@ function run(argv) {
197
console.log(' microlms install/uninstall/start/stop.');
198
} else if (action == 'amtccm') {
199
console.log('AmtCCM will attempt to activate Intel AMT on this computer into client control mode (CCM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be in "pre-provisioning" state for this command to work and a administrator password must be provided. Example usage:\r\n\r\n meshcmd amtccm --pass mypassword');
200
+ } else if (action == 'amtacm') {
201
+ console.log('AmtACM will attempt to activate Intel AMT on this computer into admin control mode (ACM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be in "pre-provisioning" state for this command to work and a administrator password and provisioning certificate must be provided. Example usage:\r\n\r\n amtconfig.js amtacm --wss servername:port');
202
+ console.log('\r\nPossible arguments:\r\n');
203
+ console.log(' --wss [server:port] The address of the AMT remote configuration server.');
204
} else if (action == 'amtdeactivate') {
205
console.log('AmtDeactivate will attempt to deactivate Intel AMT on this computer when in client control mode (CCM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be activated in client control mode for this command to work. Example usage:\r\n\r\n meshcmd amtdeactivate');
206
+ } else if (action == 'amtacmdeactivate') {
207
+ console.log('AmtACMDeactivate will attempt to deactivate Intel AMT on this computer when in admin control mode (ACM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be activated in admin control mode for this command to work. Example usage:\r\n\r\n amtconfig.js amtacmdeactivate');
208
+ console.log('\r\nPossible arguments:\r\n');
209
+ console.log(' --user [username] The Intel AMT login username, admin is default.');
210
+ console.log(' --pass [password] The Intel AMT login password.');
211
+ console.log(' --type [partial/full] Specifies to perform partial or full unprovision.');
212
} else if (action == 'amtuuid') {
213
console.log('AmtUUID action will get the unique identifier of the local or remote Intel AMT computer. By default, the local UUID is obtained unless a host is specified. Intel AMT must be activated for this command to work. Example usage:\r\n\r\n meshcmd amtuuid --host 1.2.3.4 --user admin --pass mypassword --tls');
214
console.log('\r\nPossible arguments:\r\n');
@@ -402,7 +416,7 @@ function run(argv) {
416
amtMei.getLanInterfaceSettings(0, function (result) { console.log('getLanInterfaceSettings0: ' + JSON.stringify(result)); });
417
amtMei.getLanInterfaceSettings(1, function (result) { console.log('getLanInterfaceSettings1: ' + JSON.stringify(result)); });
418
amtMei.getUuid(function (result) { console.log('getUuid: ' + JSON.stringify(result)); });
405
- amtMei.getDnsSuffix(function (result) { console.log('getDnsSuffix: ' + JSON.stringify(result)); });
419
+ amtMei.getDnsSuffix(function (result) { console.log('getDnsSuffix: ' + JSON.stringify(result)); exit(1);});
420
} else if (settings.action == 'amtsavestate') {
421
// Save the entire state of Intel AMT info a JSON file
422
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
@@ -449,10 +463,26 @@ function run(argv) {
463
settings.localport = 16992;
464
debug(1, "Settings: " + JSON.stringify(settings));
465
activeToCCM();
466
+ } else if (settings.action == 'amtacm') {
467
+ // Start activation to ACM
468
+ if ((settings.wss == null) || (typeof settings.wss != 'string') || (settings.wss == '')) { console.log('No or invalid \"server name\" specified, use --wss [servername:port].'); exit(1); return; }
469
+ settings.protocol = 'http:';
470
+ settings.localport = 16992;
471
+ debug(1, "Settings: " + JSON.stringify(settings));
472
+ activeToACM();
473
} else if (settings.action == 'amtdeactivate') {
474
// Deactivate CCM
475
debug(1, "Settings: " + JSON.stringify(settings));
476
deactivateCCM();
477
+ } else if (settings.action == 'amtacmdeactivate') {
478
+ // Deactivate ACM
479
+ if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
480
+ if ((settings.type == null) || (typeof settings.type != 'string') || (settings.type == '')) { console.log('Unprovisioning \"type\" must be specified, use --type [partial/full].'); exit(1); return; }
481
+ if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
482
+ if (settings.hostname == null) { settings.hostname = '127.0.0.1'; }
483
+ if (settings.tls == null) { settings.tls = false; }
484
+ debug(1, "Settings: " + JSON.stringify(settings));
485
+ deactivateACM();
486
} else if (settings.action == 'meshcommander') { // Start MeshCommander
487
startMeshCommander();
488
} else if (settings.action == 'amtauditlog') { // Read the Intel AMT audit log
@@ -713,6 +743,202 @@ function activeToCCMEx3(stack, name, responses, status) {
743
exit(1);
744
}
745
746
+//
747
+// Deactivate Intel AMT ACM
748
+//
749
+
750
+// When called, this will use MEI to deactivate Intel AMT when it's in ACM mode. Calls "unprovision" on MEI and checks the return code.
751
+function deactivateACM() {
752
+ settings.noconsole = true;
753
+ startLms(deactivateACMEx);
754
+}
755
+
756
+function deactivateACMEx() {
757
+ var transport = require('amt-wsman-duk');
758
+ var wsman = require('amt-wsman');
759
+ var amt = require('amt');
760
+ wsstack = new wsman(transport, settings.hostname, settings.tls ? 16993 : 16992, settings.username, settings.password, settings.tls);
761
+ amtstack = new amt(wsstack);
762
+ amtstack.Get("AMT_SetupAndConfigurationService", function (stack, name, responses, status) {
763
+ if (status !== 200) {
764
+ console.log('Command not allowed. Status: ' + status);
765
+ exit(1);
766
+ } else {
767
+ var sacs = responses.Body;
768
+ if (sacs.ZeroTouchConfigurationEnabled == true) { sacs.ZeroTouchConfigurationEnabled = true; }
769
+ amtstack.Put("AMT_SetupAndConfigurationService", sacs, function (stack, name, responses, status) {
770
+ if (settings.type == 'full') {
771
+ amtstack.AMT_SetupAndConfigurationService_Unprovision(2, function (stack, name, responses, status) {
772
+ if (status != 200) { console.log('Failed to fully unconfigure AMT, status ' + status); exit(1); }
773
+ else if (responses.Body.ReturnValue != 0) { console.log('Unprovision failed: ' + responses.Body.ReturnValueStr); exit(1); }
774
+ else { console.log('AMT fully unprovisioned.'); exit(0); }
775
+ });
776
+ } else {
777
+ console.log('Only full unprovision is currently supported.');
778
+ exit(0);
779
+ }
780
+ //} else if (settings.type == 'partial') {
781
+ // amtstack.AMT_SetupAndConfigurationService_PartialUnprovision(null, function (stack, name, responses, status) {
782
+ // if (status != 200) { console.log('Failed to partially unconfigure AMT, status ' + status); exit(1); }
783
+ // else if (responses.Body.ReturnValue != 0) { console.log('Unprovision failed: ' + responses.Body.ReturnValueStr); exit(1); }
784
+ // else { console.log('AMT partially unprovisioned.'); exit(0); }
785
+ // });
786
+ //}
787
+ });
788
+ }
789
+ });
790
+}
791
+
792
+//
793
+// Activate Intel AMT to ACM
794
+//
795
+
796
+
797
+function activeToACM() {
798
+ // See if MicroLMS needs to be started and setup the $$OsAdmin wsman stack
799
+ console.log('Starting AMT Provisioning to Admin Control Mode.');
800
+ settings.noconsole = true;
801
+ // Display Intel AMT version and activation state
802
+ mestate = {};
803
+ var amtMeiModule, amtMei;
804
+ try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { console.log(ex); exit(1); return; }
805
+ amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
806
+ amtMei.getProvisioningState(function (result) {
807
+ if (result) {
808
+ mestate.ProvisioningState = result;
809
+ startLms(getFwNonce); // TODO: Fix this so that it works even if LMS already running.
810
+ }
811
+ });
812
+}
813
+
814
+// Gets the FWNonce from AMT and saves it to a file.
815
+function getFwNonce() {
816
+ osamtstack.Get("IPS_HostBasedSetupService", function (obj, name, responses, status) {
817
+ var fwNonce = Buffer.from(responses["Body"]['ConfigurationNonce'], 'base64');
818
+ activeToACMEx(fwNonce);
819
+ });
820
+}
821
+
822
+function activeToACMEx(fwNonce) {
823
+ // open connection to RCS
824
+ console.log((new Date()) + ' initializing WebSocket');
825
+ // Establish WebSocket connection to RCS server
826
+ var connection = http.request(settings.wss);
827
+ connection.on('upgrade', function (response, socket) {
828
+ // WebSocket is up. Handle data on the duplex socket
829
+ socket.on('data', function (data) {
830
+ // All messages from RCS are JSON.stringify format and need to be parsed
831
+ var message = JSON.parse(data);
832
+ // Handle the AMT provisioning certificate blob (contains provisioning certificate, mcnonce, digital signature and password hash)
833
+ if (message.provCertObj !== undefined) {
834
+ activeToACMEx1(message, function (stack, name, responses, status, message) {
835
+ if (status !== 200) {
836
+ if (status == 2) {
837
+ console.log((new Date()) + ' AMT already provisioned.Exiting ' + status);
838
+ socket.write({ "Type": "finish", "Body": "failed" });
839
+ } else {
840
+ console.log((new Date()) + ' Failed to fetch activation status, status ' + status);
841
+ socket.write({ "Type": "finish", "Body": "failed" });
842
+ }
843
+ socket.end();
844
+ exit(status);
845
+ }
846
+ else if (responses['IPS_HostBasedSetupService'].response['AllowedControlModes'].length != 2) {
847
+ console.log((new Date()) + ' Admin control mode activation not allowed');
848
+ socket.write({ "Type": "finish", "Body": "failed" });
849
+ socket.end();
850
+ exit(status);
851
+ } else {
852
+ console.log((new Date()) + ' Certificate Injection Successful');
853
+ activeToACMEx2(message.digitalSignature, message.mcNonce, message.amtPassword, responses, function(stack, name, responses, status){
854
+ if (status != 200) {
855
+ console.log((new Date()) + ' Failed to activate, status ' + status);
856
+ console.log(JSON.stringify(responses));
857
+ socket.write({ "Type": "finish", "Body": "failed" });
858
+ }
859
+ else if (responses.Body.ReturnValue != 0) {
860
+ console.log((new Date()) + ' Admin control mode activation failed: ' + responses.Body.ReturnValueStr);
861
+ socket.write({ "Type": "finish", "Body": "failed" });
862
+ }
863
+ else {
864
+ console.log((new Date()) + ' AMT Provisioning Success');
865
+ socket.write({"Type":"finish", "Body": "success"});
866
+ socket.end();
867
+ exit(0);
868
+ }
869
+ socket.end();
870
+ exit(status);
871
+ });
872
+ }
873
+ });
874
+ }
875
+ if (message.Type == 'cmd' && message.Body == 'acmready') {
876
+ socket.write(JSON.stringify(fwNonce));
877
+ } else if (message.Type == 'cmd' && message.Body == 'profileready') {
878
+ // TODO Receive .mescript file and apply profile
879
+ }
880
+ });
881
+ socket.on('end', function () {
882
+ console.log((new Date()) + ' socket closed');
883
+ });
884
+ socket.write(JSON.stringify({ "Type": "cmd", "Body": "acm" }));
885
+ });
886
+}
887
+
888
+// Detects AMT provisioning state and injects the certificate chain into AMT firmware
889
+function activeToACMEx1(data, callback) {
890
+ if (mestate.ProvisioningState.state == 0) {
891
+ console.log((new Date()) + ' Performing full provisioning flow.');
892
+ // Perform full provisioning -- AMT was fully unprovisioned
893
+ osamtstack.IPS_HostBasedSetupService_AddNextCertInChain(data.provCertObj.leaf, true, false, function (stack, name, responses, status) {
894
+ if (status !== 200) { exit(status); return; }
895
+ else if (responses['Body']['ReturnValue'] !== 0) { exit(responses['Body']['ReturnValueStr']); return; }
896
+ else if (responses['Body']['ReturnValue'] == 0) {
897
+ console.log((new Date()) + ' Leaf Cert Injection: ' + responses['Body']['ReturnValueStr']);
898
+ osamtstack.IPS_HostBasedSetupService_AddNextCertInChain(data.provCertObj.inter3, false, false, function (stack, name, responses, status) {
899
+ if (status !== 200) { exit(status); return; }
900
+ else if (responses['Body']['ReturnValue'] !== 0) { exit(responses['Body']['ReturnValueStr']); return; }
901
+ else if (responses['Body']['ReturnValue'] == 0) {
902
+ console.log((new Date()) + ' Intermediate 3 Cert Injection: ' + responses['Body']['ReturnValueStr']);
903
+ osamtstack.IPS_HostBasedSetupService_AddNextCertInChain(data.provCertObj.inter2, false, false, function (stack, name, responses, status) {
904
+ if (status !== 200) { exit(status); return; }
905
+ else if (responses['Body']['ReturnValue'] !== 0) { exit(responses['Body']['ReturnValueStr']); return; }
906
+ else if (responses['Body']['ReturnValue'] == 0) {
907
+ console.log((new Date()) + ' Intermediate 2 Cert Injection: ' + responses['Body']['ReturnValueStr']);
908
+ osamtstack.IPS_HostBasedSetupService_AddNextCertInChain(data.provCertObj.root, false, true, function (stack, name, responses, status) {
909
+ if (status !== 200) { exit(status); return; }
910
+ else if (responses['Body']['ReturnValue'] !== 0) { exit(responses['Body']['ReturnValueStr']); return; }
911
+ else if (responses['Body']['ReturnValue'] == 0) {
912
+ console.log((new Date()) + ' Root Cert Injection: ' + responses['Body']['ReturnValueStr']);
913
+ osamtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], function(stack, name, responses, status){
914
+ callback(stack, name, responses, status, data);
915
+ });
916
+ } else { console.log((new Date()) + ' Oops, I fell through the world!'); exit(1); }
917
+ });
918
+ }
919
+ });
920
+ }
921
+ });
922
+ }
923
+ });
924
+ } else if (mestate.ProvisioningState.state == 1) {
925
+ // Perform partial provisioning -- AMT was partial unprovisioned
926
+ // TODO Set remote configuration server parameter in AMT in order to complete provisioning
927
+ console.log((new Date()) + ' Performing partial provisioning flow');
928
+ osamtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], activeToACMEx2);
929
+ } else {
930
+ // AMT already provisioned
931
+ console.log((new Date()) + ' AMT already provisioned. Exiting');
932
+ callback(null, null, null, 2, 'AMT already provisioned. Exiting')
933
+ exit(0);
934
+ }
935
+}
936
+
937
+// Sends the password hash, mcnonce, and digital signature to complete the admin control mode provisioning
938
+function activeToACMEx2(signature, mcnonce, amtpassword, responses, callback) {
939
+ var passwordhash = md5hex('admin:' + responses['AMT_GeneralSettings'].response['DigestRealm'] + ':' + amtpassword).substring(0, 32);
940
+ osamtstack.IPS_HostBasedSetupService_AdminSetup(2, passwordhash, mcnonce, 2, signature, callback);
941
+}
942
943
//
944
// Get AMT UUID