using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.IO; using System.Threading; using Microsoft.Win32.SafeHandles; using System.Security; using Common.Utils; namespace Intel.Management.Mei { [ComVisible(false)] public class HECIClass { private SafeFileHandle _handle; private uint _maxLen;//buffer size for requests private string _version; // detected version private byte _protocol; // protocol Guid _infGuid; // interface GUID (null= HECI) //private string _fqdn;// internal class DeviceOverlapped : IDisposable { private IntPtr _ptr = IntPtr.Zero; private int _InternalLow = 0; private int _InternalHigh = 0; private int _OffsetLow = 0; private int _OffsetHigh = 0; private int _EventHandle = 0; public DeviceOverlapped() { _ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeOverlapped))); _InternalLow = Marshal.OffsetOf(typeof(NativeOverlapped), "InternalLow").ToInt32(); _InternalHigh = Marshal.OffsetOf(typeof(NativeOverlapped), "InternalHigh").ToInt32(); _OffsetLow = Marshal.OffsetOf(typeof(NativeOverlapped), "OffsetLow").ToInt32(); _OffsetHigh = Marshal.OffsetOf(typeof(NativeOverlapped), "OffsetHigh").ToInt32(); _EventHandle = Marshal.OffsetOf(typeof(NativeOverlapped), "EventHandle").ToInt32(); } public IntPtr InternalLow { get { return Marshal.ReadIntPtr(_ptr, _InternalLow); } set { Marshal.WriteIntPtr(_ptr, _InternalLow, value); } } public IntPtr InternalHigh { get { return Marshal.ReadIntPtr(_ptr, _InternalHigh); } set { Marshal.WriteIntPtr(_ptr, _InternalHigh, value); } } public int OffsetLow { get { return Marshal.ReadInt32(_ptr, _OffsetLow); } set { Marshal.WriteInt32(_ptr, _OffsetLow, value); } } public int OffsetHigh { get { return Marshal.ReadInt32(_ptr, _OffsetHigh); } set { Marshal.WriteInt32(_ptr, _OffsetHigh, value); } } public IntPtr EventHandle { get { return Marshal.ReadIntPtr(_ptr, _EventHandle); } set { Marshal.WriteIntPtr(_ptr, _EventHandle, value); } } public IntPtr ToPointer() { return _ptr; } public void Reset(IntPtr hEventOverlapped) { EventHandle = hEventOverlapped; InternalLow = IntPtr.Zero; InternalHigh = IntPtr.Zero; OffsetLow = 0; OffsetHigh = 0; } public void Close() { if (_ptr != IntPtr.Zero) { Marshal.FreeHGlobal(_ptr); _ptr = IntPtr.Zero; } } #region IDisposable Members private bool _disposed = false; protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { } Close(); _disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~DeviceOverlapped() { Dispose(false); } #endregion } public class MeiException : Exception { public MeiException(string message) : base(message) { } public MeiException(string message, Exception inner) : base(message, inner) { } } public class DriverNotFoundException : MeiException { public DriverNotFoundException(string message) : base(message) { } public DriverNotFoundException(string message, Exception inner) : base(message, inner) { } } public class UnauthorizedException : MeiException { public UnauthorizedException(string message) : base(message) { } public UnauthorizedException(string message, Exception inner) : base(message, inner) { } } public class StatusException : MeiException { public StatusException(UInt32 status) : base("AmtStatus " + status.ToString()) { } } public HECIClass() { _handle = null; } public static Guid HECIGuid { get { return new Guid("12F80028-B4B7-4B2D-ACA8-46E0FF65814C"); } } public static Guid WatchDogGuid { get { return new Guid("05B79A6F-4628-4D7F-899D-A91514CB32AB"); } } public void Init() { Init(HECIGuid); } public void Init(Guid guid) { Guid devGuid = new Guid("E2D1FF34-3458-49A9-88DA-8E6915CE9BE5"); const int DIGCF_PRESENT = 0x02; const int DIGCF_DEVICEINTERFACE = 0x10; IntPtr hDevInfo = SetupDiGetClassDevs(ref devGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (hDevInfo.Equals((IntPtr)(-1))) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); SP_DEVICE_INTERFACE_DATA spdata = new SP_DEVICE_INTERFACE_DATA(); SP_DEVICE_INTERFACE_DETAIL_DATA spDetail = new SP_DEVICE_INTERFACE_DETAIL_DATA(); SP_DEVINFO_DATA spInfo = new SP_DEVINFO_DATA(); spInfo.cbSize = (uint)Marshal.SizeOf(spInfo); spdata.cbSize = (uint)Marshal.SizeOf(spdata); if (IntPtr.Size == 8) // for 64 bit operating systems spDetail.cbSize = 8; else spDetail.cbSize = 4 + (uint)Marshal.SystemDefaultCharSize; // for 32 bit systems uint bufferSize = 0; UInt32 index = 0; bool bOk = false; while (SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref devGuid, index++, ref spdata)) { bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo, ref spdata, ref spDetail, (uint)System.Runtime.InteropServices.Marshal.SizeOf(spDetail), out bufferSize, ref spInfo); } if (!bOk) new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); SetupDiDestroyDeviceInfoList(hDevInfo); // flags for create File const uint GENERIC_READ = 0x80000000; const uint GENERIC_WRITE = 0x40000000; const uint FILE_SHARE_READ = 0x00000001; const uint FILE_SHARE_WRITE = 0x00000002; const uint OPEN_EXISTING = 3; const uint FILE_FLAG_OVERLAPPED = 0x40000000; _handle = CreateFile(spDetail.DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero); if (_handle.IsInvalid) { int errorCode = Marshal.GetLastWin32Error(); _handle = null; if (errorCode == 5) throw new UnauthorizedAccessException(); throw new FileNotFoundException("Unable to open HECI Device", spDetail.DevicePath, new System.ComponentModel.Win32Exception(errorCode)); } //get version int size = Marshal.SizeOf(typeof(HECI_VERSION)); HECI_VERSION heciVer = new HECI_VERSION(); IntPtr outPtr = SendIOControl(2147540992, null, 0, heciVer, size); if (!outPtr.Equals(IntPtr.Zero)) { heciVer = (HECI_VERSION)Marshal.PtrToStructure(outPtr, typeof(HECI_VERSION)); Marshal.FreeCoTaskMem(outPtr); StringBuilder builder = new StringBuilder(); builder.Append(heciVer.major.ToString()); builder.Append("."); builder.Append(heciVer.minor.ToString()); builder.Append("."); builder.Append(heciVer.hotfix.ToString()); builder.Append("."); builder.Append(heciVer.build.ToString()); _version = builder.ToString(); } size = Marshal.SizeOf(typeof(HECI_CLIENT)); HECI_CLIENT heciClt = new HECI_CLIENT(); //connect to heci //guid = new Guid("12F80028-B4B7-4B2D-ACA8-46E0FF65814C"); byte[] guidData = guid.ToByteArray(); outPtr = SendIOControl(2147540996, guidData, guidData.Length, heciClt, size); if (!outPtr.Equals(IntPtr.Zero)) { heciClt = (HECI_CLIENT)Marshal.PtrToStructure(outPtr, typeof(HECI_CLIENT)); Marshal.FreeCoTaskMem(outPtr); _maxLen = heciClt.MaxMessageLength; _protocol = heciClt.ProtocolVersion; } } public void DeInit() { if (_handle != null) _handle.Close(); } public bool GetLocalAdminCredentials(out string userName, out SecureString password) { userName = string.Empty; password = new SecureString(); CFG_GET_LOCAL_SYSTEM_ACCOUNT_REQUEST input = new CFG_GET_LOCAL_SYSTEM_ACCOUNT_REQUEST(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108967; input.Length = 40; int inSize = Marshal.SizeOf(typeof(CFG_GET_LOCAL_SYSTEM_ACCOUNT_REQUEST)); IntPtr outPtr = SendMessage(input, inSize); if (outPtr.Equals(IntPtr.Zero)) return false; CFG_GET_LOCAL_SYSETM_ACCOUNT_RESPONSE output; output = (CFG_GET_LOCAL_SYSETM_ACCOUNT_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(CFG_GET_LOCAL_SYSETM_ACCOUNT_RESPONSE)); userName = output.UserName; password.Dispose(); password = output.Password; Marshal.FreeCoTaskMem(outPtr); return true; } public bool GetProvisioningState(out ProvisioningState state) { state = ProvisioningState.In; bool result = false; //0x04000011 // GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108881; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_PROVISIONING_STATE_RESPONSE)); GET_PROVISIONING_STATE_RESPONSE output; output = (GET_PROVISIONING_STATE_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_PROVISIONING_STATE_RESPONSE)); if (output.AmtStatus == 0) { result = true; state = output.State; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetProvisioningMode(out ProvisioningMode mode) { bool result = false; mode = ProvisioningMode.None; //0x04000011 // GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108872; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_PROVISIONING_MODE_RESPONSE)); GET_PROVISIONING_MODE_RESPONSE output; output = (GET_PROVISIONING_MODE_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_PROVISIONING_MODE_RESPONSE)); if (output.AmtStatus == 0) { result = true; mode = output.Mode; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool QueryStateIndependence() { bool isEnabled = false; STATE_INDEPENDENCE_COMMAND input = new STATE_INDEPENDENCE_COMMAND(); input.Cmd = 5; input.ByteCount = 2; input.SubCmd = 81; input.Version = 16; int inSize = Marshal.SizeOf(typeof(STATE_INDEPENDENCE_COMMAND)); IntPtr outPtr = SendMessage(input, inSize); if (outPtr.Equals(IntPtr.Zero)) return false; STATE_INDEPENDENCE_RESPONSE output; output = (STATE_INDEPENDENCE_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(STATE_INDEPENDENCE_RESPONSE)); isEnabled = output.Status != 0; Marshal.FreeCoTaskMem(outPtr); return isEnabled; } public bool EnableStateIndependence() { bool isEnabled = false; STATE_INDEPENDENCE_COMMAND input = new STATE_INDEPENDENCE_COMMAND(); input.Cmd = 5; input.ByteCount = 2; input.SubCmd = 82; input.Version = 16; int inSize = Marshal.SizeOf(typeof(STATE_INDEPENDENCE_COMMAND)); IntPtr outPtr = SendMessage(input, inSize); if (outPtr.Equals(IntPtr.Zero)) return false; STATE_INDEPENDENCE_RESPONSE output; output = (STATE_INDEPENDENCE_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(STATE_INDEPENDENCE_RESPONSE)); isEnabled = output.Status == 0; //158 means Transition to Intel AMT is not currenlty allowed Marshal.FreeCoTaskMem(outPtr); return isEnabled; } public bool StartConfiguration() { bool result = false; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108905; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_HECI_RESPONSE)); GET_HECI_RESPONSE output; output = (GET_HECI_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_HECI_RESPONSE)); if (output.AmtStatus == 0) { result = true; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool StartConfigurationEx(bool enableIpv6) { bool result = false; CFG_START_CONFIGURATION_EX_REQUEST input = new CFG_START_CONFIGURATION_EX_REQUEST(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108962;//04000062 input.Length = sizeof(uint); if (enableIpv6) input.Ipv6Enable = 1; else input.Ipv6Enable = 0; int inSize = Marshal.SizeOf(typeof(CFG_START_CONFIGURATION_EX_REQUEST)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_HECI_RESPONSE)); GET_HECI_RESPONSE output; output = (GET_HECI_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_HECI_RESPONSE)); if (output.AmtStatus == 0) { result = true; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool SetOTP(SecureString password) { bool result = false; byte[] ansiData = password.ConvertToByteArray(); if (ansiData == null) return result; CFG_SET_PROVISIONING_SERVER_OTP_REQUEST input = new CFG_SET_PROVISIONING_SERVER_OTP_REQUEST(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108906;//400002A input.Length = sizeof(ushort) + (uint)ansiData.Length; try { input.PasswordLength = (ushort)ansiData.Length;//Conversion from int to ushort } catch (System.OverflowException e) { throw new System.OverflowException(e.ToString()); } int inSize = Marshal.SizeOf(typeof(CFG_SET_PROVISIONING_SERVER_OTP_REQUEST)) + ansiData.Length; IntPtr outPtr = IntPtr.Zero; IntPtr inPtr = Marshal.AllocCoTaskMem(inSize); try { IntPtr offSetPtr = new IntPtr(inPtr.ToInt64() + Marshal.SizeOf(typeof(CFG_SET_PROVISIONING_SERVER_OTP_REQUEST))); Marshal.StructureToPtr(input, inPtr, true); //copy ansi data Marshal.Copy(ansiData, 0, offSetPtr, ansiData.Length); // byte[] data = new byte[8]; //Marshal.Copy(inPtr, data, Marshal.SizeOf(typeof(CFG_SET_PROVISIONING_SERVER_OTP_REQUEST)), data.Length); outPtr = SendMessage(inPtr, inSize); } finally { Marshal.FreeCoTaskMem(inPtr); Array.Clear(ansiData, 0, ansiData.Length); } if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_HECI_RESPONSE)); GET_HECI_RESPONSE output; output = (GET_HECI_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_HECI_RESPONSE)); if (output.AmtStatus == 0) { result = true; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetRngSeedStatus(out RngSeedStatus status) { bool result = false; status = RngSeedStatus.Exists; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108904; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_RNG_SEED_STATUS_RESPONSE)); GET_RNG_SEED_STATUS_RESPONSE output; output = (GET_RNG_SEED_STATUS_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_RNG_SEED_STATUS_RESPONSE)); if (output.AmtStatus == 0) { result = (int)output.RngStatus > 0 && (int)output.RngStatus < 3; status = output.RngStatus; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetZeroTouchEnabled(out bool enabled) { bool result = false; enabled = false; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108912; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_ZERO_TOUCH_ENABLED_RESPONSE)); GET_ZERO_TOUCH_ENABLED_RESPONSE output; output = (GET_ZERO_TOUCH_ENABLED_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_ZERO_TOUCH_ENABLED_RESPONSE)); if (output.AmtStatus == 0) { result = true; enabled = output.TlsEnabled != 0; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetTlsMode(out TlsMode mode) { bool result = false; mode = TlsMode.NotReady; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108907; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_PROVISIONING_TLS_MODE_RESPONSE)); GET_PROVISIONING_TLS_MODE_RESPONSE output; output = (GET_PROVISIONING_TLS_MODE_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_PROVISIONING_TLS_MODE_RESPONSE)); if (output.AmtStatus == 0) { result = true; mode = output.TlsMode; } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetConfigServer(out string fqdn) { bool result = false; fqdn = string.Empty; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108915; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_CONF_SERVER_FQDN_RESPONSE)); GET_CONF_SERVER_FQDN_RESPONSE output; output = (GET_CONF_SERVER_FQDN_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_CONF_SERVER_FQDN_RESPONSE)); if (output.AmtStatus == 0) { result = true; byte[] data = new byte[outSize + output.NameLength]; Marshal.Copy(outPtr, data, 0, data.Length); fqdn = Encoding.ASCII.GetString(data, outSize, output.NameLength); } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetDnsSuffix(out string suffix) { bool result = false; suffix = string.Empty; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108918; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_CONF_SERVER_FQDN_RESPONSE)); GET_CONF_SERVER_FQDN_RESPONSE output; output = (GET_CONF_SERVER_FQDN_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_CONF_SERVER_FQDN_RESPONSE)); if (output.AmtStatus == 0) { result = true; byte[] data = new byte[outSize + output.NameLength]; Marshal.Copy(outPtr, data, 0, data.Length); suffix = Encoding.ASCII.GetString(data, outSize, output.NameLength); } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetAuditRecord(out AuditRecord record) { bool result = false; record = null; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108903; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_AUDIT_RECORD_RESPONSE)); GET_AUDIT_RECORD_RESPONSE output; output = (GET_AUDIT_RECORD_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_AUDIT_RECORD_RESPONSE)); if (output.AmtStatus == 0) { result = true; DateTime timestamp = new DateTime((int)output.Year, (int)output.Month, (int)output.Day, (int)output.Hour, (int)output.Minute, (int)output.Second); byte[] data = new byte[outSize + output.NameLength]; Marshal.Copy(outPtr, data, 0, data.Length); string suffix = Encoding.ASCII.GetString(data, outSize, output.NameLength); record = new AuditRecord(timestamp, suffix, output.ProvServerIP, output.IsOemDefault, output.SelectedHashData, output.SelectedHashType, output.IsTimeValid, output.AdditionalCaSerialNums, output.CaCertificateSerials); } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetCertHashes(out HashEntry[] hashes) { bool result = false; hashes = null; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108908; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_HASH_HANDLES_RESPONSE)); GET_HASH_HANDLES_RESPONSE output; output = (GET_HASH_HANDLES_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_HASH_HANDLES_RESPONSE)); if (output.AmtStatus == 0) { result = true; int offset = outSize; hashes = new HashEntry[output.HashHandleCount]; for (int i = 0; hashes != null && i < output.HashHandleCount; i++) { UInt32 hashHandle = (UInt32)Marshal.ReadInt32(outPtr, offset); offset += sizeof(UInt32); hashes[i] = GetHashEntry(hashHandle); if (hashes[i] == null) { hashes = null; result = false; } } } Marshal.FreeCoTaskMem(outPtr); } return result; } public bool GetCodeVersions(out string bios, out AMT_VERSION_TYPE[] versions) { List verList = new List(); versions = verList.ToArray(); bios = string.Empty; bool result = false; GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108890; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(CFG_GET_CODE_VERSIONS_RESPONSE)); CFG_GET_CODE_VERSIONS_RESPONSE output; output = (CFG_GET_CODE_VERSIONS_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(CFG_GET_CODE_VERSIONS_RESPONSE)); int eltSize = Marshal.SizeOf(typeof(AMT_VERSION_TYPE)); IntPtr inPtr = Marshal.AllocCoTaskMem(eltSize); for (int i = 0; i < output.VersionCount; i++) { for (int k = 0; k < eltSize; k++) { Marshal.WriteByte(inPtr, k, Marshal.ReadByte(outPtr, outSize + (i * eltSize) + k)); } verList.Add((AMT_VERSION_TYPE) Marshal.PtrToStructure(inPtr, typeof(AMT_VERSION_TYPE))); } Marshal.FreeCoTaskMem(inPtr); versions = verList.ToArray(); bios = output.BiosVersion; result = output.AmtStatus == 0; Marshal.FreeCoTaskMem(outPtr); } return result; } public bool UnProvision() { CFG_UNPROVISION_REQUEST input = new CFG_UNPROVISION_REQUEST(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108880; input.Length = sizeof(uint); input.Mode = 0; int inSize = Marshal.SizeOf(typeof(CFG_UNPROVISION_REQUEST)); IntPtr outPtr = SendMessage(input, inSize); if (outPtr.Equals(IntPtr.Zero)) return false; CFG_UNPROVISION_RESPONSE output; output = (CFG_UNPROVISION_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(CFG_UNPROVISION_RESPONSE)); Marshal.FreeCoTaskMem(outPtr); return output.AmtStatus == 0; } public bool OpenUserInitiatedConnection() { GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108932; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (outPtr.Equals(IntPtr.Zero)) return false; GET_HECI_RESPONSE output; output = (GET_HECI_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_HECI_RESPONSE)); Marshal.FreeCoTaskMem(outPtr); return output.AmtStatus == 0; } public bool CloseUserInitiatedConnection() { GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108933; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (outPtr.Equals(IntPtr.Zero)) return false; GET_HECI_RESPONSE output; output = (GET_HECI_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_HECI_RESPONSE)); Marshal.FreeCoTaskMem(outPtr); return output.AmtStatus == 0; } public bool StopConfiguration() { GET_COMMAND_HEADER input = new GET_COMMAND_HEADER(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 75497566; input.Length = 0; int inSize = Marshal.SizeOf(typeof(GET_COMMAND_HEADER)); IntPtr outPtr = SendMessage(input, inSize); if (outPtr.Equals(IntPtr.Zero)) return false; GET_HECI_RESPONSE output; output = (GET_HECI_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_HECI_RESPONSE)); Marshal.FreeCoTaskMem(outPtr); return output.AmtStatus == 0; } private HashEntry GetHashEntry(UInt32 handle) { HashEntry result = null; GET_CERTHASH_ENTRY_REQUEST input = new GET_CERTHASH_ENTRY_REQUEST(); input.MajorNumber = 1; input.MinorNumber = 1; input.Command = 67108909; input.Length = sizeof(UInt32); input.HashHandle = handle; int inSize = Marshal.SizeOf(typeof(GET_CERTHASH_ENTRY_REQUEST)); IntPtr outPtr = SendMessage(input, inSize); if (!outPtr.Equals(IntPtr.Zero)) { int outSize = Marshal.SizeOf(typeof(GET_CERTHASH_ENTRY_RESPONSE)); GET_CERTHASH_ENTRY_RESPONSE output; output = (GET_CERTHASH_ENTRY_RESPONSE)Marshal.PtrToStructure(outPtr, typeof(GET_CERTHASH_ENTRY_RESPONSE)); if (output.AmtStatus == 0) { byte[] data = new byte[outSize + output.NameLength]; Marshal.Copy(outPtr, data, 0, data.Length); string name = Encoding.ASCII.GetString(data, outSize, output.NameLength); result = new HashEntry(output.IsActive != 0, output.IsDefault != 0, output.HashAlgorithm, output.CertificateHash, name, handle); } Marshal.FreeCoTaskMem(outPtr); } return result; } private IntPtr SendMessage(object input, int inSize) { uint bytesRead; IntPtr inPtr = IntPtr.Zero; if (!(input is IntPtr)) { inPtr = Marshal.AllocCoTaskMem(inSize); Marshal.StructureToPtr(input, inPtr, true); } else { inPtr = (IntPtr)input; } DeviceOverlapped deviceIoOverlapped; ManualResetEvent waitEvent; using (deviceIoOverlapped = new DeviceOverlapped()) { using (waitEvent = new ManualResetEvent(false)) { deviceIoOverlapped.Reset(waitEvent.SafeWaitHandle.DangerousGetHandle()); bool bOk = WriteFile(_handle, inPtr, (uint)inSize, out bytesRead, deviceIoOverlapped.ToPointer()); //997 means wait int err = Marshal.GetLastWin32Error(); if (bOk == false && err == ERROR_IO_PENDING) { waitEvent.WaitOne(); bOk = GetOverlappedResult(_handle, deviceIoOverlapped.ToPointer(), out bytesRead, true); err = Marshal.GetLastWin32Error(); } if (!(input is IntPtr)) Marshal.FreeCoTaskMem(inPtr); inPtr = IntPtr.Zero; deviceIoOverlapped.Close(); waitEvent.Close(); using (deviceIoOverlapped = new DeviceOverlapped()) { using (waitEvent = new ManualResetEvent(false)) { deviceIoOverlapped.Reset(waitEvent.SafeWaitHandle.DangerousGetHandle()); inPtr = Marshal.AllocCoTaskMem((int)_maxLen); if (bOk) { bOk = ReadFile(_handle, inPtr, _maxLen, ref bytesRead, deviceIoOverlapped.ToPointer()); err = Marshal.GetLastWin32Error(); } if (bOk == false && err == ERROR_IO_PENDING) { waitEvent.WaitOne(); bOk = GetOverlappedResult(_handle, deviceIoOverlapped.ToPointer(), out bytesRead, true); err = Marshal.GetLastWin32Error(); } } } // don't bother returning empty response if (bOk == false || (bOk && bytesRead == 0)) { Marshal.FreeCoTaskMem(inPtr); inPtr = IntPtr.Zero; } } } return inPtr; } private IntPtr SendIOControl(uint code, object input, int inSize, object output, int outSize) { uint bytesRead; IntPtr outPtr = IntPtr.Zero; IntPtr inPtr = IntPtr.Zero; if (output != null) { outPtr = Marshal.AllocCoTaskMem(outSize); Marshal.StructureToPtr(output, outPtr, false); } if (input != null) { inPtr = Marshal.AllocCoTaskMem(inSize); if (input.GetType().IsArray) { Marshal.Copy((byte[])input, 0, inPtr, inSize); } else { Marshal.StructureToPtr(input, inPtr, false); } } using (DeviceOverlapped deviceIoOverlapped = new DeviceOverlapped()) { using (ManualResetEvent waitEvent = new ManualResetEvent(false)) { deviceIoOverlapped.Reset(waitEvent.SafeWaitHandle.DangerousGetHandle()); bool bOk = DeviceIoControl(_handle, code, inPtr, (uint)inSize, outPtr, (uint)outSize, out bytesRead, deviceIoOverlapped.ToPointer()); int err = Marshal.GetLastWin32Error(); if (bOk == false && err == ERROR_IO_PENDING) { waitEvent.WaitOne(); bOk = GetOverlappedResult(_handle, deviceIoOverlapped.ToPointer() , out bytesRead, true); } if (!inPtr.Equals(IntPtr.Zero)) Marshal.FreeCoTaskMem(inPtr); if (!bOk) { Marshal.FreeCoTaskMem(outPtr); outPtr = IntPtr.Zero; } } } return outPtr; } static readonly int ERROR_IO_PENDING = 997; [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct STATE_INDEPENDENCE_COMMAND { public byte Cmd; public byte ByteCount; public byte SubCmd; public byte Version; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct STATE_INDEPENDENCE_RESPONSE { public uint Status; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct HECI_VERSION { public byte major; public byte minor; public byte hotfix; public short build; } [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] public struct AMT_UNICODE_STRING { public UInt16 Length; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] public string Text; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct AMT_VERSION_TYPE { public AMT_UNICODE_STRING Description; public AMT_UNICODE_STRING Version; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct GET_COMMAND_HEADER { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; } [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] private struct CFG_GET_CODE_VERSIONS_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string BiosVersion; public UInt32 VersionCount; } public enum ProvisioningMode { None = 0, Enterprise = 1, SmallBusiness = 2 } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct GET_PROVISIONING_MODE_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public UInt32 Legacy; public ProvisioningMode Mode; } public enum ProvisioningState { Pre = 0, In = 1, Post = 2 } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct GET_PROVISIONING_STATE_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public ProvisioningState State; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct CFG_SET_PROVISIONING_SERVER_OTP_REQUEST { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public ushort PasswordLength; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct CFG_START_CONFIGURATION_EX_REQUEST { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 Ipv6Enable; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct CFG_UNPROVISION_REQUEST { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 Mode; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct CFG_UNPROVISION_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct CFG_GET_LOCAL_SYSTEM_ACCOUNT_REQUEST { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] public byte[] Reserved2; } [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] private struct CFG_GET_LOCAL_SYSETM_ACCOUNT_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string UserName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public SecureString Password; } public enum RngSeedStatus { Exists = 0, InProgress = 1, NotExists = 2 } [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] private struct GET_RNG_SEED_STATUS_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public RngSeedStatus RngStatus; }; [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] private struct GET_HASH_HANDLES_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public UInt32 HashHandleCount; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct GET_CERTHASH_ENTRY_REQUEST { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 HashHandle; } [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] private struct GET_CERTHASH_ENTRY_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public UInt32 IsDefault; public UInt32 IsActive; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] CertificateHash; public byte HashAlgorithm; public UInt16 NameLength; } public enum HashAlgorithm { MD5 = 0, SHA1 = 1, SHA256 = 2, SHA384 = 3, SHA512 = 4 } public class HashEntry { bool _isActive; bool _isDefault; HashAlgorithm _hashAlg; byte[] _hashData; string _name; UInt32 _handle; public HashEntry(bool isActive, bool isDefault, byte hashAlg, byte[] hash, string name, UInt32 handle) { _isActive = isActive; _isDefault = isDefault; _hashAlg = (HashAlgorithm)hashAlg; _name = name; _handle = handle; // copy hash based on size switch (_hashAlg) { case HashAlgorithm.MD5: _hashData = new byte[16]; break; case HashAlgorithm.SHA1: _hashData = new byte[20]; break; case HashAlgorithm.SHA256: _hashData = new byte[32]; break; case HashAlgorithm.SHA384: _hashData = new byte[48]; break; default: _hashData = new byte[64]; break; } Array.Copy(hash, _hashData, _hashData.Length); } public bool IsDefault { get { return _isDefault; } } public bool IsActive { get { return _isActive; } } public UInt32 Handle { get { return _handle; } } public string HashString { get { return Convert.ToBase64String(_hashData); } } public string Thumbprint { get { string result = BitConverter.ToString(_hashData); result = result.Replace("-", string.Empty); return result; } } public string Name { get { return _name; } } public byte[] HashData { get { return _hashData; } } } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct GET_ZERO_TOUCH_ENABLED_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public UInt32 TlsEnabled; } public enum TlsMode { NotReady = 0, PSK = 1, PKI = 2 } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct GET_PROVISIONING_TLS_MODE_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public TlsMode TlsMode; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct GET_CONF_SERVER_FQDN_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public UInt16 NameLength; } public class AuditRecord { string _domainSuffix; DateTime _timpstamp; bool _isDefault; bool _timeValid; bool _additionalCaNums; string _ipAddress; string _hash; string[] _caSerials; HashAlgorithm _hashAlg; public AuditRecord(DateTime timestamp, string suffix, uint ipAddress, uint isDefault, byte[] hash, HashAlgorithm selectedHashType, uint timeValid, uint additionalCaNums, byte[] caSerials) { _timpstamp = timestamp; _domainSuffix = suffix; System.Net.IPAddress add = new System.Net.IPAddress(ipAddress); _ipAddress = add.ToString(); _isDefault = !isDefault.Equals(0); byte[] hashValue = null; _hashAlg = selectedHashType; switch (selectedHashType) { case HashAlgorithm.MD5: hashValue = new byte[16]; break; case HashAlgorithm.SHA1: hashValue = new byte[20]; break; case HashAlgorithm.SHA256: hashValue = new byte[32]; break; case HashAlgorithm.SHA384: hashValue = new byte[48]; break; case HashAlgorithm.SHA512: hashValue = new byte[64]; break; default: hashValue = new byte[0]; break; } Array.Copy(hash, hashValue, hashValue.Length); _hash = BitConverter.ToString(hashValue); _hash = _hash.Replace("-", string.Empty); _hash = _hash.ToUpper(); _timeValid = !timeValid.Equals(0); _additionalCaNums = !additionalCaNums.Equals(0); _caSerials = new string[0]; } public string ProvServerFQDN { get { return _domainSuffix; } } public DateTime Timestamp { get { return _timpstamp; } } public string HashData { get { return _hash; } } public HashAlgorithm HashAlgorithm { get { return _hashAlg; } } public bool HashIsOemDefault { get { return _isDefault; } } public bool TimeValid { get { return _timeValid; } } public bool AdditionalCaSerialNums { get { return _additionalCaNums; } } public string[] CaCertificateSerials { get { return _caSerials; } } public string ProvServerIP { get { return _ipAddress; } } } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct GET_AUDIT_RECORD_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; public byte ProvisioningTLSMode; public UInt32 SecureDNS; public UInt32 HostInitiated; public HashAlgorithm SelectedHashType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] SelectedHashData; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] public byte[] CaCertificateSerials; public UInt32 AdditionalCaSerialNums; public UInt32 IsOemDefault; public UInt32 IsTimeValid; public UInt32 ProvServerIP; public UInt16 Year; public UInt16 Month; public UInt16 DayOfWeek; public UInt16 Day; public UInt16 Hour; public UInt16 Minute; public UInt16 Second; public UInt16 NameLength; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct GET_HECI_RESPONSE { public byte MajorNumber; public byte MinorNumber; public UInt16 Reserved; public UInt32 Command; public UInt32 Length; public UInt32 AmtStatus; } [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct HECI_CLIENT { public UInt32 MaxMessageLength; public byte ProtocolVersion; } [StructLayout(LayoutKind.Sequential)] struct SP_DEVINFO_DATA { public UInt32 cbSize; public Guid ClassGuid; public UInt32 DevInst; public IntPtr Reserved; } [StructLayout(LayoutKind.Sequential)] struct SP_DEVICE_INTERFACE_DATA { public uint cbSize; public Guid InterfaceClassGuid; public uint Flags; public IntPtr Reserved; } // Device interface detail data [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct SP_DEVICE_INTERFACE_DETAIL_DATA { public UInt32 cbSize; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string DevicePath; } [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern Boolean SetupDiGetDeviceInterfaceDetail( IntPtr hDevInfo, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, UInt32 deviceInterfaceDetailDataSize, out UInt32 requiredSize, ref SP_DEVINFO_DATA deviceInfoData ); [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern Boolean SetupDiEnumDeviceInterfaces( IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData ); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool CloseHandle(IntPtr hObject); [DllImport("setupapi.dll", CharSet = CharSet.Auto)] static extern IntPtr SetupDiGetClassDevs( ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, int Flags); [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool SetupDiDestroyDeviceInfoList(IntPtr hDevInfo); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern SafeFileHandle CreateFile( string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] static extern bool WriteFile(SafeFileHandle hFile, IntPtr lpBuffer, uint lpNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] static extern bool ReadFile(SafeFileHandle hFile, IntPtr lpBuffer, uint numBytesToRead, ref uint lpNumberOfBytesRead, IntPtr lpOverlapped); [DllImport("kernel32.dll", SetLastError = true)] static extern bool GetOverlappedResult(SafeHandle hFile, [In] IntPtr lpOverlapped, out uint lpNumberOfBytesTransferred, bool bWait); } }