From 2acb8453e882cae8675cfa2b66b588c95b2d2b64 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 15 May 2025 10:21:23 +0300 Subject: [PATCH 01/12] MeTee: CMake: consume four-part version Consume build number when it provided in version fourth field. Signed-off-by: Alexander Usyskin --- version.cmake | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/version.cmake b/version.cmake index f03d8ba..dfc4c12 100644 --- a/version.cmake +++ b/version.cmake @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2014-2024 Intel Corporation +# Copyright (C) 2014-2025 Intel Corporation file(READ VERSION VER_FILE) string(STRIP "${VER_FILE}" VER_FILE) @@ -7,7 +7,13 @@ string(REPLACE "." ";" VER_LIST ${VER_FILE}) list(GET VER_LIST 0 TEE_VERSION_MAJOR) list(GET VER_LIST 1 TEE_VERSION_MINOR) list(GET VER_LIST 2 TEE_VERSION_PATCH) +list(LENGTH VER_LIST VER_LIST_LEN) +if(VER_LIST_LEN EQUAL 4) + list(GET VER_LIST 3 TEE_VERSION_BUILD) +else() + set(TEE_VERSION_BUILD 0) +endif() set(TEE_VERSION_STRING - ${TEE_VERSION_MAJOR}.${TEE_VERSION_MINOR}.${TEE_VERSION_PATCH}) + ${TEE_VERSION_MAJOR}.${TEE_VERSION_MINOR}.${TEE_VERSION_PATCH}.${TEE_VERSION_BUILD}) set(TEE_VERSION_COMM - ${TEE_VERSION_MAJOR},${TEE_VERSION_MINOR},${TEE_VERSION_PATCH},0) \ No newline at end of file + ${TEE_VERSION_MAJOR},${TEE_VERSION_MINOR},${TEE_VERSION_PATCH},${TEE_VERSION_BUILD}) \ No newline at end of file From e8faa9d2b07cc957d43e0ac7c429da4e244b8132 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Mon, 26 May 2025 12:24:31 +0300 Subject: [PATCH 02/12] MeTee: Windows: fix copyright format Adhere to standard format. Signed-off-by: Alexander Usyskin --- src/Windows/metee.rc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Windows/metee.rc.in b/src/Windows/metee.rc.in index 630ca5d..3c23b8f 100644 --- a/src/Windows/metee.rc.in +++ b/src/Windows/metee.rc.in @@ -73,7 +73,7 @@ BEGIN VALUE "FileDescription", "Intel(R) CSME/GSC HECI Interface Library" VALUE "FileVersion", "@TEE_VERSION_STRING@" VALUE "InternalName", "MeTee" - VALUE "LegalCopyright", "Copyright (c) 2014-2024, Intel Corporation." + VALUE "LegalCopyright", "Copyright (C) 2014, Intel Corporation." VALUE "OriginalFilename", "metee.dll" VALUE "ProductName", "Intel(R) CSME/GSC HECI Interface Library" VALUE "ProductVersion", "@TEE_VERSION_STRING@" From 4677d0f51559788d549862335cbc0c2aa6e6b307 Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Sun, 11 May 2025 11:17:55 +0300 Subject: [PATCH 03/12] MeTee: pack(1) interface structs The struct sizes in the library interface are currently aligned according to the environment and compiler, which complicates calling library functions from managed environments. To address this issue, a breaking change has been introduced that explicitly specifies struct alignment. Signed-off-by: Abliyev, Reuven --- include/metee.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/metee.h b/include/metee.h index 49df6ef..e665588 100644 --- a/include/metee.h +++ b/include/metee.h @@ -94,6 +94,8 @@ enum tee_log_level { */ typedef void(*TeeLogCallback)(bool is_error, const char* fmt, ...); +#pragma pack(1) + /*! * Structure to store connection data */ @@ -148,6 +150,8 @@ struct tee_device_address { } data; }; +#pragma pack() + /** ZERO/NULL device handle */ #define TEEHANDLE_ZERO {0} From da56c19783899ba2f3667ffa3c11b03e66ab4e71 Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Wed, 7 May 2025 17:26:14 +0300 Subject: [PATCH 04/12] MeTee: Windows: C# Wrapper C# OOP wrapper Signed-off-by: Abliyev, Reuven --- CMakeLists.txt | 1 + bindings/CMakeLists.txt | 6 + bindings/csharp/AssemblyInfo.cs.in | 36 +++ bindings/csharp/CMakeLists.txt | 28 ++ bindings/csharp/Metee.cs | 473 +++++++++++++++++++++++++++++ 5 files changed, 544 insertions(+) create mode 100644 bindings/CMakeLists.txt create mode 100644 bindings/csharp/AssemblyInfo.cs.in create mode 100644 bindings/csharp/CMakeLists.txt create mode 100644 bindings/csharp/Metee.cs diff --git a/CMakeLists.txt b/CMakeLists.txt index 714478a..d57d0f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,7 @@ endif(UNIX) include(CPack) +add_subdirectory(bindings) if(BUILD_TEST) add_subdirectory(tests) endif(BUILD_TEST) diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt new file mode 100644 index 0000000..946771c --- /dev/null +++ b/bindings/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (C) 2025 Intel Corporation + +if(BUILD_SHARED_LIBS AND WIN32) + add_subdirectory(csharp) +endif(BUILD_SHARED_LIBS AND WIN32) \ No newline at end of file diff --git a/bindings/csharp/AssemblyInfo.cs.in b/bindings/csharp/AssemblyInfo.cs.in new file mode 100644 index 0000000..853accd --- /dev/null +++ b/bindings/csharp/AssemblyInfo.cs.in @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (C) 2025 Intel Corporation + */ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Intel.Security.Metee")] +[assembly: AssemblyDescription("Metee C# bindings")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Intel Corporation")] +[assembly: AssemblyProduct("Intel.Security.Metee")] +[assembly: AssemblyCopyright("Copyright (C) 2025 Intel Corporation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("62336647-651e-4c5a-a92a-fbda141e6c4e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("${TEE_VERSION_STRING}")] +[assembly: AssemblyFileVersion("${TEE_VERSION_STRING}")] diff --git a/bindings/csharp/CMakeLists.txt b/bindings/csharp/CMakeLists.txt new file mode 100644 index 0000000..415e5b4 --- /dev/null +++ b/bindings/csharp/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (C) 2025 Intel Corporation +cmake_minimum_required(VERSION 3.8) + +project(Intel.Security.Metee VERSION 0.1.0 LANGUAGES CSharp) + +include(CSharpUtilities) + +configure_file(AssemblyInfo.cs.in ${CMAKE_CURRENT_SOURCE_DIR}/Properties/AssemblyInfo.cs) + +add_library(Intel.Security.Metee + Metee.cs + Properties/AssemblyInfo.cs +) + +add_dependencies(Intel.Security.Metee metee) + +set_property(TARGET Intel.Security.Metee PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1") + +set_property(TARGET Intel.Security.Metee PROPERTY VS_DOTNET_REFERENCES + "System" + "System.Core" + "System.Data.DataSetExtensions" + "Microsoft.CSharp" + "System.Data" +) + +install(TARGETS Intel.Security.Metee RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) \ No newline at end of file diff --git a/bindings/csharp/Metee.cs b/bindings/csharp/Metee.cs new file mode 100644 index 0000000..9f6db21 --- /dev/null +++ b/bindings/csharp/Metee.cs @@ -0,0 +1,473 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (C) 2025 Intel Corporation + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Win32.SafeHandles; + +namespace Intel.Security +{ + public class MeteeException : Exception + { + public TeeStatus ErrorCode { get; } + + public enum TeeStatus + { + TeeSuccess = 0x0000, + TeeInternalError = 0x0001, + TeeDeviceNotFound = 0x0002, + TeeDeviceNotReady = 0x0003, + TeeInvalidParameter = 0x0004, + TeeUnableToCompleteOperation = 0x0005, + TeeTimeout = 0x0006, + TeeNotSupported = 0x0007, + TeeClientNotFound = 0x0008, + TeeBusy = 0x0009, + TeeDisconnected = 0x000A, + TeeInsufficientBuffer = 0x000B, + TeePermissionDenied = 0x000C + } + + public MeteeException(string message, int errorCode) : base(message) + { + ErrorCode = (TeeStatus)errorCode; + } + } + + public class Metee : IDisposable + { + + // Reference: https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern-using-a-custom-safe-handle + // Wraps the IntPtr allocated by Marshal.AllocHGlobal() into a SafeHandle. + class LocalAllocHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private LocalAllocHandle() : base(ownsHandle: true) { } + + // No need to implement a finalizer - SafeHandle's finalizer will call ReleaseHandle for you. + protected override bool ReleaseHandle() + { + Marshal.FreeHGlobal(handle); + return true; + } + + // Allocate bytes with Marshal.AllocHGlobal() and wrap the result into a SafeHandle. + public static LocalAllocHandle Allocate(int numberOfBytes) + { + IntPtr nativeHandle = Marshal.AllocHGlobal(numberOfBytes); + LocalAllocHandle safeHandle = new LocalAllocHandle(); + safeHandle.SetHandle(nativeHandle); + return safeHandle; + } + } + + private LocalAllocHandle _safeHandle = LocalAllocHandle.Allocate(Marshal.SizeOf()); + + #region DllImport + + private enum TeeDeviceType + { + None = 0, + Path = 1, + Guid = 3, + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct TeeDeviceAddress : IDisposable + { + + public TeeDeviceAddress(string devicePath) + { + DeviceType = TeeDeviceType.Path; + DataPtr = Marshal.StringToHGlobalAnsi(devicePath); + } + + public TeeDeviceAddress(Guid guid) + { + DeviceType = TeeDeviceType.Guid; + DataPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(guid, DataPtr, false); + } + + [MarshalAs(UnmanagedType.I4)] + public TeeDeviceType DeviceType; + + public IntPtr DataPtr; + + public void Dispose() + { + if (DataPtr != IntPtr.Zero) + Marshal.FreeHGlobal(DataPtr); + } + } + + // Struct should be big enough to hold the data + // without depending on the padding in the C struct + [StructLayout(LayoutKind.Sequential)] + private struct TeeHandle + { + private readonly IntPtr Field1; + private readonly IntPtr Field2; + private readonly IntPtr Field3; + private readonly IntPtr Field4; + private readonly IntPtr Field5; + } + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeInit(IntPtr handle, ref Guid guid, IntPtr device); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeInitFull(IntPtr handle, ref Guid guid, TeeDeviceAddress deviceAddress, [MarshalAs(UnmanagedType.U4)] TeeLogLevel logLevel, IntPtr logCallback); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeConnect(IntPtr handle); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeDisconnect(IntPtr handle); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeRead(IntPtr handle, byte[] buffer, int bufferSize, out int bytesRead, uint timeout); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeWrite(IntPtr handle, byte[] buffer, int bufferSize, out int bytesWritten, uint timeout); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeFWStatus(IntPtr handle, uint fwStatusNum, out uint fwStatus); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeGetTRC(IntPtr handle, out uint trc); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int TeeGetKind(IntPtr handle, StringBuilder kind, ref int kindSize); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint TeeSetLogLevel(IntPtr handle, uint logLevel); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint TeeGetLogLevel(IntPtr handle); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint TeeGetMaxMsgLen(IntPtr handle); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern uint TeeGetProtocolVer(IntPtr handle); + + [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern int GetDriverVersion(IntPtr handle, out TeeDriverVersion driverVersion); + + [StructLayout(LayoutKind.Sequential)] + private struct TeeDriverVersion + { + public readonly short Major; + public readonly short Minor; + public readonly short Hotfix; + public readonly short Build; + } + + #endregion + + public enum TeeLogLevel + { + Quiet = 0, // no log prints + Error = 1, // error log prints + Verbose = 2, // verbose log prints + } + + /** + * Use this constructor to query driver, without connecting to FW client. + */ + public Metee() + { + Guid zeroGuid = Guid.Empty; + int status = TeeInit(_safeHandle.DangerousGetHandle(), ref zeroGuid, IntPtr.Zero); + if (status != 0) + { + throw new MeteeException("Init failed", status); + } + FwStatus = new FwSts(this); + } + + /** + * Use this constructor to connect to default driver instance. + * Useful when only one instance of driver is present in the system. + * + * @param clientGuid - GUID of the FW client that want to start a session + * @param logLevel - log level to set + * @param logCallback - callback to be called on each log message + */ + public Metee(Guid clientGuid, TeeLogLevel logLevel = TeeLogLevel.Quiet, IntPtr logCallback = default) + { + var device = new TeeDeviceAddress { DeviceType = TeeDeviceType.None, DataPtr = IntPtr.Zero }; + + int status = TeeInitFull(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, logCallback); + if (status != 0) + { + throw new MeteeException("Init failed", status); + } + FwStatus = new FwSts(this); + } + + /** + * Use this constructor to connect to a specific driver instance. + * This is particularly useful when multiple driver instances are present in the system + * and you have the instance path. + * + * @param clientGuid - FW client GUID + * @param devicePath - Instance path + * @param logLevel - log level to set + * @param logCallback - callback to be called on each log message + */ + public Metee(Guid clientGuid, string devicePath, TeeLogLevel logLevel = TeeLogLevel.Quiet, IntPtr logCallback = default) + { + int status = 1; + using (var device = new TeeDeviceAddress(devicePath)) + { + status = TeeInitFull(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, logCallback); + } + if (status != 0) + { + throw new MeteeException("Init failed", status); + } + FwStatus = new FwSts(this); + } + + /** + * Use this constructor to connect to a specific driver instance. + * This is particularly useful when multiple driver instances are present in the system + * and you have the instance interface GUID. + * + * @param clientGuid - FW client GUID + * @param interfaceGuid - Instance interface GUID + * @param logLevel - log level to set + * @param logCallback - callback to be called on each log message + */ + public Metee(Guid clientGuid, Guid interfaceGuid, TeeLogLevel logLevel = TeeLogLevel.Quiet, IntPtr logCallback = default) + { + int status = 1; + using (var device = new TeeDeviceAddress(interfaceGuid)) + { + status = TeeInitFull(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, + logCallback); + } + if (status != 0) + { + throw new MeteeException("Init failed", status); + } + FwStatus = new FwSts(this); + } + + /** + * Connects to the TEE driver and starts a session + */ + public void Connect() + { + int status = TeeConnect(_safeHandle.DangerousGetHandle()); + if (status != 0) + { + throw new MeteeException("Connect failed", status); + } + } + + /** + * Read data from the TEE device synchronously. + * @param timeout - timeout in milliseconds + * @return - data read from the device + */ + public byte[] Read(uint timeout) + { + var maxMsgLen = GetMaxMsgLen(); + var buffer = new byte[maxMsgLen]; + + int status = TeeRead(_safeHandle.DangerousGetHandle(), buffer, buffer.Length, out var bytesRead, timeout); + if (status != 0) + { + throw new MeteeException("Read failed", status); + } + + Array.Resize(ref buffer, bytesRead); + return buffer; + } + + /** + * Write data to the TEE device synchronously. + * @param buffer - data to write + * @param timeout - timeout in milliseconds + * @return - number of bytes written + */ + public uint Write(byte[] buffer, uint timeout) + { + int status = TeeWrite(_safeHandle.DangerousGetHandle(), buffer, buffer.Length, out var bytesWritten, timeout); + if (status != 0) + { + throw new MeteeException("Write failed", status); + } + + return (uint)bytesWritten; + } + + #region Properties getters + + private uint GetFwStatus(RegIndex index) + { + int status = TeeFWStatus(_safeHandle.DangerousGetHandle(), (uint)index, out var fwStatus); + if (status != 0) + { + throw new MeteeException("FWStatus failed", status); + } + + return fwStatus; + } + private uint GetTrc() + { + int status = TeeGetTRC(_safeHandle.DangerousGetHandle(), out var trc); + if (status != 0) + { + throw new MeteeException("GetTRC failed", status); + } + + return trc; + } + + private string GetKind() + { + int kindSize = 32; + StringBuilder kind = new StringBuilder(kindSize); + + int status = TeeGetKind(_safeHandle.DangerousGetHandle(), kind, ref kindSize); + if (status != 0) + { + throw new MeteeException("TeeGetKind failed", status); + } + + return kind.ToString(); + } + + private uint SetLogLevel(uint logLevel) + { + return TeeSetLogLevel(_safeHandle.DangerousGetHandle(), logLevel); + } + + private uint GetLogLevel() + { + return TeeGetLogLevel(_safeHandle.DangerousGetHandle()); + } + + private uint GetMaxMsgLen() + { + return TeeGetMaxMsgLen(_safeHandle.DangerousGetHandle()); + } + + private uint GetProtocolVer() + { + return TeeGetProtocolVer(_safeHandle.DangerousGetHandle()); + } + + private string GetDriverVersion() + { + int status = GetDriverVersion(_safeHandle.DangerousGetHandle(), out var driverVersion); + if (status != 0) + { + throw new MeteeException("GetDriverVersion failed", status); + } + + return $"{driverVersion.Major}.{driverVersion.Minor}.{driverVersion.Hotfix}.{driverVersion.Build}"; + } + + #endregion + + /** + * Obtains kind of the TEE device + */ + public string Kind => GetKind(); + + /** + * Obtains version of the TEE device driver + */ + public string DriverVersion => GetDriverVersion(); + + /** + * Retrieve client protocol version + */ + public uint ProtocolVersion => GetProtocolVer(); + + /** + * Get/Set current log level + */ + public uint LogLevel + { + get => GetLogLevel(); + set => SetLogLevel(value); + } + /** + * Retrieve client maximum message length (MTU) + */ + public uint MaxMsgLen => GetMaxMsgLen(); + + /** + * Retrieves TRC register. + */ + public uint Trc => GetTrc(); + + public enum RegIndex + { + FwStatus1 = 0, + FwStatus2 = 1, + FwStatus3 = 2, + FwStatus4 = 3, + FwStatus5 = 4, + FwStatus6 = 5, + } + public class FwSts + { + private Metee _metee; + internal FwSts(Metee metee) + { + _metee = metee; + } + + public uint this[RegIndex index] => _metee.GetFwStatus(index); + } + + /** + * Retrieves specified FW status register. + */ + public FwSts FwStatus; + + #region IDisposable + + private bool _isDisposed = false; + + /** + * Public implementation of Dispose pattern callable by consumers. + */ + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /** + * Protected implementation of Dispose pattern. + */ + protected virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + _isDisposed = true; + + if (disposing) + { + if (_safeHandle != null) + { + TeeDisconnect(_safeHandle.DangerousGetHandle()); + _safeHandle?.Dispose(); + _safeHandle = null; + } + } + } + } + #endregion + } +} \ No newline at end of file From 3dbfbf750e3d559f95c419d737baba2771f0e244 Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Wed, 7 May 2025 17:40:25 +0300 Subject: [PATCH 05/12] MeTee: Windows: C# wrapper example Working example demonstrating how to use C# wrapper to communicate with FW and driver Signed-off-by: Abliyev, Reuven --- samples/CMakeLists.txt | 6 +- samples/csharp/AssemblyInfo.cs.in | 36 +++++++++ samples/csharp/CMakeLists.txt | 28 +++++++ samples/csharp/Program.cs | 127 ++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 samples/csharp/AssemblyInfo.cs.in create mode 100644 samples/csharp/CMakeLists.txt create mode 100644 samples/csharp/Program.cs diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index fbbd2e2..63d80f9 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -28,4 +28,8 @@ install(TARGETS metee-trc RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) add_executable(metee-basic metee_basic.c) target_link_libraries(metee-basic metee) -install(TARGETS metee-basic RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) \ No newline at end of file +install(TARGETS metee-basic RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +if(BUILD_SHARED_LIBS AND WIN32) + add_subdirectory(csharp) +endif(BUILD_SHARED_LIBS AND WIN32) \ No newline at end of file diff --git a/samples/csharp/AssemblyInfo.cs.in b/samples/csharp/AssemblyInfo.cs.in new file mode 100644 index 0000000..8a33958 --- /dev/null +++ b/samples/csharp/AssemblyInfo.cs.in @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (C) 2025 Intel Corporation + */ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("metee-csharp-sample")] +[assembly: AssemblyDescription("C# sample project")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Intel Corporation")] +[assembly: AssemblyProduct("metee-csharp-sample")] +[assembly: AssemblyCopyright("Copyright (C) 2025 Intel Corporation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("62336647-651e-4c5a-a92a-fbda141e6c4e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("${TEE_VERSION_STRING}")] +[assembly: AssemblyFileVersion("${TEE_VERSION_STRING}")] \ No newline at end of file diff --git a/samples/csharp/CMakeLists.txt b/samples/csharp/CMakeLists.txt new file mode 100644 index 0000000..85e6827 --- /dev/null +++ b/samples/csharp/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (C) 2025 Intel Corporation +cmake_minimum_required(VERSION 3.8) + +project(csharp-example VERSION 0.1.0 LANGUAGES CSharp) + +include(CSharpUtilities) + +configure_file(AssemblyInfo.cs.in ${CMAKE_CURRENT_SOURCE_DIR}/Properties/AssemblyInfo.cs) + +add_executable(csharp-example + Program.cs + Properties/AssemblyInfo.cs +) + +target_link_libraries(csharp-example Intel.Security.Metee) + +set_property(TARGET csharp-example PROPERTY VS_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1") + +set_property(TARGET csharp-example PROPERTY VS_DOTNET_REFERENCES + "System" + "System.Core" + "System.Data.DataSetExtensions" + "Microsoft.CSharp" + "System.Data" +) + +install(TARGETS csharp-example RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) \ No newline at end of file diff --git a/samples/csharp/Program.cs b/samples/csharp/Program.cs new file mode 100644 index 0000000..8a702b5 --- /dev/null +++ b/samples/csharp/Program.cs @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (C) 2025 Intel Corporation + */ +using Intel.Security; +using System; + +namespace metee_csharp_sample +{ + internal class Program + { + static void PrintFwVersion(byte[] data) + { + var version = new FwVersionResponse(data); + Console.WriteLine($"CodeMinor: {version.CodeMinor}"); + Console.WriteLine($"CodeMajor: {version.CodeMajor}"); + Console.WriteLine($"CodeBuildNo: {version.CodeBuildNo}"); + Console.WriteLine($"CodeHotFix: {version.CodeHotFix}"); + } + + const byte MkhiGetFwVersionCommandId = 0x02; + const byte MkhiGenGroupId = 0xFF; + + class FwMkhiCommandRequest + { + private int _data; + + public int GroupId + { + set => _data |= value; + } + public int Command { set => _data |= (value << 8); } + + public byte[] Data => BitConverter.GetBytes(_data); + } + + class FwVersionRequest : FwMkhiCommandRequest + { + public FwVersionRequest() + { + GroupId = MkhiGenGroupId; + Command = MkhiGetFwVersionCommandId; + } + } + + class FwMkhiCommandResponse + { + protected const int ResultOffset = 4; + + protected readonly byte[] Data; + + protected FwMkhiCommandResponse(byte[] data) + { + Data = data; + if (Data.Length < ResultOffset) + throw new ArgumentException("Data length is too short"); + } + } + + class FwVersionResponse : FwMkhiCommandResponse + { + public FwVersionResponse(byte[] data) : base(data) + { + if (Data.Length < (ResultOffset + 8)) + throw new ArgumentException("Data length is too short"); + } + + public int CodeMinor => BitConverter.ToInt16(Data, ResultOffset); + public int CodeMajor => BitConverter.ToInt16(Data, ResultOffset + 2); + public int CodeBuildNo => BitConverter.ToInt16(Data, ResultOffset + 4); + public int CodeHotFix => BitConverter.ToInt16(Data, ResultOffset + 6); + } + + static byte[] BasicMeTeeFlow(Metee metee) + { + Console.WriteLine($"Driver Version {metee.DriverVersion}"); + Console.WriteLine($"TRC {metee.Trc}"); + Console.WriteLine($"FWSTS 1 0x{metee.FwStatus[Metee.RegIndex.FwStatus1]:X8}"); + Console.WriteLine($"FWSTS 2 0x{metee.FwStatus[Metee.RegIndex.FwStatus2]:X8}"); + + metee.Connect(); + + Console.WriteLine($"Protocol Version {metee.ProtocolVersion}"); + Console.WriteLine($"MaxMsgLen {metee.MaxMsgLen}"); + + metee.Write(new FwVersionRequest().Data, Int32.MaxValue); + return metee.Read(Int32.MaxValue); + } + + static void Main(string[] args) + { + var mkhiClient = new Guid(0x8e6a6715, 0x9abc, 0x4043, 0x88, 0xef, 0x9e, 0x39, 0xc6, 0xf6, 0x3e, 0x0f); + + try + { + var teeDriverInterface = new Guid(0xE2D1FF34, 0x3458, 0x49A9, + 0x88, 0xDA, 0x8E, 0x69, 0x15, 0xCE, 0x9B, 0xE5); + using (var metee = new Metee(mkhiClient, teeDriverInterface)) + { + var res = BasicMeTeeFlow(metee); + PrintFwVersion(res); + } + + using (var metee = new Metee(mkhiClient)) + { + var res = BasicMeTeeFlow(metee); + PrintFwVersion(res); + } + + // This code demonstrates how to use MeTee with a given device path. + // Keep in mind that the device path may vary across different systems. + // + // var pathToTeeDriver = @"\\?\PCI#VEN_8086..HERE-GOES-YOUR-DEVICE-PATH..."; + // using (var metee = new Metee(mkhiClient, pathToTeeDriver)) + // { + // var res = BasicMeTeeFlow(metee); + // PrintFwVersion(res); + // } + } + catch (DllNotFoundException e) + { + // Ensure that metee.dll is in the same directory as the executable + Console.WriteLine(e); + } + } + } +} \ No newline at end of file From 2bd670ba00937529551b1095e8a51b1750324e4d Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Mon, 26 May 2025 16:44:57 +0300 Subject: [PATCH 06/12] MeTee: Change TeeLogger signature Add new logger type Signed-off-by: Abliyev, Reuven --- include/helpers.h | 21 +++++++++++++++------ include/metee.h | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/include/helpers.h b/include/helpers.h index b1c763a..a249758 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -8,6 +8,8 @@ extern "C" { #endif +#define DEBUG_MSG_LEN 1024 + #ifdef _WIN32 #include #include @@ -25,8 +27,6 @@ extern "C" { #define MALLOC(X) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, X) #define FREE(X) {if(X) { HeapFree(GetProcessHeap(), 0, X); X = NULL ; } } - #define DEBUG_MSG_LEN 1024 - void DebugPrintMe(const char* args, ...); #define ErrorPrintMe(fmt, ...) DebugPrintMe(fmt, __VA_ARGS__) @@ -79,18 +79,27 @@ extern "C" { #define INIT_STATUS -EPERM #endif /* _WIN32 */ +#define LEGACY_CALLBACK_SET(h) ((h)->log_callback ? 1 : 0) +#define STANDARD_CALLBACK_SET(h) ((h)->log_callback2 ? 1 : 0) + +void CallbackPrintHelper(IN PTEEHANDLE handle, bool is_error, const char* args, ...); + #define DBGPRINT(h, _x_, ...) \ if ((h) && (h)->log_level >= TEE_LOG_LEVEL_VERBOSE) { \ - if ((h)->log_callback) \ - (h)->log_callback(false, DEBUG_PRINT_ME_PREFIX_EXTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ + if (LEGACY_CALLBACK_SET(h)) \ + (h)->log_callback(false, DEBUG_PRINT_ME_PREFIX_EXTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ + else if (STANDARD_CALLBACK_SET(h)) \ + CallbackPrintHelper((h), false, DEBUG_PRINT_ME_PREFIX_EXTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ else \ DebugPrintMe(DEBUG_PRINT_ME_PREFIX_INTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ } #define ERRPRINT(h, _x_, ...) \ if ((h) && (h)->log_level >= TEE_LOG_LEVEL_ERROR) { \ - if ((h)->log_callback) \ - (h)->log_callback(true, DEBUG_PRINT_ME_PREFIX_EXTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ + if (LEGACY_CALLBACK_SET(h)) \ + (h)->log_callback(true, DEBUG_PRINT_ME_PREFIX_EXTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ + else if (STANDARD_CALLBACK_SET(h)) \ + CallbackPrintHelper((h), true, DEBUG_PRINT_ME_PREFIX_EXTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ else \ ErrorPrintMe(DEBUG_PRINT_ME_PREFIX_INTERNAL _x_,__FILE__,__FUNCTION__,__LINE__, ##__VA_ARGS__); \ } diff --git a/include/metee.h b/include/metee.h index e665588..9968d55 100644 --- a/include/metee.h +++ b/include/metee.h @@ -91,9 +91,14 @@ enum tee_log_level { }; /*! log callback function format + * @deprecated Since version 6.0 */ typedef void(*TeeLogCallback)(bool is_error, const char* fmt, ...); +/*! log callback function format + */ +typedef void(*TeeLogCallback2)(bool is_error, const char* msg); + #pragma pack(1) /*! @@ -105,7 +110,8 @@ typedef struct _TEEHANDLE { size_t maxMsgLen; /**< FW Client Max Message Length */ uint8_t protcolVer; /**< FW Client Protocol FW */ enum tee_log_level log_level; /**< Log level */ - TeeLogCallback log_callback; /**< Log callback */ + TeeLogCallback log_callback; /**< Deprecated Log callback */ + TeeLogCallback2 log_callback2; /**< Log callback */ } TEEHANDLE; /*! @@ -190,6 +196,7 @@ typedef uint16_t TEESTATUS; /**< return status for API functions */ #define TEE_IS_SUCCESS(Status) (((TEESTATUS)(Status)) == TEE_SUCCESS) /*! Initializes a TEE connection + * @deprecated Since version 6.0 * \param handle A handle to the TEE device. All subsequent calls to the lib's functions * must be with this handle * \param guid GUID of the FW client that want to start a session @@ -202,6 +209,19 @@ TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, IN const struct tee_device_address device, IN uint32_t log_level, IN OPTIONAL TeeLogCallback log_callback); + /*! Initializes a TEE connection + * \param handle A handle to the TEE device. All subsequent calls to the lib's functions + * must be with this handle + * \param guid GUID of the FW client that want to start a session + * \param device device address structure + * \param log_level log level to set (from enum tee_log_level) + * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \return 0 if successful, otherwise error code + */ +TEESTATUS TEEAPI TeeInitFull2(IN OUT PTEEHANDLE handle, IN const GUID* guid, + IN const struct tee_device_address device, + IN uint32_t log_level, IN OPTIONAL TeeLogCallback2 log_callback); + /*! Initializes a TEE connection * \param handle A handle to the TEE device. All subsequent calls to the lib's functions * must be with this handle @@ -328,13 +348,21 @@ uint32_t TEEAPI TeeSetLogLevel(IN PTEEHANDLE handle, IN uint32_t log_level); uint32_t TEEAPI TeeGetLogLevel(IN const PTEEHANDLE handle); /*! Set log callback - * + * @deprecated Since version 6.0 * \param handle The handle of the session. * \param log_callback pointer to function to run for log write, set NULL to use built-in function * \return 0 if successful, otherwise error code. */ TEESTATUS TEEAPI TeeSetLogCallback(IN const PTEEHANDLE handle, TeeLogCallback log_callback); +/*! Set log callback + * + * \param handle The handle of the session. + * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \return 0 if successful, otherwise error code. + */ +TEESTATUS TEEAPI TeeSetLogCallback2(IN const PTEEHANDLE handle, TeeLogCallback2 log_callback); + /*! Retrieve client maximum message length (MTU) * * \param handle The handle of the session. From 53598bd4967f4a48c11cc6051ea25a2131f52754 Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Wed, 21 May 2025 17:22:59 +0300 Subject: [PATCH 07/12] MeTee: Windows: new logger interface Implementation New logger logic for Windows Signed-off-by: Abliyev, Reuven --- src/Windows/metee_win.c | 55 ++++++++++++++++++++++++++++++++-- src/Windows/metee_winhelpers.c | 10 +++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/Windows/metee_win.c b/src/Windows/metee_win.c index b4aeb58..fd3ce97 100644 --- a/src/Windows/metee_win.c +++ b/src/Windows/metee_win.c @@ -59,9 +59,10 @@ static TEESTATUS __CreateFile(PTEEHANDLE handle, const char *devicePath, PHANDLE /********************************************************************** ** TEE Lib Function * **********************************************************************/ -TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, + +static TEESTATUS TeeInitFullInt(IN OUT PTEEHANDLE handle, IN const GUID* guid, IN const struct tee_device_address device, - IN uint32_t log_level, IN OPTIONAL TeeLogCallback log_callback) + IN uint32_t log_level, IN TeeLogCallback log_callback, TeeLogCallback2 log_callback2) { TEESTATUS status; errno_t res; @@ -77,6 +78,7 @@ TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, __tee_init_handle(handle); handle->log_level = (log_level >= TEE_LOG_LEVEL_MAX) ? TEE_LOG_LEVEL_VERBOSE : log_level; handle->log_callback = log_callback; + handle->log_callback2 = log_callback2; FUNC_ENTRY(handle); @@ -222,6 +224,20 @@ TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, return status; } +TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, + IN const struct tee_device_address device, + IN uint32_t log_level, IN OPTIONAL TeeLogCallback log_callback) +{ + return TeeInitFullInt(handle, guid, device, log_level, log_callback, NULL); +} + +TEESTATUS TEEAPI TeeInitFull2(IN OUT PTEEHANDLE handle, IN const GUID* guid, + IN const struct tee_device_address device, + IN uint32_t log_level, IN OPTIONAL TeeLogCallback2 log_callback) +{ + return TeeInitFullInt(handle, guid, device, log_level, NULL, log_callback); +} + TEESTATUS TEEAPI TeeInit(IN OUT PTEEHANDLE handle, IN const GUID* guid, IN OPTIONAL const char* device) { @@ -674,6 +690,11 @@ TEESTATUS TEEAPI TeeSetLogCallback(IN const PTEEHANDLE handle, TeeLogCallback lo ERRPRINT(handle, "One of the parameters was illegal"); goto Cleanup; } + if (handle->log_callback2) { + ERRPRINT(handle, "Standard callback already in use\n"); + status = TEE_INVALID_PARAMETER; + goto Cleanup; + } handle->log_callback = log_callback; status = TEE_SUCCESS; @@ -683,6 +704,36 @@ TEESTATUS TEEAPI TeeSetLogCallback(IN const PTEEHANDLE handle, TeeLogCallback lo return status; } +TEESTATUS TEEAPI TeeSetLogCallback2(IN const PTEEHANDLE handle, TeeLogCallback2 log_callback) +{ + struct METEE_WIN_IMPL* impl_handle = to_int(handle); + TEESTATUS status; + + if (NULL == handle) { + return TEE_INVALID_PARAMETER; + } + + FUNC_ENTRY(handle); + + if (NULL == impl_handle) { + status = TEE_INVALID_PARAMETER; + ERRPRINT(handle, "One of the parameters was illegal"); + goto Cleanup; + } + if (handle->log_callback) { + ERRPRINT(handle, "Legacy callback already in use\n"); + status = TEE_INVALID_PARAMETER; + goto Cleanup; + } + + handle->log_callback2 = log_callback; + status = TEE_SUCCESS; + +Cleanup: + FUNC_EXIT(handle, status); + return status; +} + uint32_t TEEAPI TeeGetMaxMsgLen(IN const PTEEHANDLE handle) { if (NULL == handle) { diff --git a/src/Windows/metee_winhelpers.c b/src/Windows/metee_winhelpers.c index ad4c478..21deb4a 100644 --- a/src/Windows/metee_winhelpers.c +++ b/src/Windows/metee_winhelpers.c @@ -32,6 +32,16 @@ void DebugPrintMe(const char* args, ...) #endif /* SYSLOG */ } +void CallbackPrintHelper(IN PTEEHANDLE handle, bool is_error, const char* args, ...) +{ + char msg[DEBUG_MSG_LEN + 1]; + va_list varl; + va_start(varl, args); + vsprintf_s(msg, DEBUG_MSG_LEN, args, varl); + va_end(varl); + handle->log_callback2(is_error, msg); +} + /* ** Start Overlapped Operation ** From a375cd16e3d812bb2e86c3665d28504b0fa39978 Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Wed, 21 May 2025 17:32:54 +0300 Subject: [PATCH 08/12] MeTee: EFI: new logger interface Implementation new logger logic for EFI Signed-off-by: Abliyev, Reuven --- include/helpers.h | 2 +- src/uefi/metee_efi.c | 81 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/include/helpers.h b/include/helpers.h index a249758..628a1ee 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -34,7 +34,7 @@ extern "C" { #define INIT_STATUS TEE_INTERNAL_ERROR #elif defined(EFI) #define DEBUG_PRINT_ME_PREFIX_INTERNAL "TEELIB: (%a:%a():%d) " - #define DEBUG_PRINT_ME_PREFIX_EXTERNAL "TEELIB: (%s:%s():%d) " + #define DEBUG_PRINT_ME_PREFIX_EXTERNAL "TEELIB: (%a:%a():%d) " #define DebugPrintMe(fmt, ...) AsciiPrint(fmt, ##__VA_ARGS__) #define ErrorPrintMe(fmt, ...) AsciiPrint(fmt, ##__VA_ARGS__) #else diff --git a/src/uefi/metee_efi.c b/src/uefi/metee_efi.c index ed1cc0b..f5590f2 100644 --- a/src/uefi/metee_efi.c +++ b/src/uefi/metee_efi.c @@ -92,6 +92,16 @@ HwInfoGfxGsc( return hw_info; } +void CallbackPrintHelper(IN PTEEHANDLE handle, bool is_error, const char* args, ...) +{ + char msg[DEBUG_MSG_LEN + 1]; + VA_LIST varl; + VA_START(varl, args); + AsciiVSPrint(msg, DEBUG_MSG_LEN, args, varl); + VA_END(varl); + handle->log_callback2(is_error, msg); +} + static TEESTATUS SetHwInfo( IN const struct tee_device_address *device, @@ -169,17 +179,18 @@ TeeInitFullTypeEfiDevice( * \param guid GUID of the FW client that want to start a session * \param device device address structure * \param log_level log level to set (from enum tee_log_level) - * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \param log_callback pointer to function to run for log write, set NULL to use built-in function (deprecated) + * \param log_callback2 pointer to function to run for log write, set NULL to use built-in function * \return 0 if successful, otherwise error code */ -TEESTATUS -TEEAPI -TeeInitFull( +static TEESTATUS TeeInitFullInt( IN OUT PTEEHANDLE handle, IN const GUID *guid, IN const struct tee_device_address device, IN uint32_t log_level, - IN OPTIONAL TeeLogCallback log_callback) + IN TeeLogCallback log_callback, + IN TeeLogCallback2 log_callback2 + ) { TEESTATUS status = TEE_INTERNAL_ERROR; struct tee_device_address default_device = device; @@ -197,6 +208,7 @@ TeeInitFull( __tee_init_handle(handle); handle->log_level = (log_level >= TEE_LOG_LEVEL_MAX) ? TEE_LOG_LEVEL_VERBOSE : log_level; handle->log_callback = log_callback; + handle->log_callback2 = log_callback2; FUNC_ENTRY(handle); @@ -263,6 +275,20 @@ TeeInitFull( return status; } +TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, + IN const struct tee_device_address device, + IN uint32_t log_level, IN OPTIONAL TeeLogCallback log_callback) +{ + return TeeInitFullInt(handle, guid, device, log_level, log_callback, NULL); +} + +TEESTATUS TEEAPI TeeInitFull2(IN OUT PTEEHANDLE handle, IN const GUID* guid, + IN const struct tee_device_address device, + IN uint32_t log_level, IN OPTIONAL TeeLogCallback2 log_callback) +{ + return TeeInitFullInt(handle, guid, device, log_level, NULL, log_callback); +} + /*! Initializes a TEE connection * \param handle A handle to the TEE device. All subsequent calls to the lib's functions * must be with this handle @@ -665,7 +691,7 @@ uint32_t TEEAPI TeeGetLogLevel(IN const PTEEHANDLE handle) } /*! Set log callback - * + * @deprecated Since version 6.0 * \param handle The handle of the session. * \param log_callback pointer to function to run for log write, set NULL to use built-in function * \return 0 if successful, otherwise error code. @@ -688,6 +714,11 @@ TEESTATUS TEEAPI TeeSetLogCallback(IN const PTEEHANDLE handle, TeeLogCallback lo ERRPRINT(handle, "One of the parameters was illegal"); goto Cleanup; } + if (handle->log_callback2) { + ERRPRINT(handle, "Standard callback already in use\n"); + status = TEE_INVALID_PARAMETER; + goto Cleanup; + } handle->log_callback = log_callback; status = TEE_SUCCESS; @@ -697,6 +728,44 @@ TEESTATUS TEEAPI TeeSetLogCallback(IN const PTEEHANDLE handle, TeeLogCallback lo return status; } +/*! Set log callback + * + * \param handle The handle of the session. + * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \return 0 if successful, otherwise error code. + */ +TEESTATUS TEEAPI TeeSetLogCallback2(IN const PTEEHANDLE handle, TeeLogCallback2 log_callback) +{ + struct METEE_EFI_IMPL *impl_handle = to_int(handle); + TEESTATUS status; + + if (NULL == handle) + { + return TEE_INVALID_PARAMETER; + } + + FUNC_ENTRY(handle); + + if (NULL == impl_handle) + { + status = TEE_INVALID_PARAMETER; + ERRPRINT(handle, "One of the parameters was illegal"); + goto Cleanup; + } + if (handle->log_callback) { + ERRPRINT(handle, "Legacy callback already in use\n"); + status = TEE_INVALID_PARAMETER; + goto Cleanup; + } + + handle->log_callback2 = log_callback; + status = TEE_SUCCESS; + +Cleanup: + FUNC_EXIT(handle, status); + return status; +} + uint32_t TEEAPI TeeGetMaxMsgLen(IN const PTEEHANDLE handle) { if (NULL == handle) From a62d097ff8b8790f37ca19f3ddce6014cf8bfbdd Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Thu, 22 May 2025 09:26:06 +0300 Subject: [PATCH 09/12] MeTee: linux: pull libmei 1.7.0 Update to libmei 1.7.0 Signed-off-by: Abliyev, Reuven --- src/linux/libmei.h | 33 +++++++++++++++++++- src/linux/mei.c | 76 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 94 insertions(+), 15 deletions(-) diff --git a/src/linux/libmei.h b/src/linux/libmei.h index de9f3a7..c81f8d3 100644 --- a/src/linux/libmei.h +++ b/src/linux/libmei.h @@ -57,9 +57,14 @@ enum mei_log_level { }; /*! log callback function format + * @deprecated Since version 1.7.0 */ typedef void(*mei_log_callback)(bool is_error, const char* fmt, ...); +/*! log callback function format + */ +typedef void(*mei_log_callback2)(bool is_error, const char* msg); + /*! Structure to store connection data */ struct mei { @@ -74,7 +79,8 @@ struct mei { bool close_on_exit; /**< close handle on deinit */ char *device; /**< device name */ uint8_t vtag; /**< vtag used in communication */ - mei_log_callback log_callback; /**< Log callback */ + mei_log_callback log_callback; /**< Deprecated Log callback */ + mei_log_callback2 log_callback2; /**< Log callback */ }; /*! Default name of mei device @@ -131,6 +137,7 @@ int mei_init(struct mei *me, const char *device, const uuid_le *guid, /*! Initializes a mei connection with log callback * + * @deprecated Since version 1.7.0 * \param me A handle to the mei device. All subsequent calls to the lib's functions * must be with this handle * \param device device path, set MEI_DEFAULT_DEVICE to use default @@ -144,6 +151,21 @@ int mei_init_with_log(struct mei *me, const char *device, const uuid_le *guid, unsigned char req_protocol_version, bool verbose, mei_log_callback log_callback); +/*! Initializes a mei connection with log callback + * + * \param me A handle to the mei device. All subsequent calls to the lib's functions + * must be with this handle + * \param device device path, set MEI_DEFAULT_DEVICE to use default + * \param guid GUID of associated mei client + * \param req_protocol_version minimal required protocol version, 0 for any + * \param verbose print verbose output to a console + * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \return 0 if successful, otherwise error code + */ +int mei_init_with_log2(struct mei *me, const char *device, const uuid_le *guid, + unsigned char req_protocol_version, bool verbose, + mei_log_callback2 log_callback); + /*! Initializes a mei connection * * \param me A handle to the mei device. All subsequent calls to the lib's functions @@ -283,12 +305,21 @@ uint32_t mei_get_log_level(const struct mei *me); /*! Set log callback * + * @deprecated Since version 1.7.0 * \param me The mei handle * \param log_callback pointer to function to run for log write, set NULL to use built-in function * \return 0 if successful, otherwise error code. */ int mei_set_log_callback(struct mei *me, mei_log_callback log_callback); +/*! Set log callback + * + * \param me The mei handle + * \param log_callback pointer to function to run for log write, set NULL to use built-in function + * \return 0 if successful, otherwise error code. + */ +int mei_set_log_callback2(struct mei *me, mei_log_callback2 log_callback); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/linux/mei.c b/src/linux/mei.c index 70192af..3a500ce 100644 --- a/src/linux/mei.c +++ b/src/linux/mei.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "libmei.h" @@ -45,22 +46,29 @@ static inline void __dump_buffer(const char *buf) #define __mei_err(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #endif /* SYSLOG */ -#define mei_msg(_me, fmt, ARGS...) do { \ - if ((_me)->log_level >= MEI_LOG_LEVEL_VERBOSE) { \ - if ((_me)->log_callback) \ +#define LEGACY_CALLBACK_SET(h) ((h)->log_callback ? 1 : 0) +#define STANDARD_CALLBACK_SET(h) ((h)->log_callback2 ? 1 : 0) + +#define mei_msg(_me, fmt, ARGS...) do { \ + if ((_me)->log_level >= MEI_LOG_LEVEL_VERBOSE) { \ + if (LEGACY_CALLBACK_SET(_me)) \ (_me)->log_callback(false, fmt, ##ARGS); \ - else \ - __mei_msg(fmt, ##ARGS); \ - } \ + else if (STANDARD_CALLBACK_SET(_me)) \ + callback_print_helper((_me), false, fmt, ##ARGS); \ + else \ + __mei_msg(fmt, ##ARGS); \ + } \ } while (0) -#define mei_err(_me, fmt, ARGS...) do { \ - if ((_me)->log_level > MEI_LOG_LEVEL_QUIET) { \ - if ((_me)->log_callback) \ +#define mei_err(_me, fmt, ARGS...) do { \ + if ((_me)->log_level > MEI_LOG_LEVEL_QUIET) { \ + if (LEGACY_CALLBACK_SET(_me)) \ (_me)->log_callback(true, "me: error: " fmt, ##ARGS); \ - else \ - __mei_err("me: error: " fmt, ##ARGS); \ - } \ + else if (STANDARD_CALLBACK_SET(_me)) \ + callback_print_helper((_me), true, fmt, ##ARGS); \ + else \ + __mei_err("me: error: " fmt, ##ARGS); \ + } \ } while (0) #ifdef DEBUG @@ -106,6 +114,17 @@ static void mei_dump_hex_buffer(struct mei *me, } #endif /* DEBUG */ +static void callback_print_helper(struct mei *me, bool is_error, const char* args, ...) +{ +#define DEBUG_MSG_LEN 1024 + char msg[DEBUG_MSG_LEN + 1]; + va_list varl; + va_start(varl, args); + vsnprintf(msg, DEBUG_MSG_LEN, args, varl); + va_end(varl); + me->log_callback2(is_error, msg); +} + void mei_deinit(struct mei *me) { if (!me) @@ -381,9 +400,9 @@ static inline int __mei_getkind(struct mei *me, const char *device, char *kind, #undef KIND_LEN } -int mei_init_with_log(struct mei *me, const char *device, const uuid_le *guid, +static int mei_init_with_log_int(struct mei *me, const char *device, const uuid_le *guid, unsigned char req_protocol_version, bool verbose, - mei_log_callback log_callback) + mei_log_callback log_callback, mei_log_callback2 log_callback2) { int rc; @@ -395,6 +414,7 @@ int mei_init_with_log(struct mei *me, const char *device, const uuid_le *guid, me->close_on_exit = true; me->device = NULL; me->log_callback = log_callback; + me->log_callback2 = log_callback2; mei_deinit(me); me->log_level = verbose ? MEI_LOG_LEVEL_VERBOSE : MEI_LOG_LEVEL_ERROR; @@ -425,6 +445,22 @@ int mei_init_with_log(struct mei *me, const char *device, const uuid_le *guid, return 0; } +int mei_init_with_log(struct mei *me, const char *device, const uuid_le *guid, + unsigned char req_protocol_version, bool verbose, + mei_log_callback log_callback) +{ + return mei_init_with_log_int(me, device, guid, + req_protocol_version, verbose, log_callback, NULL); +} + +int mei_init_with_log2(struct mei *me, const char *device, const uuid_le *guid, + unsigned char req_protocol_version, bool verbose, + mei_log_callback2 log_callback) +{ + return mei_init_with_log_int(me, device, guid, + req_protocol_version, verbose, NULL, log_callback); +} + int mei_init(struct mei *me, const char *device, const uuid_le *guid, unsigned char req_protocol_version, bool verbose) { @@ -485,6 +521,7 @@ int mei_init_fd(struct mei *me, int fd, const uuid_le *guid, mei_deinit(me); me->fd = fd; me->log_callback = NULL; + me->log_callback2 = NULL; me->log_level = verbose ? MEI_LOG_LEVEL_VERBOSE : MEI_LOG_LEVEL_ERROR; @@ -845,3 +882,14 @@ int mei_set_log_callback(struct mei *me, mei_log_callback log_callback) return 0; } + +int mei_set_log_callback2(struct mei *me, mei_log_callback2 log_callback) +{ + if (!me) + return -EINVAL; + + me->log_callback2 = log_callback; + mei_msg(me, "New log callback set\n"); + + return 0; +} From 6bffa8ac13f10eefa8f80cc255b9a6a7fdd4eb60 Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Thu, 22 May 2025 09:28:16 +0300 Subject: [PATCH 10/12] MeTee: linux: new logger interface Implementation Implement new logger for Linux Signed-off-by: Abliyev, Reuven --- src/linux/metee_linux.c | 89 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 7 deletions(-) diff --git a/src/linux/metee_linux.c b/src/linux/metee_linux.c index 0af367b..476e7b9 100644 --- a/src/linux/metee_linux.c +++ b/src/linux/metee_linux.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "metee.h" #include "helpers.h" @@ -92,9 +93,20 @@ static inline TEESTATUS errno2status_init(ssize_t err) } } -TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, +void CallbackPrintHelper(IN PTEEHANDLE handle, bool is_error, const char* args, ...) +{ + char msg[DEBUG_MSG_LEN + 1]; + va_list varl; + va_start(varl, args); + vsnprintf(msg, DEBUG_MSG_LEN, args, varl); + va_end(varl); + handle->log_callback2(is_error, msg); +} + +static TEESTATUS TeeInitFullInt(IN OUT PTEEHANDLE handle, IN const GUID* guid, IN const struct tee_device_address device, - IN uint32_t log_level, IN OPTIONAL TeeLogCallback log_callback) + IN uint32_t log_level, IN TeeLogCallback log_callback, + IN TeeLogCallback2 log_callback2) { struct metee_linux_intl *intl; TEESTATUS status; @@ -108,6 +120,7 @@ TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, __tee_init_handle(handle); handle->log_level = (log_level >= TEE_LOG_LEVEL_MAX) ? TEE_LOG_LEVEL_VERBOSE : log_level; handle->log_callback = log_callback; + handle->log_callback2 = log_callback2; FUNC_ENTRY(handle); @@ -154,17 +167,29 @@ TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, switch (device.type) { case TEE_DEVICE_TYPE_NONE: - rc = mei_init_with_log(&intl->me, MEI_DEFAULT_DEVICE, - (uuid_le*)guid, 0, verbose, log_callback); + if (log_callback) + rc = mei_init_with_log(&intl->me, MEI_DEFAULT_DEVICE, + (uuid_le*)guid, 0, verbose, log_callback); + else + rc = mei_init_with_log2(&intl->me, MEI_DEFAULT_DEVICE, + (uuid_le*)guid, 0, verbose, log_callback2); break; case TEE_DEVICE_TYPE_PATH: - rc = mei_init_with_log(&intl->me, device.data.path, - (uuid_le*)guid, 0, verbose, log_callback); + if (log_callback) + rc = mei_init_with_log(&intl->me, device.data.path, + (uuid_le*)guid, 0, verbose, log_callback); + else + rc = mei_init_with_log2(&intl->me, device.data.path, + (uuid_le*)guid, 0, verbose, log_callback2); + break; case TEE_DEVICE_TYPE_HANDLE: rc = mei_init_fd(&intl->me, device.data.handle, (uuid_le*)guid, 0, verbose); if (!rc) { - mei_set_log_callback(&intl->me, log_callback); + if (log_callback) + mei_set_log_callback(&intl->me, log_callback); + else + mei_set_log_callback2(&intl->me, log_callback2); mei_set_log_level(&intl->me, verbose); } break; @@ -194,6 +219,20 @@ TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, return status; } +TEESTATUS TEEAPI TeeInitFull(IN OUT PTEEHANDLE handle, IN const GUID* guid, + IN const struct tee_device_address device, + IN uint32_t log_level, IN OPTIONAL TeeLogCallback log_callback) +{ + return TeeInitFullInt(handle, guid, device, log_level, log_callback, NULL); +} + +TEESTATUS TEEAPI TeeInitFull2(IN OUT PTEEHANDLE handle, IN const GUID* guid, + IN const struct tee_device_address device, + IN uint32_t log_level, IN OPTIONAL TeeLogCallback2 log_callback) +{ + return TeeInitFullInt(handle, guid, device, log_level, NULL, log_callback); +} + TEESTATUS TEEAPI TeeInit(IN OUT PTEEHANDLE handle, IN const GUID* guid, IN OPTIONAL const char* device) { @@ -571,6 +610,11 @@ TEESTATUS TEEAPI TeeSetLogCallback(IN const PTEEHANDLE handle, TeeLogCallback lo ERRPRINT(handle, "One of the parameters was illegal\n"); goto Cleanup; } + if (handle->log_callback2) { + ERRPRINT(handle, "Standard callback already in use\n"); + status = TEE_INVALID_PARAMETER; + goto Cleanup; + } handle->log_callback = log_callback; mei_set_log_callback(me, log_callback); @@ -581,6 +625,37 @@ TEESTATUS TEEAPI TeeSetLogCallback(IN const PTEEHANDLE handle, TeeLogCallback lo return status; } +TEESTATUS TEEAPI TeeSetLogCallback2(IN const PTEEHANDLE handle, TeeLogCallback2 log_callback) +{ + struct mei *me = to_mei(handle); + TEESTATUS status; + + if (!handle) { + return TEE_INVALID_PARAMETER; + } + + FUNC_ENTRY(handle); + + if (!me) { + status = TEE_INVALID_PARAMETER; + ERRPRINT(handle, "One of the parameters was illegal\n"); + goto Cleanup; + } + if (handle->log_callback) { + ERRPRINT(handle, "Legacy callback already in use\n"); + status = TEE_INVALID_PARAMETER; + goto Cleanup; + } + + handle->log_callback2 = log_callback; + mei_set_log_callback2(me, log_callback); + status = TEE_SUCCESS; + +Cleanup: + FUNC_EXIT(handle, status); + return status; +} + uint32_t TEEAPI TeeGetMaxMsgLen(IN const PTEEHANDLE handle) { if (!handle) { From 13e06ee37ef3a598125b27ebb9b6e8fe7c972f1c Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Tue, 20 May 2025 08:34:15 +0300 Subject: [PATCH 11/12] MeTee: Windows: C# Wrapper logger C# logger callback implementation with examples Signed-off-by: Abliyev, Reuven --- bindings/csharp/Metee.cs | 22 +++++++++++++++------- samples/csharp/Program.cs | 3 ++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/bindings/csharp/Metee.cs b/bindings/csharp/Metee.cs index 9f6db21..1c2f05c 100644 --- a/bindings/csharp/Metee.cs +++ b/bindings/csharp/Metee.cs @@ -65,6 +65,13 @@ public static LocalAllocHandle Allocate(int numberOfBytes) private LocalAllocHandle _safeHandle = LocalAllocHandle.Allocate(Marshal.SizeOf()); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void LogCallback( + [MarshalAs(UnmanagedType.I1)] + bool isError, + [In][MarshalAs(UnmanagedType.LPStr)] string msg + ); + #region DllImport private enum TeeDeviceType @@ -113,13 +120,14 @@ private struct TeeHandle private readonly IntPtr Field3; private readonly IntPtr Field4; private readonly IntPtr Field5; + private readonly IntPtr Field6; } [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int TeeInit(IntPtr handle, ref Guid guid, IntPtr device); [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] - private static extern int TeeInitFull(IntPtr handle, ref Guid guid, TeeDeviceAddress deviceAddress, [MarshalAs(UnmanagedType.U4)] TeeLogLevel logLevel, IntPtr logCallback); + private static extern int TeeInitFull2(IntPtr handle, ref Guid guid, TeeDeviceAddress deviceAddress, [MarshalAs(UnmanagedType.U4)] TeeLogLevel logLevel, LogCallback logCallback); [DllImport("metee.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int TeeConnect(IntPtr handle); @@ -197,11 +205,11 @@ public Metee() * @param logLevel - log level to set * @param logCallback - callback to be called on each log message */ - public Metee(Guid clientGuid, TeeLogLevel logLevel = TeeLogLevel.Quiet, IntPtr logCallback = default) + public Metee(Guid clientGuid, TeeLogLevel logLevel = TeeLogLevel.Quiet, LogCallback logCallback = default) { var device = new TeeDeviceAddress { DeviceType = TeeDeviceType.None, DataPtr = IntPtr.Zero }; - int status = TeeInitFull(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, logCallback); + int status = TeeInitFull2(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, logCallback); if (status != 0) { throw new MeteeException("Init failed", status); @@ -219,12 +227,12 @@ public Metee(Guid clientGuid, TeeLogLevel logLevel = TeeLogLevel.Quiet, IntPtr l * @param logLevel - log level to set * @param logCallback - callback to be called on each log message */ - public Metee(Guid clientGuid, string devicePath, TeeLogLevel logLevel = TeeLogLevel.Quiet, IntPtr logCallback = default) + public Metee(Guid clientGuid, string devicePath, TeeLogLevel logLevel = TeeLogLevel.Quiet, LogCallback logCallback = default) { int status = 1; using (var device = new TeeDeviceAddress(devicePath)) { - status = TeeInitFull(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, logCallback); + status = TeeInitFull2(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, logCallback); } if (status != 0) { @@ -243,12 +251,12 @@ public Metee(Guid clientGuid, string devicePath, TeeLogLevel logLevel = TeeLogLe * @param logLevel - log level to set * @param logCallback - callback to be called on each log message */ - public Metee(Guid clientGuid, Guid interfaceGuid, TeeLogLevel logLevel = TeeLogLevel.Quiet, IntPtr logCallback = default) + public Metee(Guid clientGuid, Guid interfaceGuid, TeeLogLevel logLevel = TeeLogLevel.Quiet, LogCallback logCallback = default) { int status = 1; using (var device = new TeeDeviceAddress(interfaceGuid)) { - status = TeeInitFull(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, + status = TeeInitFull2(_safeHandle.DangerousGetHandle(), ref clientGuid, device, logLevel, logCallback); } if (status != 0) diff --git a/samples/csharp/Program.cs b/samples/csharp/Program.cs index 8a702b5..a3390b7 100644 --- a/samples/csharp/Program.cs +++ b/samples/csharp/Program.cs @@ -95,7 +95,8 @@ static void Main(string[] args) { var teeDriverInterface = new Guid(0xE2D1FF34, 0x3458, 0x49A9, 0x88, 0xDA, 0x8E, 0x69, 0x15, 0xCE, 0x9B, 0xE5); - using (var metee = new Metee(mkhiClient, teeDriverInterface)) + using (var metee = new Metee(mkhiClient, teeDriverInterface, Metee.TeeLogLevel.Verbose, + delegate(bool error, string msg) { Console.Write($"{error} ==> [{msg}]"); })) { var res = BasicMeTeeFlow(metee); PrintFwVersion(res); From 41dbf2a7af3976e5115b308014630ecc5a26945b Mon Sep 17 00:00:00 2001 From: "Abliyev, Reuven" Date: Tue, 10 Jun 2025 12:32:13 +0300 Subject: [PATCH 12/12] MeTee: bump version to 6.0.0 Update CHANGELOG.md Signed-off-by: Abliyev, Reuven --- CHANGELOG.md | 15 +++++++++++++++ README.md | 6 +++++- VERSION | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa10479..ac71298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +## [6.0.0] + +**Note:** Backward incompatible ABI change: + The struct TEEHANDLE struct is packed(1) now + Added field to store V2 logger callback. + +### Changed + - Linux: pull libmei 1.7.0 + - CMake: consume four-part version + - Windows: fix copyright format + +### Added + - Windows: C# OOP wrapper + - TeeInitFull2 API + ## [5.0.0] **Note:** Backward incompatible API change: diff --git a/README.md b/README.md index 18591bb..bbe8122 100644 --- a/README.md +++ b/README.md @@ -61,4 +61,8 @@ Every thread should either initialize and use its own handle or a locking mechanism should be implemented by the caller to ensure that only one thread uses the handle at any time. The only exception is ability to call Disconnect to exit from read -blocked on another thread. \ No newline at end of file +blocked on another thread. + +## Artificial Intelligence + +These contents may have been developed with support from one or more Intel-operated generative artificial intelligence solutions. \ No newline at end of file diff --git a/VERSION b/VERSION index 0062ac9..09b254e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0 +6.0.0