More work on Intel AMT One Click Recovery support.

Ylian Saint-Hilaire committed Mar 23, 2021 at 00:21 UTC fd1248c3913428c0586741314ba688e9005bcb8d
1 file changed +66 -7
amtmanager.js
+66 -7
@@ -825,7 +825,7 @@ module.exports.CreateAmtManager = function (parent) {
825 // Make sure the MPS server root certificate is present.
826 // Start by looking at existing certificates.
827 dev.ocrfile = file;
828 - dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate'], performOneClickRecoveryActionEx);
828 + dev.amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', '*AMT_BootCapabilities'], performOneClickRecoveryActionEx);
829 }
830 }
831 }
@@ -834,9 +834,14 @@ module.exports.CreateAmtManager = function (parent) {
834 function performOneClickRecoveryActionEx(stack, name, responses, status) {
835 const dev = stack.dev;
836 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
837 - if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); removeAmtDevice(dev, 19); return; }
837 + if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); delete dev.ocrfile; return; }
838 +
839 + // Check if this Intel AMT device supports OCR
840 + if (responses['AMT_PublicKeyCertificate'].responses['ForceUEFIHTTPSBoot'] !== true) {
841 + dev.consoleMsg("This Intel AMT device does not support UEFI HTTPS boot (" + status + ")."); delete dev.ocrfile; return;
842 + }
843
839 - // Organize the certificates
844 + // Organize the certificates and add the MPS root cert if missing
845 var xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
846 for (var i in xxCertificates) {
847 xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
@@ -848,15 +853,63 @@ module.exports.CreateAmtManager = function (parent) {
853 attemptRootCertSync(dev, performOneClickRecoveryActionEx2, true);
854 }
855
856 + // MPS root certificate was added
857 function performOneClickRecoveryActionEx2(dev) {
858 + // Ask for Boot Settings Data
859 + dev.amtstack.Get('AMT_BootSettingData', performOneClickRecoveryActionEx3, 0, 1);
860 + }
861 +
862 + // Getting Intel AMT Boot Settings Data
863 + function performOneClickRecoveryActionEx3(stack, name, response, status) {
864 + const dev = stack.dev;
865 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
866 + if (status != 200) { dev.consoleMsg("Failed to get boot settings data (" + status + ")."); delete dev.ocrfile; return; }
867 +
868 // Generate the one-time URL.
853 - var cookie = obj.parent.encodeCookie({ a: 'ocr', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey)
854 - var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/ocr/' + cookie + '.iso';
869 + //var cookie = obj.parent.encodeCookie({ a: 'ocr', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey)
870 + //var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/ocr/' + cookie + '.iso';
871 + delete dev.ocrfile;
872 +
873 + // DEBUG
874 + var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/ocr/abc.iso';
875 + console.log('OCR: ' + url);
876 +
877 + // Generate the boot data for OCR with URL
878 + var r = response.Body;
879 + r['UefiBootParametersArray'] = Buffer.from(makeUefiBootParam(1, url) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2), 'binary').toString('base64');
880 + r['UefiBootNumberOfParams'] = 3;
881 + r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
882 +
883 + // Set the boot order to null, this is needed for some Intel AMT versions that don't clear this automatically.
884 + dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(null, function (stack, name, response, status) {
885 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
886 + if (status != 200) { dev.consoleMsg("Failed to set boot order (" + status + ")."); return; }
887 + dev.amtstack.Put('AMT_BootSettingData', r, performOneClickRecoveryActionEx4, 0, 1);
888 + }, 0, 1);
889 + }
890
856 - // TODO: Issue the WSMAN command.
857 - console.log('Perform One Click Recovery', url);
891 + // Intel AMT Put Boot Settings
892 + function performOneClickRecoveryActionEx4(stack, name, response, status) {
893 + const dev = stack.dev;
894 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
895 + if (status != 200) { dev.consoleMsg("Failed to set boot settings data (" + status + ")."); return; }
896 + dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status) {
897 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
898 + if (status != 200) { dev.consoleMsg("Failed to set boot config role (" + status + ")."); return; }
899 + var bootSource = 'Force OCR UEFI HTTPS Boot';
900 + dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder((bootSource == null) ? bootSource : '<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: ' + bootSource + '</Selector></SelectorSet></ReferenceParameters>', function (stack, name, response, status) {
901 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
902 + if (status != 200) { dev.consoleMsg("Failed to set boot config (" + status + ")."); return; }
903 + dev.amtstack.RequestPowerStateChange(10, function (stack, name, response, status) { // 10 = Reset, 2 = Power Up
904 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
905 + if (status != 200) { dev.consoleMsg("Failed to perform power action (" + status + ")."); return; }
906 + console.log('One Click Recovery Completed.');
907 + });
908 + });
909 + }, 0, 1);
910 }
911
912 +
913 //
914 // Intel AMT Clock Syncronization
915 //
@@ -2255,6 +2308,12 @@ module.exports.CreateAmtManager = function (parent) {
2308 function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
2309 function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
2310
2311 + // Returns a UEFI boot parameter in binary
2312 + function makeUefiBootParam(type, data, len) {
2313 + 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); } }
2314 + return parent.common.ShortToStrX(0x8086) + parent.common.ShortToStrX(type) + parent.common.IntToStrX(data.length) + data;
2315 + }
2316 +
2317 function parseCertName(x) {
2318 var j, r = {}, xx = x.split(',');
2319 for (var i in xx) { j = xx[i].indexOf('='); r[xx[i].substring(0, j)] = xx[i].substring(j + 1); }