amt-setupbin-0.1.0.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /**
  2. * @description Intel(R) AMT Setup.bin Parser
  3. * @author Ylian Saint-Hilaire
  4. * @version v0.1.0
  5. */
  6. // Intel(R) AMT Setup.bin GUID's
  7. var AmtSetupBinSetupGuids = [
  8. "\xb5\x16\xfb\x71\x87\xcb\xf9\x4a\xb4\x41\xca\x7b\x38\x35\x78\xf9", // Version 1
  9. "\x96\xb2\x81\x58\xcf\x6b\x72\x4c\x8b\x91\xa1\x5e\x51\x2e\x99\xc4", // Version 2
  10. "\xa7\xf7\xf6\xc6\x89\xc4\xf6\x47\x93\xed\xe2\xe5\x02\x0d\xa5\x1d", // Version 3
  11. "\xaa\xa9\x34\x52\xe1\x29\xa9\x44\x8d\x4d\x08\x1c\x07\xb9\x63\x53" // Version 4
  12. ];
  13. // Notes about version 2 of setup.bin:
  14. // - Default "admin" must be followed by a new MEBx password
  15. // - ME_VARIABLE_IDENTIFIER_MANAGEABILITY_FEATURE_SELECTION may not appear after any CM settings
  16. // - CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERT_ADD must be preceded by setting CM_VARIABLE_IDENTIFIER_USER_DEFINED_CERTS_CONFIG to (TODO!)
  17. // General notes:
  18. // - Setup.bin should always start with "CurrentMEBx Pwd", "newMebx Pwd", "manageability selection" (if present).
  19. // Intel(R) AMT variable identifiers
  20. // Type: 0 = Binar Stringy, 1 = Char, 2 = Short, 3 = Int
  21. var AmtSetupBinVarIds =
  22. {
  23. 1: {
  24. 1: [0, "Current MEBx Password"],
  25. 2: [0, "New MEBx Password"],
  26. 3: [1, "Manageability Feature Selection"],
  27. 4: [1, "Firmware Local Update", // 0 = Disabled, 1 = Enabled, 2 = Password Protected
  28. { 0: "Disabled", 1: "Enabled", 2: "Password Protected" }],
  29. 5: [1, "Firmware Update Qualifier", // 0 = Always, 1 = Never, 2 = Restricted
  30. { 0: "Always", 1: "Never", 2: "Restricted" }],
  31. 6: [0, "Power Package"] // GUID Length (16 bytes), Intel AMT version 2.1, 3 and 4
  32. },
  33. 2: {
  34. 1: [0, "Provisioning Preshared Key ID (PID)"],
  35. 2: [0, "Provisioning Preshared Key (PPS)"],
  36. 3: [0, "PKI DNS Suffix"], // 255 bytes max length
  37. 4: [0, "Configuration Server FQDN"], // 255 bytes max length
  38. 5: [1, "Remote Configuration Enabled (RCFG)", // 0 = Off, 1 = On
  39. { 0: "Off", 1: "On" }],
  40. 6: [1, "Pre-Installed Certificates Enabled", // 0 = Off, 1 = On
  41. { 0: "Off", 1: "On" }],
  42. 7: [1, "User Defined Certificate Configuration", // 0 = Disabled, 1 = Enabled, 2 = Delete
  43. { 0: "Disabled", 1: "Enabled", 2: "Delete" }],
  44. 8: [0, "User Defined Certificate Addition"], // 1 byte hash algo, 20 to 48 bytes hash, 1 byte name length, up to 32 bytes friendly name, 1 = SHA1 (20 bytes), 2 = SHA256 (32 bytes), 3 = SHA384 (48 bytes). Algo 2 & 3 are for version 3 and up.
  45. 10: [1, "SOL/IDER Redirection Configuration"],
  46. 11: [0, "Hostname"], // 63 bytes max length
  47. 12: [0, "Domain Name"], // 255 bytes max length
  48. 13: [0, "DHCP"],
  49. 14: [1, "Secure Firmware Update (SFWU)", // 0 = Disabled, 1 = Enabled
  50. { 0: "Disabled", 1: "Enabled" }],
  51. 15: [0, "ITO"],
  52. 16: [1, "Provisioning Mode (PM)", // 1 = Enterprise, 2 = Small Buisness (SMB)
  53. { 0: "Enterprise", 1: "Small Buisness"}],
  54. 17: [0, "Provisioning Server Address"],
  55. 18: [2, "Provision Server Port Number (PSPO)"],
  56. 19: [0, "Static PV4 Parameters"],
  57. 20: [0, "VLAN"],
  58. 21: [0, "PASS Policy Flag"],
  59. 22: [0, "IPv6"], // Length is 204 bytes old format, 84 bytes new format, Version 3+ only
  60. 23: [1, "Shared/Dedicated FQDN", // 0 = Dedicated, 1 = Shared. This option is valid only if configuring the hostname as well
  61. { 0: "Dedicated", 1: "Shared" }],
  62. 24: [1, "Dynamic DNS Update", // 0 = Disabled, 1 = Enabled
  63. { 0: "Disabled", 1: "Enabled" }],
  64. 25: [1, "Remote Desktop (KVM) State", // 0 = Disabled, 1 = Enabled
  65. { 0: "Disabled", 1: "Enabled" }],
  66. 26: [1, "Opt-in User Consent Option", // 0 = Disabled, 1 = KVM, 0xFF = ALL
  67. { 0 : "Disabled", 1 : "KVM", 255 : "All" }],
  68. 27: [1, "Opt-in Remote IT Consent Policy", // 0 = Disabled, 1 = Enabled. Allows user consent to be configured remotely.
  69. { 0 : "Disabled", 1 : "Enabled"} ],
  70. 28: [1, "ME Provision Halt Active", // 0 = Stop, 1 = Start. The "ME provisioning Halt/Activate" command must appear in the file only after "PKIDNSSuffix", "ConfigServerFQDN" and "Provisioning Server Address"
  71. { 0 : "Stop", 1 : "Start"}],
  72. 29: [1, "Manual Setup and Configuration", // 0 = Automated, 1 = Manual
  73. { 0 : "Automated", 1 : "Manual"}],
  74. 30: [3, "Support Channel Identifier"], // 4 bytes length. Support channel identifier (valid values: 1-65535)
  75. 31: [0, "Support Channel Description"], // 60 bytes max. Friendly name used to describe the party representedby the support channel identifier.
  76. 32: [0, "Service Account Number"], // 32 bytes max. Unique string identifier given to the end user by the service provider.
  77. 33: [0, "Enrollement Passcode"], // 32 bytes max
  78. 34: [3, "Service Type"], // 4 bytes length. 1 = Reactive, 2 = Proactive, 4 = One Time Session
  79. 35: [0, "Service Provider Identifier"] // GUID Length (16 bytes)
  80. }
  81. }
  82. // Parse the Setup.bin file
  83. var AmtSetupBinCreate = function (version, flags) {
  84. var obj = {};
  85. obj.fileType = version;
  86. obj.recordChunkCount = 0;
  87. obj.recordHeaderByteCount = 0;
  88. obj.recordNumber = 0;
  89. obj.majorVersion = version;
  90. obj.minorVersion = 0;
  91. obj.flags = flags;
  92. obj.dataRecordsConsumed = 0;
  93. obj.dataRecordChunkCount = 0;
  94. obj.records = [];
  95. return obj;
  96. }
  97. // Parse the Setup.bin file
  98. var AmtSetupBinDecode = function (file) {
  99. // Format of the setup file header:
  100. // FileTypeUUID(16) - uniquely identifies the file type. This identifier will remain valid and constant across all versions of the file type.
  101. // RecordChunkCount(2) - indicates the number of 512-byte chunks occupied by this record, including all header, body, and reserved fields.
  102. // RecordHeaderBytes(2) - indicates the length of the record header in bytes.
  103. // RecordNumber(4) - uniquely identifies the record among all records in the file. The field contains a non-negative ordinal value. The value of this field is always zero in the Local Provisioning File Header Record.
  104. // MajorVersion(1) - identifies the major version of the file format specification. This is a positive integer that is greater than or equal to 1. The Major Version number is incremented to indicate that changes have been introduced that will cause code written against a lower Major Version number to fail.
  105. // MinorVersion(1) - identifies the minor version of the file format specification. This is an integer that is greater than or equal to 0. The Minor Version number is incremented to indicate that changes have been introduced that will not cause code written against the same Major Version and a lower Minor Version number to fail. The purpose of this behavior is to allow a single local provisioning file to be used for multiple generations of Intel® AMT platform.
  106. // DataRecordCount(4) - indicates the total number of data records written in the file when it was created.
  107. // DataRecordsConsumed(4) - is a counter value that begins at 0 and is incremented by 1 by each platform BIOS when it consumes a data record from the file. This value is used to determine the offset of the next data record in the file.
  108. // DataRecordChunkCount(2) - contains the number of 512-byte chunks in each data record. All data records are the same length.
  109. // ModuleList - contains a list of module identifiers. A module’s identifier appears in the list if and only if the data records contain entries for that module. Each module identifier is two bytes in length. The list is terminated by an identifier value of 0.
  110. var obj = {}, UUID = file.substring(0, 16);
  111. obj.fileType = 0;
  112. for (var i in AmtSetupBinSetupGuids) { if (UUID == AmtSetupBinSetupGuids[i]) obj.fileType = (+i + 1); }
  113. if (obj.fileType == 0) return; // Bad header
  114. obj.recordChunkCount = ReadShortX(file, 16);
  115. obj.recordHeaderByteCount = ReadShortX(file, 18);
  116. obj.recordNumber = ReadIntX(file, 20);
  117. obj.majorVersion = file.charCodeAt(24);
  118. obj.minorVersion = file.charCodeAt(25);
  119. obj.flags = ReadShortX(file, 26); // Flags: 1 = Do not consume records
  120. var dataRecordCount = ReadIntX(file, 28);
  121. obj.dataRecordsConsumed = ReadIntX(file, 32);
  122. obj.dataRecordChunkCount = ReadShortX(file, 36);
  123. obj.records = [];
  124. var ptr = 512;
  125. while (ptr + 512 <= file.length) {
  126. // Format of a data record header:
  127. // RecordTypeIdentifier(4) - identifies the type of record (in this case a data record). Record Identifiers: Invalid - 0, Data Record - 1
  128. // RecordFlags(4) - contains a set of bit flags that characterize the record.
  129. // RecordChunkCount(2) - contains the number of 512-byte chunks occupied by the record including all header, body, and reserved fields.
  130. // RecordHeaderByteCount(2) - indicates the length of the record header in bytes.
  131. // RecordNumber(4) - uniquely identifies the record among all records in the file, including invalid as well as valid records. The identifier is a non-negative integer.
  132. var r = {};
  133. r.typeIdentifier = ReadIntX(file, ptr);
  134. r.flags = ReadIntX(file, ptr + 4); // Flags: 1 = Valid, 2 = Scrambled
  135. r.chunkCount = ReadShortX(file, ptr + 8);
  136. r.headerByteCount = ReadShortX(file, ptr + 10);
  137. r.number = ReadIntX(file, ptr + 12);
  138. r.variables = [];
  139. var ptr2 = 0, recbin = file.substring(ptr + 24, ptr + 512);
  140. if ((r.flags & 2) != 0) { recbin = AmtSetupBinDescrambleRecordData(recbin); } // De-Scramble the record
  141. while (true) {
  142. // Format of a data record entry:
  143. // ModuleIdentifier(2) - identifies the target ME module for the entry.
  144. // VariableIdentifier(2) - an enumeration value that identifies the variable. Variable identifiers are unique to each ModuleIdentifier.
  145. // VariableLength(2) - is the length of the variable value in bytes.
  146. // VariableValue - is the value to be assigned to the variable.
  147. var v = {};
  148. v.moduleid = ReadShortX(recbin, ptr2);
  149. v.varid = ReadShortX(recbin, ptr2 + 2);
  150. if (v.moduleid == 0 || v.varid == 0) break;
  151. if (AmtSetupBinVarIds[v.moduleid][v.varid]) {
  152. v.length = ReadShortX(recbin, ptr2 + 4);
  153. v.type = AmtSetupBinVarIds[v.moduleid][v.varid][0];
  154. v.desc = AmtSetupBinVarIds[v.moduleid][v.varid][1];
  155. v.value = recbin.substring(ptr2 + 8, ptr2 + 8 + v.length);
  156. if (v.type == 1 && v.length == 1) v.value = v.value.charCodeAt(0);
  157. else if (v.type == 2 && v.length == 2) v.value = ReadShortX(v.value, 0);
  158. else if (v.type == 3 && v.length == 4) v.value = ReadIntX(v.value, 0);
  159. r.variables.push(v);
  160. }
  161. ptr2 += (8 + (Math.floor((v.length + 3) / 4) * 4));
  162. }
  163. // Sort the variables
  164. r.variables.sort(AmtSetupBinVariableCompare);
  165. obj.records.push(r);
  166. ptr += 512;
  167. }
  168. if (dataRecordCount != obj.records.length) return; // Mismatch record count
  169. return obj;
  170. }
  171. // Construct a Setup.bin file
  172. var AmtSetupBinEncode = function (obj) {
  173. if (obj.fileType < 1 && obj.fileType > AmtSetupBinSetupGuids.length) return null;
  174. var out = [], r = AmtSetupBinSetupGuids[obj.fileType - 1], reccount = 0;
  175. r += ShortToStrX(obj.recordChunkCount);
  176. r += ShortToStrX(obj.recordHeaderByteCount);
  177. r += IntToStrX(obj.recordNumber);
  178. r += String.fromCharCode(obj.majorVersion, obj.minorVersion);
  179. r += ShortToStrX(obj.flags); // Flags: 1 = Do not consume records
  180. r += IntToStrX(obj.records.length);
  181. r += IntToStrX(obj.dataRecordsConsumed);
  182. r += ShortToStrX(obj.dataRecordChunkCount);
  183. while (r.length < 512) { r += "\0"; } // Pad the header
  184. out.push(r);
  185. // Write each record
  186. for (var i in obj.records) {
  187. var r2 = "", rec = obj.records[i];
  188. r2 += IntToStrX(rec.typeIdentifier);
  189. r2 += IntToStrX(rec.flags);
  190. r2 += IntToStrX(0); // Reserved
  191. r2 += IntToStrX(0); // Reserved
  192. r2 += ShortToStrX(1); // rec.chunkCount
  193. r2 += ShortToStrX(24); // rec.headerByteCount
  194. r2 += IntToStrX(++reccount);
  195. // Sort the variables
  196. rec.variables.sort(AmtSetupBinVariableCompare);
  197. /*
  198. // Change variable priority
  199. AmtSetupBinMoveToTop(r.variables, 1, 3); // Manageability Feature Selection
  200. AmtSetupBinMoveToTop(r.variables, 1, 2); // New MEBx password
  201. AmtSetupBinMoveToTop(r.variables, 1, 1); // Current MEBx password
  202. */
  203. // Write each variable
  204. for (var j in rec.variables) {
  205. var r3 = "", v = rec.variables[j], data = v.value;
  206. v.type = AmtSetupBinVarIds[v.moduleid][v.varid][0]; // Set the correct type if not alreay connect
  207. if (v.type > 0) { // If this is a numeric value, encode it correctly
  208. data = parseInt(data);
  209. if (v.type == 1) data = String.fromCharCode(data);
  210. if (v.type == 2) data = ShortToStrX(data);
  211. if (v.type == 3) data = IntToStrX(data);
  212. }
  213. r3 += ShortToStrX(v.moduleid); // Module Identifier
  214. r3 += ShortToStrX(v.varid); // Variable Identifier
  215. r3 += ShortToStrX(data.length); // Variable Length
  216. r3 += ShortToStrX(0); // Reserved
  217. r3 += data; // Variable Data
  218. while (r3.length % 4 != 0) { r3 += "\0"; } // Pad the variable
  219. r2 += r3;
  220. }
  221. while (r2.length < 512) { r2 += "\0"; } // Pad the record
  222. if ((rec.flags & 2) != 0) { r2 = r2.substring(0, 24) + AmtSetupBinScrambleRecordData(r2.substring(24)); } // Scramble the record starting at byte 24, after the header
  223. out.push(r2);
  224. }
  225. return out.join('');
  226. }
  227. // Used to sort variables
  228. function AmtSetupBinVariableCompare(a, b) {
  229. if (a.moduleid > b.moduleid) return 1;
  230. if (a.moduleid < b.moduleid) return -1;
  231. if (a.varid > b.varid) return 1;
  232. if (a.varid < b.varid) return -1;
  233. return 0;
  234. }
  235. // Scramble and un-scramble records
  236. function AmtSetupBinScrambleRecordData(data) { var out = ""; for (var i = 0; i < data.length; i++) { out += String.fromCharCode((data.charCodeAt(i) + 17) & 0xFF); } return out; }
  237. function AmtSetupBinDescrambleRecordData(data) { var out = ""; for (var i = 0; i < data.length; i++) { out += String.fromCharCode((data.charCodeAt(i) + 0xEF) & 0xFF); } return out; }
  238. // Find a moduleid/varid in the variable list, if found, move it to the top
  239. //function AmtSetupBinMoveToTop(variables, moduleid, varid) { var i = -1; for (var j in variables) { if ((variables[j].moduleid == moduleid) && (variables[j].varid == varid)) { i = j; } } if (i > 1) { ArrayElementMove(variables, i, 0); } }