diff --git a/src/Security/AuthorizationEngine.cs b/src/Security/AuthorizationEngine.cs
new file mode 100644
index 000000000000..31ea94611d42
--- /dev/null
+++ b/src/Security/AuthorizationEngine.cs
@@ -0,0 +1,31 @@
+#if __MACOS__
+#nullable enable
+
+using System;
+using System.Runtime.Versioning;
+using CoreFoundation;
+using ObjCRuntime;
+
+namespace Security {
+
+ /// Represents an opaque reference to an authorization engine used in authorization plugin views.
+ public class AuthorizationEngine : NativeObject {
+ [Preserve (Conditional = true)]
+ internal AuthorizationEngine (NativeHandle handle, bool owns)
+ : base (handle, owns)
+ {
+ }
+#if !COREBUILD
+ /// Creates an from a raw handle without taking ownership.
+ /// The native AuthorizationEngineRef handle.
+ /// A managed wrapper, or if the handle is zero.
+ public static AuthorizationEngine? Create (NativeHandle handle)
+ {
+ if (handle == IntPtr.Zero)
+ return null;
+ return new AuthorizationEngine (handle, owns: false);
+ }
+#endif // !COREBUILD
+ }
+}
+#endif // __MACOS__
diff --git a/src/Security/SecKeychain.cs b/src/Security/SecKeychain.cs
new file mode 100644
index 000000000000..31f097a6e66e
--- /dev/null
+++ b/src/Security/SecKeychain.cs
@@ -0,0 +1,100 @@
+#if __MACOS__
+#nullable enable
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using ObjCRuntime;
+using CoreFoundation;
+
+namespace Security {
+
+ /// Represents a keychain on macOS.
+ public class SecKeychain : NativeObject {
+ [Preserve (Conditional = true)]
+ internal SecKeychain (NativeHandle handle, bool owns)
+ : base (handle, owns)
+ {
+ }
+#if !COREBUILD
+ [SupportedOSPlatform ("macos")]
+ [ObsoletedOSPlatform ("macos10.10")]
+ [DllImport (Constants.SecurityLibrary)]
+ extern static unsafe int /* OSStatus */ SecKeychainGetTypeID ();
+
+ /// Returns the Core Foundation type identifier for SecKeychain.
+ /// The Core Foundation type identifier.
+ public static nint GetTypeID ()
+ {
+ return SecKeychainGetTypeID ();
+ }
+
+ [SupportedOSPlatform ("macos")]
+ [ObsoletedOSPlatform ("macos10.10")]
+ [DllImport (Constants.SecurityLibrary)]
+ extern static unsafe int /* OSStatus */ SecKeychainCopyDefault (IntPtr* keychain);
+
+ /// Gets the default keychain.
+ /// The default , or on failure.
+ public static SecKeychain? GetDefault ()
+ {
+ IntPtr handle;
+ int status;
+ unsafe {
+ status = SecKeychainCopyDefault (&handle);
+ }
+ if (status != 0 || handle == IntPtr.Zero)
+ return null;
+ return new SecKeychain (handle, owns: true);
+ }
+
+ [SupportedOSPlatform ("macos")]
+ [ObsoletedOSPlatform ("macos10.10")]
+ [DllImport (Constants.SecurityLibrary)]
+ extern static unsafe int /* OSStatus */ SecKeychainOpen (IntPtr pathName, IntPtr* keychain);
+
+ /// Opens the keychain at the specified file path.
+ /// The file system path of the keychain to open.
+ /// A for the specified path, or on failure.
+ public static SecKeychain? Open (string path)
+ {
+ if (path is null)
+ ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (path));
+ using var pathStr = new TransientString (path);
+ IntPtr handle;
+ int status;
+ unsafe {
+ status = SecKeychainOpen (pathStr, &handle);
+ }
+ if (status != 0 || handle == IntPtr.Zero)
+ return null;
+ return new SecKeychain (handle, owns: true);
+ }
+
+ [SupportedOSPlatform ("macos")]
+ [ObsoletedOSPlatform ("macos10.10")]
+ [DllImport (Constants.SecurityLibrary)]
+ extern static unsafe int /* OSStatus */ SecKeychainGetPath (IntPtr keychainRef, int* ioPathLength, IntPtr pathName);
+
+ /// Gets the file system path of this keychain.
+ /// The POSIX path of the keychain, or on failure.
+ public string? GetPath ()
+ {
+ int pathLength = 1024;
+ IntPtr buffer = Marshal.AllocHGlobal (pathLength);
+ try {
+ int status;
+ unsafe {
+ status = SecKeychainGetPath (Handle, &pathLength, buffer);
+ }
+ if (status != 0)
+ return null;
+ return Marshal.PtrToStringUTF8 (buffer, pathLength);
+ } finally {
+ Marshal.FreeHGlobal (buffer);
+ }
+ }
+#endif // !COREBUILD
+ }
+}
+#endif // __MACOS__
diff --git a/src/Security/SecKeychainSettings.cs b/src/Security/SecKeychainSettings.cs
new file mode 100644
index 000000000000..de9b84e28d88
--- /dev/null
+++ b/src/Security/SecKeychainSettings.cs
@@ -0,0 +1,50 @@
+#if __MACOS__
+#nullable enable
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+
+namespace Security {
+
+ /// Represents keychain settings for lock behavior on macOS.
+ [StructLayout (LayoutKind.Sequential)]
+ public struct SecKeychainSettings {
+ int /* UInt32 */ version;
+ byte /* Boolean */ lockOnSleep;
+ byte /* Boolean */ useLockInterval;
+ int /* UInt32 */ lockInterval;
+
+ /// Gets or sets the version of this settings structure.
+ public int Version {
+ get => version;
+ set => version = value;
+ }
+
+ /// Gets or sets whether the keychain locks when the system sleeps.
+ public bool LockOnSleep {
+ get => lockOnSleep != 0;
+ set => lockOnSleep = value ? (byte) 1 : (byte) 0;
+ }
+
+ /// Gets or sets whether the lock interval is used.
+ public bool UseLockInterval {
+ get => useLockInterval != 0;
+ set => useLockInterval = value ? (byte) 1 : (byte) 0;
+ }
+
+ /// Gets or sets the number of seconds before the keychain auto-locks.
+ public int LockInterval {
+ get => lockInterval;
+ set => lockInterval = value;
+ }
+
+ /// Creates a new with the current version.
+ /// A new initialized with version 1.
+ public static SecKeychainSettings Create ()
+ {
+ return new SecKeychainSettings { version = 1 };
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/src/SecurityInterface/AuthorizationCallbacks.cs b/src/SecurityInterface/AuthorizationCallbacks.cs
new file mode 100644
index 000000000000..2a70ffc76945
--- /dev/null
+++ b/src/SecurityInterface/AuthorizationCallbacks.cs
@@ -0,0 +1,262 @@
+#nullable enable
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Text;
+using Foundation;
+using ObjCRuntime;
+using Security;
+
+namespace SecurityInterface {
+
+ /// Specifies the result of an authorization operation.
+ [SupportedOSPlatform ("macos")]
+ public enum AuthorizationResult : uint {
+ /// The authorization was granted.
+ Allow = 0,
+ /// The authorization was denied.
+ Deny = 1,
+ /// The result is undefined.
+ Undefined = 2,
+ /// The user cancelled the authorization.
+ UserCanceled = 3,
+ }
+
+ /// Flags that describe properties of an authorization context value.
+ [SupportedOSPlatform ("macos")]
+ [Flags]
+ public enum AuthorizationContextFlags : uint {
+ /// The value can be extracted by the client.
+ Extractable = 1 << 0,
+ /// The value is volatile and should not be persisted.
+ Volatile = 1 << 1,
+ /// The value is sticky and persists across mechanism evaluations.
+ Sticky = 1 << 2,
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ unsafe struct AuthorizationValueNative {
+ public nuint Length;
+ public void* Data;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ unsafe struct AuthorizationValueVectorNative {
+ public uint Count;
+ public AuthorizationValueNative* Values;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ unsafe struct AuthorizationCallbacksNative {
+ public uint Version;
+ public delegate* unmanaged SetResult;
+ public delegate* unmanaged RequestInterrupt;
+ public delegate* unmanaged DidDeactivate;
+ public delegate* unmanaged GetContextValue;
+ public delegate* unmanaged SetContextValue;
+ public delegate* unmanaged GetHintValue;
+ public delegate* unmanaged SetHintValue;
+ public delegate* unmanaged GetArguments;
+ public delegate* unmanaged GetSessionId;
+ public delegate* unmanaged GetImmutableHintValue;
+ public delegate* unmanaged GetLAContext;
+ public delegate* unmanaged GetTokenIdentities;
+ public delegate* unmanaged GetTKTokenWatcher;
+ public delegate* unmanaged RemoveHintValue;
+ public delegate* unmanaged RemoveContextValue;
+ }
+
+ /// Wraps the native AuthorizationCallbacks structure provided by the authorization engine host for communicating with the Security Server.
+ [SupportedOSPlatform ("macos")]
+ public unsafe sealed class AuthorizationCallbacks : INativeObject {
+ readonly NativeHandle handle;
+
+ /// Creates an from a native callbacks pointer.
+ /// The pointer to the native AuthorizationCallbacks structure.
+ public AuthorizationCallbacks (NativeHandle handle)
+ {
+ this.handle = handle;
+ }
+
+ /// Gets the native handle for this callbacks structure.
+ public NativeHandle Handle => handle;
+
+ internal static AuthorizationCallbacks? Create (NativeHandle handle)
+ {
+ if (handle == NativeHandle.Zero)
+ return null;
+ return new AuthorizationCallbacks (handle);
+ }
+
+ AuthorizationCallbacksNative* Native {
+ get {
+ if (handle == NativeHandle.Zero)
+ throw new ObjectDisposedException (nameof (AuthorizationCallbacks));
+ return (AuthorizationCallbacksNative*) handle;
+ }
+ }
+
+ /// Gets the version of the callbacks structure.
+ public uint Version => Native->Version;
+
+ static byte [] ToNullTerminatedUtf8 (string value)
+ {
+ var utf8 = Encoding.UTF8.GetBytes (value);
+ var rv = new byte [utf8.Length + 1];
+ Buffer.BlockCopy (utf8, 0, rv, 0, utf8.Length);
+ return rv;
+ }
+
+ static byte []? CopyValue (AuthorizationValueNative* value)
+ {
+ if (value is null || value->Length == 0)
+ return null;
+ var length = checked((int) value->Length);
+ var rv = new byte [length];
+ Marshal.Copy ((IntPtr) value->Data, rv, 0, length);
+ return rv;
+ }
+
+ /// Sets the result of the current authorization evaluation.
+ /// The authorization engine.
+ /// The authorization result.
+ /// An OSStatus code; 0 on success.
+ public int SetResult (AuthorizationEngine engine, AuthorizationResult result)
+ {
+ var rv = Native->SetResult (engine.GetNonNullHandle (nameof (engine)), result);
+ GC.KeepAlive (engine);
+ return rv;
+ }
+
+ /// Requests an interrupt of the current authorization evaluation.
+ /// The authorization engine.
+ /// An OSStatus code; 0 on success.
+ public int RequestInterrupt (AuthorizationEngine engine)
+ {
+ var rv = Native->RequestInterrupt (engine.GetNonNullHandle (nameof (engine)));
+ GC.KeepAlive (engine);
+ return rv;
+ }
+
+ /// Notifies the engine that the mechanism has deactivated.
+ /// The authorization engine.
+ /// An OSStatus code; 0 on success.
+ public int DidDeactivate (AuthorizationEngine engine)
+ {
+ var rv = Native->DidDeactivate (engine.GetNonNullHandle (nameof (engine)));
+ GC.KeepAlive (engine);
+ return rv;
+ }
+
+ /// Gets a context value for the specified key.
+ /// The authorization engine.
+ /// The context key name.
+ /// On return, the flags associated with the context value.
+ /// On return, the context value as a byte array, or if not found.
+ /// An OSStatus code; 0 on success.
+ public int GetContextValue (AuthorizationEngine engine, string key, out AuthorizationContextFlags contextFlags, out byte []? value)
+ {
+ if (key is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (key));
+ fixed (byte* keyPtr = ToNullTerminatedUtf8 (key)) {
+ AuthorizationContextFlags flags = default;
+ AuthorizationValueNative* nativeValue = null;
+ var rv = Native->GetContextValue (engine.GetNonNullHandle (nameof (engine)), (IntPtr) keyPtr, &flags, &nativeValue);
+ contextFlags = flags;
+ value = rv == 0 ? CopyValue (nativeValue) : null;
+ GC.KeepAlive (engine);
+ return rv;
+ }
+ }
+
+ /// Sets a context value for the specified key.
+ /// The authorization engine.
+ /// The context key name.
+ /// The flags to associate with the value.
+ /// The value to set.
+ /// An OSStatus code; 0 on success.
+ public int SetContextValue (AuthorizationEngine engine, string key, AuthorizationContextFlags contextFlags, byte [] value)
+ {
+ if (key is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (key));
+ if (value is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (value));
+ fixed (byte* keyPtr = ToNullTerminatedUtf8 (key))
+ fixed (byte* valuePtr = value) {
+ var nativeValue = new AuthorizationValueNative { Length = (nuint) value.Length, Data = valuePtr };
+ var rv = Native->SetContextValue (engine.GetNonNullHandle (nameof (engine)), (IntPtr) keyPtr, contextFlags, &nativeValue);
+ GC.KeepAlive (engine);
+ return rv;
+ }
+ }
+
+ /// Gets a hint value for the specified key.
+ /// The authorization engine.
+ /// The hint key name.
+ /// On return, the hint value as a byte array, or if not found.
+ /// An OSStatus code; 0 on success.
+ public int GetHintValue (AuthorizationEngine engine, string key, out byte []? value)
+ {
+ if (key is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (key));
+ fixed (byte* keyPtr = ToNullTerminatedUtf8 (key)) {
+ AuthorizationValueNative* nativeValue = null;
+ var rv = Native->GetHintValue (engine.GetNonNullHandle (nameof (engine)), (IntPtr) keyPtr, &nativeValue);
+ value = rv == 0 ? CopyValue (nativeValue) : null;
+ GC.KeepAlive (engine);
+ return rv;
+ }
+ }
+
+ /// Sets a hint value for the specified key.
+ /// The authorization engine.
+ /// The hint key name.
+ /// The value to set.
+ /// An OSStatus code; 0 on success.
+ public int SetHintValue (AuthorizationEngine engine, string key, byte [] value)
+ {
+ if (key is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (key));
+ if (value is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (value));
+ fixed (byte* keyPtr = ToNullTerminatedUtf8 (key))
+ fixed (byte* valuePtr = value) {
+ var nativeValue = new AuthorizationValueNative { Length = (nuint) value.Length, Data = valuePtr };
+ var rv = Native->SetHintValue (engine.GetNonNullHandle (nameof (engine)), (IntPtr) keyPtr, &nativeValue);
+ GC.KeepAlive (engine);
+ return rv;
+ }
+ }
+
+ /// Removes a hint value for the specified key.
+ /// The authorization engine.
+ /// The hint key name to remove.
+ /// An OSStatus code; 0 on success.
+ public int RemoveHintValue (AuthorizationEngine engine, string key)
+ {
+ if (key is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (key));
+ fixed (byte* keyPtr = ToNullTerminatedUtf8 (key)) {
+ var rv = Native->RemoveHintValue (engine.GetNonNullHandle (nameof (engine)), (IntPtr) keyPtr);
+ GC.KeepAlive (engine);
+ return rv;
+ }
+ }
+
+ /// Removes a context value for the specified key.
+ /// The authorization engine.
+ /// The context key name to remove.
+ /// An OSStatus code; 0 on success.
+ public int RemoveContextValue (AuthorizationEngine engine, string key)
+ {
+ if (key is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (key));
+ fixed (byte* keyPtr = ToNullTerminatedUtf8 (key)) {
+ var rv = Native->RemoveContextValue (engine.GetNonNullHandle (nameof (engine)), (IntPtr) keyPtr);
+ GC.KeepAlive (engine);
+ return rv;
+ }
+ }
+ }
+}
diff --git a/src/SecurityInterface/AuthorizationRights.cs b/src/SecurityInterface/AuthorizationRights.cs
new file mode 100644
index 000000000000..b733e676e744
--- /dev/null
+++ b/src/SecurityInterface/AuthorizationRights.cs
@@ -0,0 +1,217 @@
+#nullable enable
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Text;
+using ObjCRuntime;
+
+namespace SecurityInterface {
+
+ /// Represents a single authorization right with a name, optional value, and flags.
+ [SupportedOSPlatform ("macos")]
+ public readonly struct AuthorizationRight {
+ readonly byte []? value;
+
+ /// Gets the name of the authorization right.
+ public string Name { get; }
+
+ /// Gets the flags associated with this right.
+ public uint Flags { get; }
+
+ /// Gets a copy of the value data, or if no value is set.
+ public byte []? Value => value is null ? null : (byte []) value.Clone ();
+
+ /// Creates a new authorization right with the specified name, optional value, and flags.
+ /// The authorization right name.
+ /// The optional value data.
+ /// The flags for this right.
+ public AuthorizationRight (string name, byte []? value = null, uint flags = 0)
+ {
+ if (name is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (name));
+ Name = name;
+ this.value = value is null ? null : (byte []) value.Clone ();
+ Flags = flags;
+ }
+
+ internal byte []? GetRawValue () => value;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ unsafe struct AuthorizationItemNative {
+ public IntPtr Name;
+ public nuint ValueLength;
+ public IntPtr Value;
+ public uint Flags;
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ unsafe struct AuthorizationRightsNative {
+ public uint Count;
+ public AuthorizationItemNative* Items;
+ }
+
+ /// Represents a set of authorization rights used to configure an .
+ [SupportedOSPlatform ("macos")]
+ public unsafe sealed class AuthorizationRights : IDisposable, INativeObject, IReadOnlyList {
+ NativeHandle handle;
+ readonly AuthorizationRight [] items;
+
+ /// Creates a new authorization rights set from the specified rights.
+ /// The authorization rights to include.
+ public AuthorizationRights (params AuthorizationRight [] items)
+ : this ((IEnumerable) items)
+ {
+ }
+
+ /// Creates a new authorization rights set from the specified right names.
+ /// The authorization right names.
+ public AuthorizationRights (params string [] rights)
+ {
+ if (rights is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (rights));
+ items = new AuthorizationRight [rights.Length];
+ for (int i = 0; i < rights.Length; i++)
+ items [i] = new AuthorizationRight (rights [i]);
+ AllocateNative ();
+ }
+
+ /// Creates a new authorization rights set from the specified rights.
+ /// The authorization rights to include.
+ public AuthorizationRights (IEnumerable items)
+ {
+ if (items is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (items));
+ var list = new List ();
+ foreach (var item in items)
+ list.Add (new AuthorizationRight (item.Name, item.GetRawValue (), item.Flags));
+ this.items = list.ToArray ();
+ AllocateNative ();
+ }
+
+ AuthorizationRights (AuthorizationRight [] items, bool noCopy)
+ {
+ this.items = items;
+ AllocateNative ();
+ }
+
+ ~AuthorizationRights ()
+ {
+ Dispose (false);
+ }
+
+ /// Gets the native handle to the AuthorizationRights structure.
+ public NativeHandle Handle => handle;
+
+ /// Gets the number of rights in this set.
+ public int Count => items.Length;
+
+ /// Gets the authorization right at the specified index.
+ /// The zero-based index.
+ public AuthorizationRight this [int index] => items [index];
+
+ /// Returns an enumerator that iterates through the authorization rights.
+ public IEnumerator GetEnumerator () => ((IEnumerable) items).GetEnumerator ();
+
+ IEnumerator IEnumerable.GetEnumerator () => items.GetEnumerator ();
+
+ /// Creates an by reading from a native AuthorizationRights pointer.
+ /// The pointer to the native AuthorizationRights structure, or zero for .
+ /// A new managed rights set cloned from the native data, or if the handle is zero.
+ public static AuthorizationRights? FromHandle (NativeHandle handle)
+ {
+ if (handle == NativeHandle.Zero)
+ return null;
+
+ var native = (AuthorizationRightsNative*) handle;
+ var managedItems = new AuthorizationRight [native->Count];
+
+ for (int i = 0; i < native->Count; i++) {
+ var item = native->Items [i];
+ var name = Marshal.PtrToStringUTF8 (item.Name)!;
+ byte []? value = null;
+
+ if (item.ValueLength != 0) {
+ var length = checked((int) item.ValueLength);
+ value = new byte [length];
+ Marshal.Copy (item.Value, value, 0, length);
+ }
+
+ managedItems [i] = new AuthorizationRight (name, value, item.Flags);
+ }
+
+ return new AuthorizationRights (managedItems, noCopy: true);
+ }
+
+ void AllocateNative ()
+ {
+ handle = Marshal.AllocHGlobal (sizeof (AuthorizationRightsNative));
+ var native = (AuthorizationRightsNative*) handle;
+ native->Count = (uint) items.Length;
+
+ if (items.Length == 0) {
+ native->Items = null;
+ return;
+ }
+
+ native->Items = (AuthorizationItemNative*) Marshal.AllocHGlobal (sizeof (AuthorizationItemNative) * items.Length);
+
+ for (int i = 0; i < items.Length; i++) {
+ var item = items [i];
+ var value = item.GetRawValue ();
+ native->Items [i] = new AuthorizationItemNative {
+ Name = StringToUtf8 (item.Name),
+ ValueLength = value is null ? 0 : (nuint) value.Length,
+ Value = value is null || value.Length == 0 ? IntPtr.Zero : BytesToHGlobal (value),
+ Flags = item.Flags,
+ };
+ }
+ }
+
+ static IntPtr StringToUtf8 (string value)
+ {
+ var bytes = Encoding.UTF8.GetBytes (value);
+ var ptr = Marshal.AllocHGlobal (bytes.Length + 1);
+ Marshal.Copy (bytes, 0, ptr, bytes.Length);
+ Marshal.WriteByte (ptr, bytes.Length, 0);
+ return ptr;
+ }
+
+ static IntPtr BytesToHGlobal (byte [] value)
+ {
+ var ptr = Marshal.AllocHGlobal (value.Length);
+ Marshal.Copy (value, 0, ptr, value.Length);
+ return ptr;
+ }
+
+ /// Releases all unmanaged memory associated with this rights set.
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ void Dispose (bool disposing)
+ {
+ if (handle == NativeHandle.Zero)
+ return;
+
+ var native = (AuthorizationRightsNative*) handle;
+ if (native->Items is not null) {
+ for (int i = 0; i < native->Count; i++) {
+ if (native->Items [i].Name != IntPtr.Zero)
+ Marshal.FreeHGlobal (native->Items [i].Name);
+ if (native->Items [i].Value != IntPtr.Zero)
+ Marshal.FreeHGlobal (native->Items [i].Value);
+ }
+ Marshal.FreeHGlobal ((IntPtr) native->Items);
+ }
+
+ Marshal.FreeHGlobal (handle);
+ handle = NativeHandle.Zero;
+ }
+ }
+}
diff --git a/src/SecurityInterface/Enums.cs b/src/SecurityInterface/Enums.cs
new file mode 100644
index 000000000000..5299c733278c
--- /dev/null
+++ b/src/SecurityInterface/Enums.cs
@@ -0,0 +1,43 @@
+#nullable enable
+
+using System;
+using System.Runtime.Versioning;
+using ObjCRuntime;
+
+namespace SecurityInterface {
+
+ /// Defines the authorization states of an .
+ [SupportedOSPlatform ("macos")]
+ public enum SFAuthorizationViewState : int {
+ /// The initial state before the first status update.
+ Startup = 0,
+ /// The view is locked, indicating the user is not authorized.
+ Locked,
+ /// An authorization operation is in progress.
+ InProgress,
+ /// The view is unlocked, indicating the user is authorized.
+ Unlocked,
+ }
+
+ /// Identifies button types in an authorization plugin view.
+ [SupportedOSPlatform ("macos")]
+ public enum SFButtonType : int {
+ /// The cancel button.
+ Cancel = 0,
+ /// The OK button.
+ Ok = 1,
+ /// The back button. This has the same value as .
+ Back = 0,
+ /// The login button. This has the same value as .
+ Login = 1,
+ }
+
+ /// Specifies the type of view requested from an authorization plugin view.
+ [SupportedOSPlatform ("macos")]
+ public enum SFViewType : int {
+ /// A view showing both identity and credentials fields.
+ IdentityAndCredentials = 0,
+ /// A view showing only credentials fields.
+ Credentials,
+ }
+}
diff --git a/src/SecurityInterface/SFAuthorizationPluginView.cs b/src/SecurityInterface/SFAuthorizationPluginView.cs
new file mode 100644
index 000000000000..6ed2efc72b46
--- /dev/null
+++ b/src/SecurityInterface/SFAuthorizationPluginView.cs
@@ -0,0 +1,30 @@
+#nullable enable
+
+using System;
+using Foundation;
+using ObjCRuntime;
+using Security;
+
+namespace SecurityInterface {
+
+ public partial class SFAuthorizationPluginView {
+
+ /// Initializes the view with the authorization callbacks and engine reference provided by the plugin host.
+ /// The authorization callbacks for communicating with the Security Server.
+ /// The authorization engine reference.
+ public SFAuthorizationPluginView (AuthorizationCallbacks callbacks, AuthorizationEngine engineRef)
+ : base (NSObjectFlag.Empty)
+ {
+ if (callbacks is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (callbacks));
+ if (engineRef is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (engineRef));
+ InitializeHandle (_InitWithCallbacks (callbacks.Handle, engineRef), "initWithCallbacks:andEngineRef:");
+ GC.KeepAlive (callbacks);
+ GC.KeepAlive (engineRef);
+ }
+
+ /// Gets the authorization callbacks structure for communicating with the Security Server.
+ public AuthorizationCallbacks? Callbacks => AuthorizationCallbacks.Create (_Callbacks);
+ }
+}
diff --git a/src/SecurityInterface/SFAuthorizationView.cs b/src/SecurityInterface/SFAuthorizationView.cs
new file mode 100644
index 000000000000..e0f2a2d9d188
--- /dev/null
+++ b/src/SecurityInterface/SFAuthorizationView.cs
@@ -0,0 +1,30 @@
+#nullable enable
+
+using System;
+using ObjCRuntime;
+
+namespace SecurityInterface {
+
+ /// A view that displays a lock icon for controlling access to a privileged operation.
+ public partial class SFAuthorizationView {
+
+ /// Sets the authorization right string to check for.
+ /// The authorization right name as a UTF-8 string.
+ public void SetAuthorizationString (string authorizationString)
+ {
+ if (authorizationString is null)
+ ThrowHelper.ThrowArgumentNullException (nameof (authorizationString));
+ using var str = new TransientString (authorizationString);
+ _SetAuthorizationString (str);
+ }
+
+ /// Gets or sets the authorization rights to check for.
+ public AuthorizationRights? AuthorizationRightsSet {
+ get => AuthorizationRights.FromHandle (_AuthorizationRights);
+ set {
+ _SetAuthorizationRights (value?.Handle ?? NativeHandle.Zero);
+ GC.KeepAlive (value);
+ }
+ }
+ }
+}
diff --git a/src/bgen/Caches/TypeCache.cs b/src/bgen/Caches/TypeCache.cs
index c6dba9daf63f..289603c814bf 100644
--- a/src/bgen/Caches/TypeCache.cs
+++ b/src/bgen/Caches/TypeCache.cs
@@ -74,8 +74,11 @@ public class TypeCache {
public Type SCNVector3 { get; }
public Type SCNVector4 { get; }
public Type SecAccessControl { get; }
+ public Type? AuthorizationEngine { get; }
+ public Type SecCertificate { get; }
public Type SecIdentity { get; }
public Type SecKey { get; }
+ public Type? SecKeychain { get; }
public Type SecTrust { get; }
public Type SecProtocolMetadata { get; }
public Type SecProtocolOptions { get; }
@@ -235,6 +238,11 @@ public TypeCache (MetadataLoadContext universe, Frameworks frameworks, PlatformN
SCNVector4 = Lookup (platformAssembly, "SceneKit", "SCNVector4");
SCNMatrix4 = Lookup (platformAssembly, "SceneKit", "SCNMatrix4");
SecAccessControl = Lookup (platformAssembly, "Security", "SecAccessControl");
+ if (frameworks.HaveSecurityInterface) {
+ AuthorizationEngine = ConditionalLookup (platformAssembly, "Security", "AuthorizationEngine");
+ SecKeychain = ConditionalLookup (platformAssembly, "Security", "SecKeychain");
+ }
+ SecCertificate = Lookup (platformAssembly, "Security", "SecCertificate");
SecIdentity = Lookup (platformAssembly, "Security", "SecIdentity");
SecKey = Lookup (platformAssembly, "Security", "SecKey");
SecTrust = Lookup (platformAssembly, "Security", "SecTrust");
diff --git a/src/bgen/Models/MarshalTypeList.cs b/src/bgen/Models/MarshalTypeList.cs
index c1ef12e548f2..587f99f978a7 100644
--- a/src/bgen/Models/MarshalTypeList.cs
+++ b/src/bgen/Models/MarshalTypeList.cs
@@ -71,6 +71,11 @@ public void Load (TypeCache typeCache, Frameworks frameworks)
Add (typeCache.AudioUnit);
Add (typeCache.SecIdentity);
Add (typeCache.SecIdentity2);
+ if (typeCache.AuthorizationEngine is not null)
+ Add (typeCache.AuthorizationEngine);
+ Add (typeCache.SecCertificate);
+ if (typeCache.SecKeychain is not null)
+ Add (typeCache.SecKeychain);
Add (typeCache.SecKey);
Add (typeCache.SecTrust);
Add (typeCache.SecTrust2);
diff --git a/src/build/dotnet/generator-frameworks.g.cs b/src/build/dotnet/generator-frameworks.g.cs
index 9346b0afb5e1..67f777b38d76 100644
--- a/src/build/dotnet/generator-frameworks.g.cs
+++ b/src/build/dotnet/generator-frameworks.g.cs
@@ -274,6 +274,7 @@ partial class Frameworks {
"ScriptingBridge",
"SearchKit",
"Security",
+ "SecurityInterface",
"SecurityUI",
"SensitiveContentAnalysis",
"ServiceManagement",
@@ -672,6 +673,7 @@ partial class Frameworks {
bool? _ScriptingBridge;
bool? _SearchKit;
bool? _Security;
+ bool? _SecurityInterface;
bool? _SecurityUI;
bool? _SensitiveContentAnalysis;
bool? _SensorKit;
@@ -846,6 +848,7 @@ partial class Frameworks {
public bool HaveScriptingBridge { get { if (!_ScriptingBridge.HasValue) _ScriptingBridge = GetValue ("ScriptingBridge"); return _ScriptingBridge.Value; } }
public bool HaveSearchKit { get { if (!_SearchKit.HasValue) _SearchKit = GetValue ("SearchKit"); return _SearchKit.Value; } }
public bool HaveSecurity { get { if (!_Security.HasValue) _Security = GetValue ("Security"); return _Security.Value; } }
+ public bool HaveSecurityInterface { get { if (!_SecurityInterface.HasValue) _SecurityInterface = GetValue ("SecurityInterface"); return _SecurityInterface.Value; } }
public bool HaveSecurityUI { get { if (!_SecurityUI.HasValue) _SecurityUI = GetValue ("SecurityUI"); return _SecurityUI.Value; } }
public bool HaveSensitiveContentAnalysis { get { if (!_SensitiveContentAnalysis.HasValue) _SensitiveContentAnalysis = GetValue ("SensitiveContentAnalysis"); return _SensitiveContentAnalysis.Value; } }
public bool HaveSensorKit { get { if (!_SensorKit.HasValue) _SensorKit = GetValue ("SensorKit"); return _SensorKit.Value; } }
diff --git a/src/frameworks.sources b/src/frameworks.sources
index a8254313ba3f..9222cbe031bf 100644
--- a/src/frameworks.sources
+++ b/src/frameworks.sources
@@ -1571,8 +1571,11 @@ SECURITY_API_SOURCES = \
Security/SecureTransport.cs \
SECURITY_CORE_SOURCES = \
+ Security/AuthorizationEngine.cs \
Security/Certificate.cs \
Security/SecAccessControl.cs \
+ Security/SecKeychain.cs \
+ Security/SecKeychainSettings.cs \
Security/SecProtocolMetadata.cs \
Security/SecProtocolOptions.cs \
Security/Trust.cs \
@@ -1593,6 +1596,17 @@ SECURITY_SOURCES = \
Security/SslConnection.cs \
Security/SslContext.cs \
+# SecurityInterface
+
+SECURITYINTERFACE_CORE_SOURCES = \
+ SecurityInterface/Enums.cs \
+
+SECURITYINTERFACE_SOURCES = \
+ SecurityInterface/AuthorizationCallbacks.cs \
+ SecurityInterface/AuthorizationRights.cs \
+ SecurityInterface/SFAuthorizationPluginView.cs \
+ SecurityInterface/SFAuthorizationView.cs \
+
# SensitiveContentAnalysis
SENSITIVECONTENTANALYSIS_SOURCES = \
@@ -2094,6 +2108,7 @@ MACOS_FRAMEWORKS = \
SensitiveContentAnalysis \
ServiceManagement \
Security \
+ SecurityInterface \
SecurityUI \
SharedWithYou \
SharedWithYouCore \
diff --git a/src/rsp/dotnet/macos-defines-dotnet.rsp b/src/rsp/dotnet/macos-defines-dotnet.rsp
index 17b1bd296208..2a7d3918a7f6 100644
--- a/src/rsp/dotnet/macos-defines-dotnet.rsp
+++ b/src/rsp/dotnet/macos-defines-dotnet.rsp
@@ -117,6 +117,7 @@
-d:HAS_SCRIPTINGBRIDGE
-d:HAS_SEARCHKIT
-d:HAS_SECURITY
+-d:HAS_SECURITYINTERFACE
-d:HAS_SECURITYUI
-d:HAS_SENSITIVECONTENTANALYSIS
-d:HAS_SERVICEMANAGEMENT
diff --git a/src/securityinterface.cs b/src/securityinterface.cs
new file mode 100644
index 000000000000..268dcbf8972f
--- /dev/null
+++ b/src/securityinterface.cs
@@ -0,0 +1,659 @@
+//
+// securityinterface.cs: Bindings for the SecurityInterface framework (macOS only)
+//
+// Copyright 2025 Microsoft Corp.
+//
+
+#nullable enable
+
+using System;
+using AppKit;
+using Foundation;
+using ObjCRuntime;
+using Security;
+
+namespace SecurityInterface {
+
+ /// Host view for authorization plugin mechanisms, subclassed to provide custom UI for the loginwindow authorization process.
+ [BaseType (typeof (NSObject))]
+ [DisableDefaultCtor]
+ interface SFAuthorizationPluginView {
+
+ [Internal]
+ [Export ("initWithCallbacks:andEngineRef:")]
+ NativeHandle _InitWithCallbacks (IntPtr callbacks, AuthorizationEngine engineRef);
+
+ /// Gets the authorization engine reference for communicating with the Security Server.
+ [Export ("engineRef")]
+ AuthorizationEngine EngineRef { get; }
+
+ [Internal]
+ [Export ("callbacks")]
+ IntPtr _Callbacks { get; }
+
+ /// Called when the user presses a button in the UI.
+ /// The type of button that was pressed.
+ [Export ("buttonPressed:")]
+ void ButtonPressed (SFButtonType buttonType);
+
+ /// Returns the last error that occurred during the authorization process.
+ /// An describing the last error, or if no error occurred.
+ [Export ("lastError")]
+ [return: NullAllowed]
+ NSError GetLastError ();
+
+ /// Called after the view has been activated.
+ [Export ("didActivate")]
+ void DidActivate ();
+
+ /// Called before the view activates, providing a dictionary of user information.
+ /// A dictionary containing user information, or .
+ [Export ("willActivateWithUser:")]
+ void WillActivateWithUser ([NullAllowed] NSDictionary userInformation);
+
+ /// Called after the view has been deactivated.
+ [Export ("didDeactivate")]
+ void DidDeactivate ();
+
+ /// Returns the first view in the keyboard focus chain.
+ /// The first in the key view loop, or .
+ [Export ("firstKeyView")]
+ [return: NullAllowed]
+ NSView GetFirstKeyView ();
+
+ /// Returns the first responder for the view.
+ /// The first , or .
+ [Export ("firstResponder")]
+ [return: NullAllowed]
+ NSResponder GetFirstResponder ();
+
+ /// Returns the last view in the keyboard focus chain.
+ /// The last in the key view loop, or .
+ [Export ("lastKeyView")]
+ [return: NullAllowed]
+ NSView GetLastKeyView ();
+
+ /// Enables or disables the view.
+ /// to enable the view; to disable it.
+ [Export ("setEnabled:")]
+ void SetEnabled (bool enabled);
+
+ /// Returns the view for the specified view type.
+ /// The type of view to retrieve.
+ /// The for the specified type, or .
+ [Export ("viewForType:")]
+ [return: NullAllowed]
+ NSView GetView (SFViewType viewType);
+
+ /// Displays the authorization plugin view.
+ [Export ("displayView")]
+ void DisplayView ();
+
+ /// Enables or disables the specified button.
+ /// The button to enable or disable.
+ /// to enable the button; to disable it.
+ [Export ("setButton:enabled:")]
+ void SetButton (SFButtonType buttonType, bool enabled);
+
+ /// Updates the view to reflect current state.
+ [Export ("updateView")]
+ void UpdateView ();
+ }
+
+ /// Interface representing the protocol methods of .
+ interface ISFAuthorizationViewDelegate { }
+
+ /// Delegate methods for responding to authorization state changes in an .
+ [Protocol (IsInformal = true, BackwardsCompatibleCodeGeneration = false), Model]
+ [BaseType (typeof (NSObject))]
+ interface SFAuthorizationViewDelegate {
+
+ /// Called when the authorization view has been authorized.
+ /// The that was authorized.
+ [Export ("authorizationViewDidAuthorize:")]
+ void DidAuthorize (SFAuthorizationView view);
+
+ /// Called when the authorization view has been deauthorized.
+ /// The that was deauthorized.
+ [Export ("authorizationViewDidDeauthorize:")]
+ void DidDeauthorize (SFAuthorizationView view);
+
+ /// Called to determine whether the authorization view should deauthorize.
+ /// The requesting deauthorization.
+ /// to allow deauthorization; otherwise, .
+ [Export ("authorizationViewShouldDeauthorize:")]
+ bool ShouldDeauthorize (SFAuthorizationView view);
+
+ /// Called when the authorization view has created an authorization reference.
+ /// The that created the authorization.
+ [Export ("authorizationViewCreatedAuthorization:")]
+ void CreatedAuthorization (SFAuthorizationView view);
+
+ /// Called when the authorization view has released its authorization reference.
+ /// The that released the authorization.
+ [Export ("authorizationViewReleasedAuthorization:")]
+ void ReleasedAuthorization (SFAuthorizationView view);
+
+ /// Called when the authorization view has been hidden.
+ /// The that was hidden.
+ [Export ("authorizationViewDidHide:")]
+ void DidHide (SFAuthorizationView view);
+ }
+
+ /// A view that displays a lock icon for controlling access to a privileged operation.
+ [BaseType (typeof (NSView))]
+ interface SFAuthorizationView {
+
+ /// Initializes the view with the specified frame rectangle.
+ /// The frame rectangle for the view.
+ [Export ("initWithFrame:")]
+ NativeHandle Constructor (CoreGraphics.CGRect frameRect);
+
+ [Internal]
+ [Export ("setString:")]
+ void _SetAuthorizationString (IntPtr authorizationString);
+
+ [Internal]
+ [Export ("setAuthorizationRights:")]
+ void _SetAuthorizationRights (IntPtr authorizationRights);
+
+ [Internal]
+ [Export ("authorizationRights")]
+ IntPtr _AuthorizationRights { get; }
+
+ /// Gets the authorization object associated with this view, or if not yet authorized.
+ [Export ("authorization")]
+ [NullAllowed]
+ NSObject Authorization { get; }
+
+ /// Updates the authorization status and lock icon state.
+ /// The object that initiated the update, or .
+ /// if the status was updated successfully; otherwise, .
+ [Export ("updateStatus:")]
+ bool UpdateStatus ([NullAllowed] NSObject sender);
+
+ /// Enables or disables automatic status updates.
+ /// to enable auto-updating; to disable it.
+ [Export ("setAutoupdate:")]
+ void SetAutoupdate (bool autoupdate);
+
+ /// Enables or disables automatic status updates with a specified interval.
+ /// to enable auto-updating; to disable it.
+ /// The interval in seconds between automatic updates.
+ [Export ("setAutoupdate:interval:")]
+ void SetAutoupdate (bool autoupdate, double interval);
+
+ /// Gets the current authorization state of the view.
+ [Export ("authorizationState")]
+ SFAuthorizationViewState AuthorizationState { get; }
+
+ /// Enables or disables the view.
+ /// to enable the view; to disable it.
+ [Export ("setEnabled:")]
+ void SetEnabled (bool enabled);
+
+ /// Gets a value indicating whether the view is currently enabled.
+ [Export ("isEnabled")]
+ bool IsEnabled { get; }
+
+ /// Sets the authorization flags as a bitmask of AuthorizationFlags values.
+ /// A bitmask of authorization flag values.
+ [Export ("setFlags:")]
+ void SetFlags (int flags);
+
+ /// Gets or sets the weak delegate that receives authorization state change notifications.
+ [Export ("delegate", ArgumentSemantic.Weak)]
+ [NullAllowed]
+ NSObject WeakDelegate { get; set; }
+
+ /// Gets or sets the delegate that receives authorization state change notifications.
+ [Wrap ("WeakDelegate")]
+ [NullAllowed]
+ ISFAuthorizationViewDelegate Delegate { get; set; }
+
+ /// Attempts to authorize.
+ /// The object that initiated the authorization, or .
+ /// if authorization succeeded; otherwise, .
+ [Export ("authorize:")]
+ bool Authorize ([NullAllowed] NSObject sender);
+
+ /// Attempts to deauthorize.
+ /// The object that initiated the deauthorization, or .
+ /// if deauthorization succeeded; otherwise, .
+ [Export ("deauthorize:")]
+ bool Deauthorize ([NullAllowed] NSObject sender);
+ }
+
+ /// Interface representing the protocol methods of .
+ interface ISFCertificatePanelDelegate { }
+
+ /// Delegate methods for the .
+ [Protocol (IsInformal = true, BackwardsCompatibleCodeGeneration = false), Model]
+ [BaseType (typeof (NSObject))]
+ interface SFCertificatePanelDelegate {
+
+ /// Called when the user clicks the help button in the certificate panel.
+ /// The that sent the message.
+ /// if help was displayed; otherwise, .
+ [Export ("certificatePanelShowHelp:")]
+ bool ShowHelp (SFCertificatePanel sender);
+ }
+
+ /// A panel that displays one or more certificates, presented as a modal dialog or a sheet.
+ [BaseType (typeof (NSPanel))]
+ interface SFCertificatePanel {
+
+ /// Gets the shared certificate panel instance.
+ [Static]
+ [Export ("sharedCertificatePanel")]
+ SFCertificatePanel SharedCertificatePanel { get; }
+
+ /// Displays the panel modally for the specified object.
+ /// The object containing the certificates to display.
+ /// Whether to display the certificate group.
+ /// The button code that was pressed to dismiss the panel.
+ [Export ("runModalForTrust:showGroup:")]
+ nint RunModalForTrust (SecTrust trust, bool showGroup);
+
+ /// Displays the panel modally for the specified array of certificates.
+ /// An array of certificates to display.
+ /// Whether to display the certificate group.
+ /// The button code that was pressed to dismiss the panel.
+ [Export ("runModalForCertificates:showGroup:")]
+ nint RunModalForCertificates (NSArray certificates, bool showGroup);
+
+ /// Displays the panel as a sheet for the specified object.
+ /// The window to which the sheet is attached.
+ /// The delegate that receives the did-end callback, or .
+ /// The selector invoked when the sheet ends, or .
+ /// A pointer to context information passed to the callback.
+ /// The object containing the certificates to display.
+ /// Whether to display the certificate group.
+ [Export ("beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:trust:showGroup:")]
+ void BeginSheet (NSWindow docWindow, [NullAllowed] NSObject modalDelegate, [NullAllowed] Selector didEndSelector, IntPtr contextInfo, SecTrust trust, bool showGroup);
+
+ /// Displays the panel as a sheet for the specified array of certificates.
+ /// The window to which the sheet is attached.
+ /// The delegate that receives the did-end callback, or .
+ /// The selector invoked when the sheet ends, or .
+ /// A pointer to context information passed to the callback.
+ /// An array of certificates to display.
+ /// Whether to display the certificate group.
+ [Export ("beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:certificates:showGroup:")]
+ void BeginSheet (NSWindow docWindow, [NullAllowed] NSObject modalDelegate, [NullAllowed] Selector didEndSelector, IntPtr contextInfo, NSArray certificates, bool showGroup);
+
+ /// Sets the policies used to evaluate the certificates.
+ /// An of SecPolicy objects, a single SecPolicy, or .
+ [Export ("setPolicies:")]
+ void SetPolicies ([NullAllowed] NSObject policies);
+
+ /// Gets the policies used to evaluate the certificates.
+ [Export ("policies")]
+ NSArray Policies { get; }
+
+ /// Sets the title of the default button.
+ /// The button title, or to use the default title.
+ [Export ("setDefaultButtonTitle:")]
+ void SetDefaultButtonTitle ([NullAllowed] string title);
+
+ /// Sets the title of the alternate button.
+ /// The button title, or to hide the button.
+ [Export ("setAlternateButtonTitle:")]
+ void SetAlternateButtonTitle ([NullAllowed] string title);
+
+ /// Sets whether the panel shows a help button.
+ /// to show the help button; otherwise, .
+ [Export ("setShowsHelp:")]
+ void SetShowsHelp (bool showsHelp);
+
+ /// Gets a value indicating whether the panel shows a help button.
+ [Export ("showsHelp")]
+ bool ShowsHelp { get; }
+
+ /// Sets the help anchor string for the help button.
+ /// The help anchor string, or .
+ [Export ("setHelpAnchor:")]
+ void SetHelpAnchor ([NullAllowed] string anchor);
+
+ /// Gets the help anchor string.
+ [Export ("helpAnchor")]
+ [NullAllowed]
+ string HelpAnchor { get; }
+
+ /// Gets the used to display certificate details.
+ [Export ("certificateView")]
+ SFCertificateView CertificateView { get; }
+ }
+
+ /// A panel for making trust decisions about certificates that cannot be verified.
+ [BaseType (typeof (SFCertificatePanel))]
+ interface SFCertificateTrustPanel {
+
+ /// Gets the shared certificate trust panel instance.
+ [Static]
+ [Export ("sharedCertificateTrustPanel")]
+ SFCertificateTrustPanel SharedCertificateTrustPanel { get; }
+
+ /// Displays the panel modally for the specified object with a descriptive message.
+ /// The object to evaluate.
+ /// A message to display in the panel, or .
+ /// The button code that was pressed to dismiss the panel.
+ [Export ("runModalForTrust:message:")]
+ nint RunModalForTrust (SecTrust trust, [NullAllowed] string message);
+
+ /// Displays the panel as a sheet for the specified object with a message.
+ /// The window to which the sheet is attached.
+ /// The delegate that receives the did-end callback, or .
+ /// The selector invoked when the sheet ends, or .
+ /// A pointer to context information passed to the callback.
+ /// The object to evaluate.
+ /// A message to display in the panel, or .
+ [Export ("beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:trust:message:")]
+ void BeginSheet (NSWindow docWindow, [NullAllowed] NSObject modalDelegate, [NullAllowed] Selector didEndSelector, IntPtr contextInfo, SecTrust trust, [NullAllowed] string message);
+
+ /// Sets the informative text displayed in the panel.
+ /// The informative text string, or .
+ [Export ("setInformativeText:")]
+ void SetInformativeText ([NullAllowed] string informativeText);
+
+ /// Gets the informative text displayed in the panel.
+ [Export ("informativeText")]
+ [NullAllowed]
+ string InformativeText { get; }
+ }
+
+ /// A view that displays the contents of a certificate, with support for disclosable details and trust editing.
+ [BaseType (typeof (NSVisualEffectView))]
+ interface SFCertificateView {
+
+ /// Initializes the view with the specified frame rectangle.
+ /// The frame rectangle for the view.
+ [Export ("initWithFrame:")]
+ NativeHandle Constructor (CoreGraphics.CGRect frameRect);
+
+ /// Sets the certificate to display.
+ /// The to display, or to clear.
+ [Export ("setCertificate:")]
+ void SetCertificate ([NullAllowed] SecCertificate certificate);
+
+ /// Gets the currently displayed certificate.
+ /// The being displayed, or .
+ [Export ("certificate")]
+ [return: NullAllowed]
+ SecCertificate GetCertificate ();
+
+ /// Sets the policies used to evaluate the certificate trust.
+ /// An of SecPolicy objects, a single SecPolicy, or .
+ [Export ("setPolicies:")]
+ void SetPolicies ([NullAllowed] NSObject policies);
+
+ /// Gets the policies used for trust evaluation.
+ [Export ("policies")]
+ NSArray Policies { get; }
+
+ /// Sets whether the user can edit the trust settings.
+ /// to allow trust editing; otherwise, .
+ [Export ("setEditableTrust:")]
+ void SetEditableTrust (bool editable);
+
+ /// Gets a value indicating whether the trust settings are editable.
+ [Export ("isEditable")]
+ bool IsEditable { get; }
+
+ /// Sets whether trust information is displayed.
+ /// to show trust information; otherwise, .
+ [Export ("setDisplayTrust:")]
+ void SetDisplayTrust (bool display);
+
+ /// Gets a value indicating whether trust information is currently displayed.
+ [Export ("isTrustDisplayed")]
+ bool IsTrustDisplayed { get; }
+
+ /// Saves the current trust settings to the user's trust database.
+ [Export ("saveTrustSettings")]
+ void SaveTrustSettings ();
+
+ /// Sets whether certificate details are displayed.
+ /// to show certificate details; otherwise, .
+ [Export ("setDisplayDetails:")]
+ void SetDisplayDetails (bool display);
+
+ /// Gets a value indicating whether certificate details are displayed.
+ [Export ("detailsDisplayed")]
+ bool DetailsDisplayed { get; }
+
+ /// Sets whether the details section is disclosed (expanded).
+ /// to expand the details section; otherwise, .
+ [Export ("setDetailsDisclosed:")]
+ void SetDetailsDisclosed (bool disclosed);
+
+ /// Gets a value indicating whether the details section is disclosed.
+ [Export ("detailsDisclosed")]
+ bool DetailsDisclosed { get; }
+
+ /// Sets whether the policies section is disclosed (expanded).
+ /// to expand the policies section; otherwise, .
+ [Export ("setPoliciesDisclosed:")]
+ void SetPoliciesDisclosed (bool disclosed);
+
+ /// Gets a value indicating whether the policies section is disclosed.
+ [Export ("policiesDisclosed")]
+ bool PoliciesDisclosed { get; }
+
+ /// Notification posted when the disclosure state of details or policies changes.
+ [Notification]
+ [Field ("SFCertificateViewDisclosureStateDidChange")]
+ NSString DisclosureStateDidChangeNotification { get; }
+ }
+
+ /// Interface representing the protocol methods of .
+ interface ISFChooseIdentityPanelDelegate { }
+
+ /// Delegate methods for the .
+ [Protocol (IsInformal = true, BackwardsCompatibleCodeGeneration = false), Model]
+ [BaseType (typeof (NSObject))]
+ interface SFChooseIdentityPanelDelegate {
+
+ /// Called when the user clicks the help button in the choose identity panel.
+ /// The that sent the message.
+ /// if help was displayed; otherwise, .
+ [Export ("chooseIdentityPanelShowHelp:")]
+ bool ShowHelp (SFChooseIdentityPanel sender);
+ }
+
+ /// A panel that lets the user choose a digital identity (certificate and private key pair) from a list.
+ [BaseType (typeof (NSPanel))]
+ interface SFChooseIdentityPanel {
+
+ /// Gets the shared choose identity panel instance.
+ [Static]
+ [Export ("sharedChooseIdentityPanel")]
+ SFChooseIdentityPanel SharedChooseIdentityPanel { get; }
+
+ /// Displays the panel modally with the specified array of identities and a message.
+ /// An array of objects to display.
+ /// A message to display in the panel, or .
+ /// The button code that was pressed to dismiss the panel.
+ [Export ("runModalForIdentities:message:")]
+ nint RunModalForIdentities (NSArray identities, [NullAllowed] string message);
+
+ /// Displays the panel as a sheet with the specified identities and message.
+ /// The window to which the sheet is attached.
+ /// The delegate that receives the did-end callback, or .
+ /// The selector invoked when the sheet ends, or .
+ /// A pointer to context information passed to the callback.
+ /// An array of objects to display.
+ /// A message to display in the panel, or .
+ [Export ("beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:identities:message:")]
+ void BeginSheet (NSWindow docWindow, [NullAllowed] NSObject modalDelegate, [NullAllowed] Selector didEndSelector, IntPtr contextInfo, NSArray identities, [NullAllowed] string message);
+
+ /// Gets the identity that the user chose from the list.
+ [Export ("identity")]
+ [NullAllowed]
+ SecIdentity Identity { get; }
+
+ /// Sets the policies used to evaluate the identities.
+ /// An of SecPolicy objects, a single SecPolicy, or .
+ [Export ("setPolicies:")]
+ void SetPolicies ([NullAllowed] NSObject policies);
+
+ /// Gets the policies used to evaluate the identities.
+ [Export ("policies")]
+ NSArray Policies { get; }
+
+ /// Sets the title of the default button.
+ /// The button title, or to use the default title.
+ [Export ("setDefaultButtonTitle:")]
+ void SetDefaultButtonTitle ([NullAllowed] string title);
+
+ /// Sets the title of the alternate button.
+ /// The button title, or to hide the button.
+ [Export ("setAlternateButtonTitle:")]
+ void SetAlternateButtonTitle ([NullAllowed] string title);
+
+ /// Sets whether the panel shows a help button.
+ /// to show the help button; otherwise, .
+ [Export ("setShowsHelp:")]
+ void SetShowsHelp (bool showsHelp);
+
+ /// Gets a value indicating whether the panel shows a help button.
+ [Export ("showsHelp")]
+ bool ShowsHelp { get; }
+
+ /// Sets the help anchor string for the help button.
+ /// The help anchor string, or .
+ [Export ("setHelpAnchor:")]
+ void SetHelpAnchor ([NullAllowed] string anchor);
+
+ /// Gets the help anchor string.
+ [Export ("helpAnchor")]
+ [NullAllowed]
+ string HelpAnchor { get; }
+
+ /// Sets the informative text displayed in the panel.
+ /// The informative text string, or .
+ [Export ("setInformativeText:")]
+ void SetInformativeText ([NullAllowed] string informativeText);
+
+ /// Gets the informative text displayed in the panel.
+ [Export ("informativeText")]
+ [NullAllowed]
+ string InformativeText { get; }
+
+ /// Sets the domain string used to filter identities.
+ /// The domain string, or .
+ [Export ("setDomain:")]
+ void SetDomain ([NullAllowed] string domainString);
+
+ /// Gets the domain string used to filter identities.
+ [Export ("domain")]
+ [NullAllowed]
+ string Domain { get; }
+ }
+
+ /// A table cell view used in the identity chooser panel to display identity and issuer information.
+ [BaseType (typeof (NSTableCellView))]
+ interface SFChooseIdentityTableCellView {
+
+ /// Initializes the cell view with the specified frame rectangle.
+ /// The frame rectangle for the cell view.
+ [Export ("initWithFrame:")]
+ NativeHandle Constructor (CoreGraphics.CGRect frameRect);
+
+ /// Gets or sets the text field that displays the certificate issuer name.
+ [NullAllowed]
+ [Export ("issuerTextField", ArgumentSemantic.Assign)]
+ NSTextField IssuerTextField { get; set; }
+ }
+
+ /// A save panel for creating a new keychain file.
+ [BaseType (typeof (NSSavePanel))]
+ interface SFKeychainSavePanel {
+
+ /// Gets the shared keychain save panel instance.
+ [Static]
+ [Export ("sharedKeychainSavePanel")]
+ SFKeychainSavePanel SharedKeychainSavePanel { get; }
+
+ /// Displays the panel modally starting in the specified directory with a suggested filename.
+ /// The directory to start in, or for the default.
+ /// The suggested filename, or .
+ /// The button code that was pressed to dismiss the panel.
+ [Export ("runModalForDirectory:file:")]
+ nint RunModalForDirectory ([NullAllowed] string path, [NullAllowed] string name);
+
+ /// Sets the password for the new keychain.
+ /// The password to use, or .
+ [Export ("setPassword:")]
+ void SetPassword ([NullAllowed] string password);
+
+ /// Gets the keychain that was created, or if the user cancelled.
+ [Export ("keychain")]
+ [NullAllowed]
+ SecKeychain Keychain { get; }
+
+ /// Gets the last error that occurred during keychain creation, or if no error.
+ [Export ("error")]
+ [NullAllowed]
+ NSError Error { get; }
+
+ /// Displays the panel as a sheet starting in the specified directory with a suggested filename.
+ /// The directory to start in, or for the default.
+ /// The suggested filename, or .
+ /// The window to which the sheet is attached.
+ /// The delegate that receives the did-end callback, or .
+ /// The selector invoked when the sheet ends, or .
+ /// A pointer to context information passed to the callback.
+ [Export ("beginSheetForDirectory:file:modalForWindow:modalDelegate:didEndSelector:contextInfo:")]
+ void BeginSheet ([NullAllowed] string path, [NullAllowed] string name, NSWindow docWindow, [NullAllowed] NSObject modalDelegate, [NullAllowed] Selector didEndSelector, IntPtr contextInfo);
+ }
+
+ /// A panel for editing keychain settings such as lock-on-sleep and auto-lock interval.
+ [BaseType (typeof (NSPanel))]
+ interface SFKeychainSettingsPanel {
+
+ /// Gets the shared keychain settings panel instance.
+ [Static]
+ [Export ("sharedKeychainSettingsPanel")]
+ SFKeychainSettingsPanel SharedKeychainSettingsPanel { get; }
+
+ /// Displays the panel modally for the specified keychain and settings.
+ /// The to edit.
+ /// The whose settings to edit.
+ /// The button code that was pressed to dismiss the panel.
+ [Export ("runModalForSettings:keychain:")]
+ nint RunModalForSettings (ref SecKeychainSettings settings, SecKeychain keychain);
+
+ /// Displays the panel as a sheet for editing the specified keychain settings.
+ /// The window to which the sheet is attached.
+ /// The delegate that receives the did-end callback, or .
+ /// The selector invoked when the sheet ends, or .
+ /// A pointer to context information passed to the callback.
+ /// The to edit.
+ /// The whose settings to edit.
+ [Export ("beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:settings:keychain:")]
+ void BeginSheet (NSWindow docWindow, [NullAllowed] NSObject modalDelegate, [NullAllowed] Selector didEndSelector, IntPtr contextInfo, ref SecKeychainSettings settings, SecKeychain keychain);
+ }
+
+ /// Contains keys for the user information dictionary passed to authorization plugin views.
+ [Static]
+ interface SFAuthorizationPluginViewKeys {
+
+ /// Key for the user name value in the user information dictionary.
+ [Field ("SFAuthorizationPluginViewUserNameKey")]
+ NSString UserNameKey { get; }
+
+ /// Key for the user short name value in the user information dictionary.
+ [Field ("SFAuthorizationPluginViewUserShortNameKey")]
+ NSString UserShortNameKey { get; }
+ }
+
+ /// Contains exception names raised by authorization plugin views.
+ [Static]
+ interface SFAuthorizationPluginViewExceptions {
+
+ /// The name of the exception raised when an authorization plugin view cannot be displayed.
+ [Field ("SFDisplayViewException")]
+ NSString DisplayViewException { get; }
+ }
+}
diff --git a/tests/cecil-tests/ApiTest.KnownFailures.cs b/tests/cecil-tests/ApiTest.KnownFailures.cs
index 2127b451fa98..3cc36f1e7352 100644
--- a/tests/cecil-tests/ApiTest.KnownFailures.cs
+++ b/tests/cecil-tests/ApiTest.KnownFailures.cs
@@ -582,12 +582,14 @@ public partial class ApiTest {
"SearchKit.SKSearch..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"SearchKit.SKSummary..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.Authorization..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
+ "Security.AuthorizationEngine..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecAccessControl..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecCertificate..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecCertificate2..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecIdentity..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecIdentity2..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecKey..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
+ "Security.SecKeychain..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecPolicy..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecProtocolMetadata..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
"Security.SecProtocolOptions..ctor(ObjCRuntime.NativeHandle, System.Boolean)",
diff --git a/tests/cecil-tests/ConstructorTest.cs b/tests/cecil-tests/ConstructorTest.cs
index e8e13fc18598..1e869f26c565 100644
--- a/tests/cecil-tests/ConstructorTest.cs
+++ b/tests/cecil-tests/ConstructorTest.cs
@@ -306,6 +306,7 @@ public void INativeObjectIntPtrConstructorDoesNotOwnHandle (ApplePlatform platfo
case "Protocol": // not really refcounted
case "AURenderEventEnumerator": // this class shouldn't really be an INativeObject in the first place
case "AudioBuffers": // this class shouldn't really be an INativeObject in the first place
+ case "AuthorizationCallbacks": // non-owning wrapper over a borrowed callback struct pointer
case "AVAudioChannelLayout": // has a private IntPtr constructor which is a void* in native code (i.e. not a mistake).
case "VNVideoProcessorFrameRateCadence": // has a nint (i.e. IntPtr) constructor (framerate) - not a mistake
case "NSMutableOrderedSet`1":
diff --git a/tests/cecil-tests/Documentation.KnownFailures.txt b/tests/cecil-tests/Documentation.KnownFailures.txt
index 2a3ae6cf7f27..6ad9d7c2b958 100644
--- a/tests/cecil-tests/Documentation.KnownFailures.txt
+++ b/tests/cecil-tests/Documentation.KnownFailures.txt
@@ -16113,6 +16113,9 @@ M:Security.SslContext.Read(System.Byte[],System.IntPtr@)
M:Security.SslContext.Write(System.Byte[],System.IntPtr@)
M:Security.SslStreamConnection.Read(System.IntPtr,System.IntPtr@)
M:Security.SslStreamConnection.Write(System.IntPtr,System.IntPtr@)
+M:SecurityInterface.AuthorizationRights.Finalize
+M:SecurityInterface.SFAuthorizationView.Dispose(System.Boolean)
+M:SecurityInterface.SFChooseIdentityTableCellView.Dispose(System.Boolean)
M:SecurityUI.SFCertificatePresentation.#ctor(Security.SecTrust)
M:SecurityUI.SFCertificatePresentation.DismissSheet
M:SecurityUI.SFCertificatePresentation.PresentSheet(AppKit.NSWindow,System.Action)
diff --git a/tests/cecil-tests/HandleSafety.KnownFailures.cs b/tests/cecil-tests/HandleSafety.KnownFailures.cs
index 403ad70a55bd..e7e5f38cb680 100644
--- a/tests/cecil-tests/HandleSafety.KnownFailures.cs
+++ b/tests/cecil-tests/HandleSafety.KnownFailures.cs
@@ -200,6 +200,15 @@ public partial class HandleSafetyTest {
"Security.SecRecord.set_Label (System.String)",
"Security.SecRecord.set_TokenID (Security.SecTokenID)",
"Security.SslContext.Bundle (Security.SecIdentity, System.Collections.Generic.IEnumerable`1)",
+ "SecurityInterface.AuthorizationCallbacks.DidDeactivate (Security.AuthorizationEngine)",
+ "SecurityInterface.AuthorizationCallbacks.GetContextValue (Security.AuthorizationEngine, System.String, SecurityInterface.AuthorizationContextFlags&, System.Byte[]&)",
+ "SecurityInterface.AuthorizationCallbacks.GetHintValue (Security.AuthorizationEngine, System.String, System.Byte[]&)",
+ "SecurityInterface.AuthorizationCallbacks.RemoveContextValue (Security.AuthorizationEngine, System.String)",
+ "SecurityInterface.AuthorizationCallbacks.RemoveHintValue (Security.AuthorizationEngine, System.String)",
+ "SecurityInterface.AuthorizationCallbacks.RequestInterrupt (Security.AuthorizationEngine)",
+ "SecurityInterface.AuthorizationCallbacks.SetContextValue (Security.AuthorizationEngine, System.String, SecurityInterface.AuthorizationContextFlags, System.Byte[])",
+ "SecurityInterface.AuthorizationCallbacks.SetHintValue (Security.AuthorizationEngine, System.String, System.Byte[])",
+ "SecurityInterface.AuthorizationCallbacks.SetResult (Security.AuthorizationEngine, SecurityInterface.AuthorizationResult)",
"System.Boolean ObjCRuntime.DisposableObject.op_Equality (ObjCRuntime.DisposableObject, ObjCRuntime.DisposableObject)",
"System.Boolean ObjCRuntime.DisposableObject.op_Inequality (ObjCRuntime.DisposableObject, ObjCRuntime.DisposableObject)",
"System.Boolean ObjCRuntime.NativeHandle.op_Equality (System.IntPtr, ObjCRuntime.NativeHandle)",
diff --git a/tests/cecil-tests/HandleSafety.cs b/tests/cecil-tests/HandleSafety.cs
index b9957120e483..b3642b0f393e 100644
--- a/tests/cecil-tests/HandleSafety.cs
+++ b/tests/cecil-tests/HandleSafety.cs
@@ -174,6 +174,8 @@ static bool IsUnsafeMethodCall (MethodReference? target)
case "CoreGraphics.CGPDFObject": // just a wrapper around a pointer, doesn't free anything in its destructor
case "CoreText.CTRunDelegateOperations": // The Handle property is a GCHandle (converted to IntPtr)
case "CoreGraphics.CGEvent/TapData": // The Handle property is a GCHandle (converted to IntPtr)
+ case "SecurityInterface.AuthorizationCallbacks": // non-owning wrapper around a borrowed callback struct pointer
+ case "SecurityInterface.AuthorizationRights": // IDisposable wrapper that manages its own unmanaged memory
switch (target.Name) {
case "get_Handle":
return false;
diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs
index db0634f8b81e..ec355f13b81a 100644
--- a/tests/dotnet/UnitTests/ProjectTest.cs
+++ b/tests/dotnet/UnitTests/ProjectTest.cs
@@ -3405,6 +3405,7 @@ public void AppendRuntimeIdentifierToOutputPath_DisableDirectoryBuildProps (Appl
"/System/Library/Frameworks/ScreenTime.framework/Versions/A/ScreenTime",
"/System/Library/Frameworks/ScriptingBridge.framework/Versions/A/ScriptingBridge",
"/System/Library/Frameworks/Security.framework/Versions/A/Security",
+ "/System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface",
"/System/Library/Frameworks/SecurityUI.framework/Versions/A/SecurityUI",
"/System/Library/Frameworks/SensitiveContentAnalysis.framework/Versions/A/SensitiveContentAnalysis",
"/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement",
diff --git a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-size.txt b/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-size.txt
index f991490a3294..3a270a941c4b 100644
--- a/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-size.txt
+++ b/tests/dotnet/UnitTests/expected/MacOSX-CoreCLR-Interpreter-size.txt
@@ -1,10 +1,10 @@
-AppBundleSize: 247,357,169 bytes (241,559.7 KB = 235.9 MB)
+AppBundleSize: 247,497,750 bytes (241,697.0 KB = 236.0 MB)
# The following list of files and their sizes is just informational / for review, and isn't used in the test:
Contents/_CodeSignature/CodeResources: 67,160 bytes (65.6 KB = 0.1 MB)
-Contents/Info.plist: 725 bytes (0.7 KB = 0.0 MB)
-Contents/MacOS/SizeTestApp: 8,001,536 bytes (7,814.0 KB = 7.6 MB)
+Contents/Info.plist: 746 bytes (0.7 KB = 0.0 MB)
+Contents/MacOS/SizeTestApp: 8,003,856 bytes (7,816.3 KB = 7.6 MB)
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.CSharp.dll: 893,200 bytes (872.3 KB = 0.9 MB)
-Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll: 36,723,712 bytes (35,863.0 KB = 35.0 MB)
+Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.macOS.dll: 36,792,832 bytes (35,930.5 KB = 35.1 MB)
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.Core.dll: 1,335,048 bytes (1,303.8 KB = 1.3 MB)
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.VisualBasic.dll: 17,712 bytes (17.3 KB = 0.0 MB)
Contents/MonoBundle/.xamarin/osx-arm64/Microsoft.Win32.Primitives.dll: 16,144 bytes (15.8 KB = 0.0 MB)
@@ -178,7 +178,7 @@ Contents/MonoBundle/.xamarin/osx-arm64/System.Xml.XPath.dll: 16,136 bytes (15.8
Contents/MonoBundle/.xamarin/osx-arm64/System.Xml.XPath.XDocument.dll: 17,672 bytes (17.3 KB = 0.0 MB)
Contents/MonoBundle/.xamarin/osx-arm64/WindowsBase.dll: 16,656 bytes (16.3 KB = 0.0 MB)
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.CSharp.dll: 796,432 bytes (777.8 KB = 0.8 MB)
-Contents/MonoBundle/.xamarin/osx-x64/Microsoft.macOS.dll: 36,723,712 bytes (35,863.0 KB = 35.0 MB)
+Contents/MonoBundle/.xamarin/osx-x64/Microsoft.macOS.dll: 36,792,832 bytes (35,930.5 KB = 35.1 MB)
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.VisualBasic.Core.dll: 1,166,600 bytes (1,139.3 KB = 1.1 MB)
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.VisualBasic.dll: 17,720 bytes (17.3 KB = 0.0 MB)
Contents/MonoBundle/.xamarin/osx-x64/Microsoft.Win32.Primitives.dll: 16,144 bytes (15.8 KB = 0.0 MB)
diff --git a/tests/monotouch-test/SecurityInterface/AuthorizationManualBindingsTest.cs b/tests/monotouch-test/SecurityInterface/AuthorizationManualBindingsTest.cs
new file mode 100644
index 000000000000..353e16dd2979
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/AuthorizationManualBindingsTest.cs
@@ -0,0 +1,200 @@
+#if __MACOS__
+using System;
+using System.Runtime.InteropServices;
+using NUnit.Framework;
+using ObjCRuntime;
+using Security;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class AuthorizationEngineTest {
+
+ [Test]
+ public void Create_Zero_ReturnsNull ()
+ {
+ var engine = AuthorizationEngine.Create (NativeHandle.Zero);
+ Assert.That (engine, Is.Null, "Zero handle should return null");
+ }
+ }
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public unsafe class AuthorizationCallbacksTest {
+
+ [StructLayout (LayoutKind.Sequential)]
+ struct FakeCallbacksNative {
+ public uint Version;
+ // All remaining fields are function pointers — set to zero for testing
+ public IntPtr SetResult;
+ public IntPtr RequestInterrupt;
+ public IntPtr DidDeactivate;
+ public IntPtr GetContextValue;
+ public IntPtr SetContextValue;
+ public IntPtr GetHintValue;
+ public IntPtr SetHintValue;
+ public IntPtr GetArguments;
+ public IntPtr GetSessionId;
+ public IntPtr GetImmutableHintValue;
+ public IntPtr GetLAContext;
+ public IntPtr GetTokenIdentities;
+ public IntPtr GetTKTokenWatcher;
+ public IntPtr RemoveHintValue;
+ public IntPtr RemoveContextValue;
+ }
+
+ [Test]
+ public void Create_Zero_StoresHandle ()
+ {
+ var callbacks = new AuthorizationCallbacks (NativeHandle.Zero);
+ Assert.That ((IntPtr) callbacks.Handle, Is.EqualTo (IntPtr.Zero), "Zero handle should be stored");
+ }
+
+ [Test]
+ public void Create_NonZero_ReturnsWrapper ()
+ {
+ var native = new FakeCallbacksNative { Version = 7 };
+ var ptr = Marshal.AllocHGlobal (Marshal.SizeOf ());
+ try {
+ Marshal.StructureToPtr (native, ptr, false);
+ var callbacks = new AuthorizationCallbacks (ptr);
+ Assert.That (callbacks, Is.Not.Null, "Should create a wrapper");
+ Assert.That (callbacks.Handle, Is.EqualTo ((NativeHandle) ptr), "Handle should match");
+ } finally {
+ Marshal.FreeHGlobal (ptr);
+ }
+ }
+
+ [Test]
+ public void Version_ReadsCorrectly ()
+ {
+ var native = new FakeCallbacksNative { Version = 42 };
+ var ptr = Marshal.AllocHGlobal (Marshal.SizeOf ());
+ try {
+ Marshal.StructureToPtr (native, ptr, false);
+ var callbacks = new AuthorizationCallbacks (ptr);
+ Assert.That (callbacks.Version, Is.EqualTo (42u), "Version should read 42");
+ } finally {
+ Marshal.FreeHGlobal (ptr);
+ }
+ }
+
+ [Test]
+ public void Version_DifferentValues ()
+ {
+ var native = new FakeCallbacksNative { Version = 1 };
+ var ptr = Marshal.AllocHGlobal (Marshal.SizeOf ());
+ try {
+ Marshal.StructureToPtr (native, ptr, false);
+ var callbacks = new AuthorizationCallbacks (ptr);
+ Assert.That (callbacks.Version, Is.EqualTo (1u), "Version should be 1");
+
+ // Update the native memory and verify the wrapper reads the new value
+ native.Version = 99;
+ Marshal.StructureToPtr (native, ptr, false);
+ Assert.That (callbacks.Version, Is.EqualTo (99u), "Version should update to 99");
+ } finally {
+ Marshal.FreeHGlobal (ptr);
+ }
+ }
+ }
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class AuthorizationRightsRoundTripTest {
+
+ [Test]
+ public void FromHandle_NullReturnsNull ()
+ {
+ var rights = AuthorizationRights.FromHandle (NativeHandle.Zero);
+ Assert.That (rights, Is.Null, "Zero handle should return null");
+ }
+
+ [Test]
+ public void NativeHandle_RoundTrip ()
+ {
+ // Create rights, get their handle, then read them back via FromHandle
+ using var original = new AuthorizationRights (
+ new AuthorizationRight ("com.example.right1", new byte [] { 0xAA, 0xBB }, 5),
+ new AuthorizationRight ("com.example.right2")
+ );
+
+ var handle = original.Handle;
+ Assert.That (handle, Is.Not.EqualTo (NativeHandle.Zero), "Handle should be valid");
+
+ // Read back from the same handle (simulates what the bgen getter does)
+ using var readBack = AuthorizationRights.FromHandle (handle);
+ Assert.That (readBack, Is.Not.Null, "FromHandle should return non-null");
+ Assert.That (readBack!.Count, Is.EqualTo (2), "Count should match");
+
+ Assert.That (readBack [0].Name, Is.EqualTo ("com.example.right1"), "Name[0]");
+ Assert.That (readBack [0].Value, Is.EqualTo (new byte [] { 0xAA, 0xBB }), "Value[0]");
+ Assert.That (readBack [0].Flags, Is.EqualTo (5u), "Flags[0]");
+
+ Assert.That (readBack [1].Name, Is.EqualTo ("com.example.right2"), "Name[1]");
+ Assert.That (readBack [1].Value, Is.Null, "Value[1] should be null");
+ Assert.That (readBack [1].Flags, Is.EqualTo (0u), "Flags[1]");
+ }
+
+ [Test]
+ public void LargeRightsSet ()
+ {
+ var items = new AuthorizationRight [100];
+ for (int i = 0; i < 100; i++)
+ items [i] = new AuthorizationRight ($"com.example.right{i}", new byte [] { (byte) i }, (uint) i);
+
+ using var rights = new AuthorizationRights (items);
+ Assert.That (rights.Count, Is.EqualTo (100), "Count");
+
+ using var readBack = AuthorizationRights.FromHandle (rights.Handle);
+ Assert.That (readBack!.Count, Is.EqualTo (100), "ReadBack Count");
+ Assert.That (readBack [50].Name, Is.EqualTo ("com.example.right50"), "Name[50]");
+ Assert.That (readBack [50].Value, Is.EqualTo (new byte [] { 50 }), "Value[50]");
+ Assert.That (readBack [50].Flags, Is.EqualTo (50u), "Flags[50]");
+ }
+
+ [Test]
+ public void UnicodeRightNames ()
+ {
+ using var rights = new AuthorizationRights (
+ new AuthorizationRight ("com.example.日本語テスト"),
+ new AuthorizationRight ("com.example.émojis🎉")
+ );
+
+ using var readBack = AuthorizationRights.FromHandle (rights.Handle);
+ Assert.That (readBack! [0].Name, Is.EqualTo ("com.example.日本語テスト"), "Unicode name[0]");
+ Assert.That (readBack [1].Name, Is.EqualTo ("com.example.émojis🎉"), "Unicode name[1]");
+ }
+
+ [Test]
+ public void EmptyValueVsNullValue ()
+ {
+ using var rights = new AuthorizationRights (
+ new AuthorizationRight ("with-empty", new byte [0]),
+ new AuthorizationRight ("with-null", null)
+ );
+
+ using var readBack = AuthorizationRights.FromHandle (rights.Handle);
+ Assert.That (readBack! [0].Value, Is.Null, "Empty byte array should read back as null (zero length)");
+ Assert.That (readBack [1].Value, Is.Null, "Null value should remain null");
+ }
+ }
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFAuthorizationPluginViewManualTest {
+
+ [Test]
+ public void SFAuthorizationPluginView_CallbacksProperty_Null ()
+ {
+ // We can't construct a real SFAuthorizationPluginView without a valid engine+callbacks
+ // from the authorization plugin host. But we can verify the type exists and is constructible
+ // via the ObjC runtime by checking the class handle.
+ var classHandle = global::ObjCRuntime.Class.GetHandle ("SFAuthorizationPluginView");
+ Assert.That (classHandle, Is.Not.EqualTo (IntPtr.Zero), "SFAuthorizationPluginView ObjC class should exist");
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/AuthorizationRightsTest.cs b/tests/monotouch-test/SecurityInterface/AuthorizationRightsTest.cs
new file mode 100644
index 000000000000..e911c998c503
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/AuthorizationRightsTest.cs
@@ -0,0 +1,99 @@
+#if __MACOS__
+using System;
+using NUnit.Framework;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class AuthorizationRightsTest {
+
+ [Test]
+ public void Create_FromStrings ()
+ {
+ using var rights = new AuthorizationRights ("com.example.right1", "com.example.right2");
+ Assert.That (rights.Count, Is.EqualTo (2), "Count");
+ Assert.That (rights [0].Name, Is.EqualTo ("com.example.right1"), "Name[0]");
+ Assert.That (rights [1].Name, Is.EqualTo ("com.example.right2"), "Name[1]");
+ Assert.That (rights.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void Create_FromAuthorizationRight ()
+ {
+ var right = new AuthorizationRight ("com.example.test", new byte [] { 1, 2, 3 }, 42);
+ using var rights = new AuthorizationRights (right);
+ Assert.That (rights.Count, Is.EqualTo (1), "Count");
+ Assert.That (rights [0].Name, Is.EqualTo ("com.example.test"), "Name");
+ Assert.That (rights [0].Value, Is.EqualTo (new byte [] { 1, 2, 3 }), "Value");
+ Assert.That (rights [0].Flags, Is.EqualTo (42u), "Flags");
+ }
+
+ [Test]
+ public void Create_Empty ()
+ {
+ using var rights = new AuthorizationRights (Array.Empty ());
+ Assert.That (rights.Count, Is.EqualTo (0), "Count");
+ Assert.That (rights.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle should be valid even when empty");
+ }
+
+ [Test]
+ public void AuthorizationRight_NullValue ()
+ {
+ var right = new AuthorizationRight ("com.example.novalue");
+ Assert.That (right.Name, Is.EqualTo ("com.example.novalue"), "Name");
+ Assert.That (right.Value, Is.Null, "Value should be null");
+ Assert.That (right.Flags, Is.EqualTo (0u), "Flags should default to 0");
+ }
+
+ [Test]
+ public void AuthorizationRight_ValueIsCopied ()
+ {
+ var original = new byte [] { 10, 20, 30 };
+ var right = new AuthorizationRight ("test", original);
+ original [0] = 99;
+ Assert.That (right.Value! [0], Is.EqualTo (10), "Value should be a copy, not a reference");
+ }
+
+ [Test]
+ public void AuthorizationRight_NullName_Throws ()
+ {
+ Assert.Throws (() => new AuthorizationRight (null!));
+ }
+
+ [Test]
+ public void Dispose_ClearsHandle ()
+ {
+ var rights = new AuthorizationRights ("test");
+ Assert.That (rights.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle before dispose");
+ rights.Dispose ();
+ Assert.That ((IntPtr) rights.Handle, Is.EqualTo (IntPtr.Zero), "Handle after dispose");
+ }
+
+ [Test]
+ public void Dispose_CanBeCalledMultipleTimes ()
+ {
+ var rights = new AuthorizationRights ("test");
+ rights.Dispose ();
+ Assert.DoesNotThrow (() => rights.Dispose (), "Double dispose should not throw");
+ }
+
+ [Test]
+ public void Enumeration ()
+ {
+ using var rights = new AuthorizationRights ("a", "b", "c");
+ var names = new global::System.Collections.Generic.List ();
+ foreach (var right in rights)
+ names.Add (right.Name);
+ Assert.That (names, Is.EqualTo (new [] { "a", "b", "c" }), "Enumeration");
+ }
+
+ [Test]
+ public void NullStrings_Throws ()
+ {
+ Assert.Throws (() => new AuthorizationRights ((string []) null!));
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SFAuthorizationViewTest.cs b/tests/monotouch-test/SecurityInterface/SFAuthorizationViewTest.cs
new file mode 100644
index 000000000000..7a7850b12cb8
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SFAuthorizationViewTest.cs
@@ -0,0 +1,93 @@
+#if __MACOS__
+using System;
+using NUnit.Framework;
+using AppKit;
+using Foundation;
+using Security;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFAuthorizationViewTest {
+
+ [Test]
+ public void Constructor ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ Assert.That (view.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void AuthorizationState_InitialValue ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ var state = view.AuthorizationState;
+ Assert.That (state, Is.EqualTo (SFAuthorizationViewState.Startup), "Initial state should be Startup");
+ }
+
+ [Test]
+ public void IsEnabled_Default ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ // The default enabled state depends on the system, just verify it doesn't crash
+ var _ = view.IsEnabled;
+ }
+
+ [Test]
+ public void SetEnabled ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ Assert.DoesNotThrow (() => view.SetEnabled (false), "SetEnabled false");
+ Assert.DoesNotThrow (() => view.SetEnabled (true), "SetEnabled true");
+ }
+
+ [Test]
+ public void SetAuthorizationString ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ Assert.DoesNotThrow (() => view.SetAuthorizationString ("com.example.test"), "SetAuthorizationString");
+ }
+
+ [Test]
+ public void SetAuthorizationString_NullThrows ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ Assert.Throws (() => view.SetAuthorizationString (null!));
+ }
+
+ [Test]
+ public void AuthorizationRightsSet_Get_InitiallyNull ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ var rights = view.AuthorizationRightsSet;
+ // Rights may or may not be null depending on initialization state
+ }
+
+ [Test]
+ public void Delegate_SetAndGet ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ Assert.That (view.WeakDelegate, Is.Null, "Delegate should initially be null");
+ view.WeakDelegate = NSObject.FromObject ("test");
+ Assert.That (view.WeakDelegate, Is.Not.Null, "Delegate should be set");
+ }
+
+ [Test]
+ public void SetFlags ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ Assert.DoesNotThrow (() => view.SetFlags (0), "SetFlags 0");
+ }
+
+ [Test]
+ public void SetAutoupdate ()
+ {
+ using var view = new SFAuthorizationView (new global::CoreGraphics.CGRect (0, 0, 100, 100));
+ Assert.DoesNotThrow (() => view.SetAutoupdate (false), "SetAutoupdate false");
+ Assert.DoesNotThrow (() => view.SetAutoupdate (true, 60.0), "SetAutoupdate with interval");
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SFCertificatePanelTest.cs b/tests/monotouch-test/SecurityInterface/SFCertificatePanelTest.cs
new file mode 100644
index 000000000000..3e3fbbc18555
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SFCertificatePanelTest.cs
@@ -0,0 +1,74 @@
+#if __MACOS__
+using System;
+using NUnit.Framework;
+using AppKit;
+using Foundation;
+using Security;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFCertificatePanelTest {
+
+ [Test]
+ public void SharedCertificatePanel ()
+ {
+ var panel = SFCertificatePanel.SharedCertificatePanel;
+ Assert.That (panel, Is.Not.Null, "SharedCertificatePanel should not be null");
+ Assert.That (panel.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void CertificateView ()
+ {
+ // Accessing the panel's CertificateView triggers NSView hierarchy initialization
+ // which causes a CF_IS_OBJC breakpoint trap on headless CI machines, hanging the process.
+ TestRuntime.IgnoreInCI ("SFCertificatePanel.CertificateView triggers view hierarchy init that hangs on headless CI.");
+ var panel = SFCertificatePanel.SharedCertificatePanel;
+ var view = panel.CertificateView;
+ }
+
+ [Test]
+ public void Properties ()
+ {
+ // Panel property setters may trigger deferred UI operations on headless CI.
+ TestRuntime.IgnoreInCI ("SFCertificatePanel property setters may trigger UI operations on headless CI.");
+ var panel = SFCertificatePanel.SharedCertificatePanel;
+
+ Assert.DoesNotThrow (() => panel.SetShowsHelp (false), "SetShowsHelp");
+ Assert.That (panel.ShowsHelp, Is.False, "ShowsHelp");
+
+ Assert.DoesNotThrow (() => panel.SetDefaultButtonTitle ("OK"), "SetDefaultButtonTitle");
+ Assert.DoesNotThrow (() => panel.SetAlternateButtonTitle ("Cancel"), "SetAlternateButtonTitle");
+
+ panel.SetHelpAnchor ("testAnchor");
+ Assert.That (panel.HelpAnchor, Is.EqualTo ("testAnchor"), "HelpAnchor round-trip");
+ }
+ }
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFCertificateTrustPanelTest {
+
+ [Test]
+ public void SharedCertificateTrustPanel ()
+ {
+ var panel = SFCertificateTrustPanel.SharedCertificateTrustPanel;
+ Assert.That (panel, Is.Not.Null, "SharedCertificateTrustPanel should not be null");
+ Assert.That (panel.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void InformativeText ()
+ {
+ // Panel property setters may trigger deferred UI operations on headless CI.
+ TestRuntime.IgnoreInCI ("SFCertificateTrustPanel property setters may trigger UI operations on headless CI.");
+ var panel = SFCertificateTrustPanel.SharedCertificateTrustPanel;
+ panel.SetInformativeText ("Test informative text");
+ Assert.That (panel.InformativeText, Is.EqualTo ("Test informative text"), "InformativeText round-trip");
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SFCertificateViewTest.cs b/tests/monotouch-test/SecurityInterface/SFCertificateViewTest.cs
new file mode 100644
index 000000000000..d52f13c88449
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SFCertificateViewTest.cs
@@ -0,0 +1,110 @@
+#if __MACOS__
+using System;
+using NUnit.Framework;
+using AppKit;
+using Foundation;
+using Security;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFCertificateViewTest {
+
+ [Test]
+ public void Constructor ()
+ {
+ using var view = new SFCertificateView (new global::CoreGraphics.CGRect (0, 0, 300, 200));
+ Assert.That (view.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void GetCertificate_InitiallyNull ()
+ {
+ using var view = new SFCertificateView (new global::CoreGraphics.CGRect (0, 0, 300, 200));
+ var cert = view.GetCertificate ();
+ Assert.That (cert, Is.Null, "Certificate should initially be null");
+ }
+
+ [Test]
+ public void SetCertificate_Null ()
+ {
+ using var view = new SFCertificateView (new global::CoreGraphics.CGRect (0, 0, 300, 200));
+ Assert.DoesNotThrow (() => view.SetCertificate (null), "SetCertificate null");
+ }
+
+ [Test]
+ public void SetCertificate_Valid ()
+ {
+ using var view = new SFCertificateView (new global::CoreGraphics.CGRect (0, 0, 300, 200));
+ using var data = NSData.FromArray (CertificateData.AppleComCert);
+ using var cert = new SecCertificate (data);
+ view.SetCertificate (cert);
+
+ var retrieved = view.GetCertificate ();
+ Assert.That (retrieved, Is.Not.Null, "Should get certificate back");
+ retrieved!.Dispose ();
+ }
+
+ [Test]
+ public void Properties ()
+ {
+ using var view = new SFCertificateView (new global::CoreGraphics.CGRect (0, 0, 300, 200));
+
+ Assert.DoesNotThrow (() => view.SetEditableTrust (false), "SetEditableTrust");
+ Assert.DoesNotThrow (() => { var _ = view.IsEditable; }, "IsEditable");
+
+ Assert.DoesNotThrow (() => view.SetDisplayTrust (true), "SetDisplayTrust");
+ Assert.DoesNotThrow (() => { var _ = view.IsTrustDisplayed; }, "IsTrustDisplayed");
+
+ Assert.DoesNotThrow (() => view.SetDisplayDetails (true), "SetDisplayDetails");
+ Assert.DoesNotThrow (() => { var _ = view.DetailsDisplayed; }, "DetailsDisplayed");
+
+ Assert.DoesNotThrow (() => view.SetDetailsDisclosed (false), "SetDetailsDisclosed");
+ Assert.DoesNotThrow (() => { var _ = view.DetailsDisclosed; }, "DetailsDisclosed");
+
+ Assert.DoesNotThrow (() => view.SetPoliciesDisclosed (false), "SetPoliciesDisclosed");
+ Assert.DoesNotThrow (() => { var _ = view.PoliciesDisclosed; }, "PoliciesDisclosed");
+ }
+
+ [Test]
+ public void DisclosureStateDidChangeNotification_Exists ()
+ {
+ var notification = SFCertificateView.DisclosureStateDidChangeNotification;
+ Assert.That (notification, Is.Not.Null, "Notification should not be null");
+ Assert.That ((int) notification.Length, Is.GreaterThan (0), "Notification string should not be empty");
+ }
+ }
+
+ static class CertificateData {
+ // Valid self-signed EC P-256 DER certificate (CN=TestCert, valid 10 years)
+ public static readonly byte [] AppleComCert = {
+ 0x30, 0x82, 0x01, 0x7b, 0x30, 0x82, 0x01, 0x21, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x7d,
+ 0x74, 0x9f, 0x84, 0xa4, 0x7d, 0xe9, 0x76, 0x2c, 0xfe, 0x00, 0x77, 0x4d, 0xf3, 0xc4, 0x5e, 0xdd,
+ 0x0d, 0x0b, 0xa4, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
+ 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74,
+ 0x43, 0x65, 0x72, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x34, 0x31, 0x31, 0x30, 0x32,
+ 0x33, 0x36, 0x31, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x34, 0x30, 0x38, 0x30, 0x32, 0x33,
+ 0x36, 0x31, 0x30, 0x5a, 0x30, 0x13, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+ 0x08, 0x54, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
+ 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
+ 0x03, 0x42, 0x00, 0x04, 0xc0, 0xc5, 0xf7, 0x7d, 0xb9, 0x5e, 0x44, 0x11, 0x73, 0xb6, 0x27, 0xdb,
+ 0xaf, 0xdb, 0x6c, 0xa3, 0x40, 0x03, 0xb2, 0xb7, 0x23, 0xf0, 0xdd, 0xd3, 0x6a, 0xe7, 0xa0, 0x89,
+ 0x75, 0xfa, 0xcb, 0x9f, 0xcb, 0xc3, 0x99, 0x1e, 0x40, 0xde, 0x1d, 0x24, 0x6b, 0xda, 0xd7, 0x65,
+ 0xfd, 0x9b, 0xff, 0x84, 0x0b, 0xef, 0x5a, 0xd7, 0xec, 0xc9, 0x10, 0x88, 0x57, 0x0f, 0x5b, 0xbc,
+ 0x69, 0x26, 0x9d, 0xd4, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0xbd, 0xfe, 0xc1, 0xd4, 0xb9, 0x00, 0xe8, 0x0b, 0x67, 0xd8, 0xe6, 0xbc, 0x26,
+ 0x54, 0x76, 0x4f, 0xe0, 0x95, 0xcb, 0xc0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0xbd, 0xfe, 0xc1, 0xd4, 0xb9, 0x00, 0xe8, 0x0b, 0x67, 0xd8, 0xe6, 0xbc,
+ 0x26, 0x54, 0x76, 0x4f, 0xe0, 0x95, 0xcb, 0xc0, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+ 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xf9, 0xb6, 0x9d,
+ 0x20, 0x4c, 0x71, 0xc4, 0x4f, 0xa1, 0xbb, 0x2e, 0x0d, 0x68, 0x09, 0x2a, 0x0c, 0xdd, 0x78, 0xa2,
+ 0x62, 0xa8, 0x73, 0x5e, 0xd9, 0x26, 0x37, 0x83, 0x25, 0x44, 0x26, 0x01, 0xbd, 0x02, 0x20, 0x4e,
+ 0x2a, 0x75, 0x1d, 0x90, 0xde, 0xc6, 0x3b, 0xf7, 0xd0, 0xf4, 0x62, 0x8b, 0x66, 0x87, 0x06, 0xea,
+ 0x6c, 0xfa, 0xda, 0x25, 0xe3, 0xf6, 0xba, 0x15, 0x47, 0xe5, 0xf2, 0x4e, 0x99, 0xce, 0x9f,
+ };
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SFChooseIdentityPanelTest.cs b/tests/monotouch-test/SecurityInterface/SFChooseIdentityPanelTest.cs
new file mode 100644
index 000000000000..da203c7743c3
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SFChooseIdentityPanelTest.cs
@@ -0,0 +1,84 @@
+#if __MACOS__
+using System;
+using NUnit.Framework;
+using AppKit;
+using Foundation;
+using Security;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFChooseIdentityPanelTest {
+
+ [Test]
+ public void SharedChooseIdentityPanel ()
+ {
+ var panel = SFChooseIdentityPanel.SharedChooseIdentityPanel;
+ Assert.That (panel, Is.Not.Null, "SharedChooseIdentityPanel should not be null");
+ Assert.That (panel.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void Properties ()
+ {
+ // Panel property setters may trigger deferred UI operations on headless CI.
+ TestRuntime.IgnoreInCI ("SFChooseIdentityPanel property setters may trigger UI operations on headless CI.");
+ var panel = SFChooseIdentityPanel.SharedChooseIdentityPanel;
+
+ Assert.DoesNotThrow (() => panel.SetShowsHelp (true), "SetShowsHelp");
+ Assert.That (panel.ShowsHelp, Is.True, "ShowsHelp");
+
+ panel.SetDefaultButtonTitle ("Select");
+ panel.SetAlternateButtonTitle ("Cancel");
+
+ panel.SetHelpAnchor ("identityHelp");
+ Assert.That (panel.HelpAnchor, Is.EqualTo ("identityHelp"), "HelpAnchor round-trip");
+
+ panel.SetInformativeText ("Choose an identity");
+ Assert.That (panel.InformativeText, Is.EqualTo ("Choose an identity"), "InformativeText round-trip");
+
+ panel.SetDomain ("com.example.test");
+ Assert.That (panel.Domain, Is.EqualTo ("com.example.test"), "Domain round-trip");
+ }
+
+ [Test]
+ public void Identity_InitiallyNull ()
+ {
+ var panel = SFChooseIdentityPanel.SharedChooseIdentityPanel;
+ // Identity is null until a user selects one from the panel
+ var identity = panel.Identity;
+ Assert.That (identity, Is.Null, "Identity should be null when no selection made");
+ }
+ }
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFChooseIdentityTableCellViewTest {
+
+ [Test]
+ public void Constructor ()
+ {
+ using var cellView = new SFChooseIdentityTableCellView (new global::CoreGraphics.CGRect (0, 0, 200, 44));
+ Assert.That (cellView.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void IssuerTextField_DefaultNull ()
+ {
+ using var cellView = new SFChooseIdentityTableCellView (new global::CoreGraphics.CGRect (0, 0, 200, 44));
+ Assert.That (cellView.IssuerTextField, Is.Null, "IssuerTextField should initially be null");
+ }
+
+ [Test]
+ public void IssuerTextField_SetAndGet ()
+ {
+ using var cellView = new SFChooseIdentityTableCellView (new global::CoreGraphics.CGRect (0, 0, 200, 44));
+ using var textField = new NSTextField ();
+ cellView.IssuerTextField = textField;
+ Assert.That (cellView.IssuerTextField, Is.Not.Null, "IssuerTextField should be set");
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SFFieldsAndEnumsTest.cs b/tests/monotouch-test/SecurityInterface/SFFieldsAndEnumsTest.cs
new file mode 100644
index 000000000000..98078a0204a2
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SFFieldsAndEnumsTest.cs
@@ -0,0 +1,85 @@
+#if __MACOS__
+using System;
+using NUnit.Framework;
+using Foundation;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFAuthorizationPluginViewFieldsTest {
+
+ [Test]
+ public void UserNameKey ()
+ {
+ var key = SFAuthorizationPluginViewKeys.UserNameKey;
+ Assert.That (key, Is.Not.Null, "UserNameKey should not be null");
+ Assert.That ((string) key, Is.Not.Empty, "UserNameKey should not be empty");
+ }
+
+ [Test]
+ public void UserShortNameKey ()
+ {
+ var key = SFAuthorizationPluginViewKeys.UserShortNameKey;
+ Assert.That (key, Is.Not.Null, "UserShortNameKey should not be null");
+ Assert.That ((string) key, Is.Not.Empty, "UserShortNameKey should not be empty");
+ }
+
+ [Test]
+ public void DisplayViewException ()
+ {
+ var exc = SFAuthorizationPluginViewExceptions.DisplayViewException;
+ Assert.That (exc, Is.Not.Null, "DisplayViewException should not be null");
+ Assert.That ((string) exc, Is.Not.Empty, "DisplayViewException should not be empty");
+ }
+ }
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFEnumsTest {
+
+ [Test]
+ public void AuthorizationViewState_Values ()
+ {
+ Assert.That ((int) SFAuthorizationViewState.Startup, Is.EqualTo (0));
+ Assert.That ((int) SFAuthorizationViewState.Locked, Is.EqualTo (1));
+ Assert.That ((int) SFAuthorizationViewState.InProgress, Is.EqualTo (2));
+ Assert.That ((int) SFAuthorizationViewState.Unlocked, Is.EqualTo (3));
+ }
+
+ [Test]
+ public void ButtonType_Values ()
+ {
+ Assert.That ((int) SFButtonType.Cancel, Is.EqualTo (0));
+ Assert.That ((int) SFButtonType.Ok, Is.EqualTo (1));
+ Assert.That ((int) SFButtonType.Back, Is.EqualTo (0));
+ Assert.That ((int) SFButtonType.Login, Is.EqualTo (1));
+ }
+
+ [Test]
+ public void ViewType_Values ()
+ {
+ Assert.That ((int) SFViewType.IdentityAndCredentials, Is.EqualTo (0));
+ Assert.That ((int) SFViewType.Credentials, Is.EqualTo (1));
+ }
+
+ [Test]
+ public void AuthorizationResult_Values ()
+ {
+ Assert.That ((uint) AuthorizationResult.Allow, Is.EqualTo (0u));
+ Assert.That ((uint) AuthorizationResult.Deny, Is.EqualTo (1u));
+ Assert.That ((uint) AuthorizationResult.Undefined, Is.EqualTo (2u));
+ Assert.That ((uint) AuthorizationResult.UserCanceled, Is.EqualTo (3u));
+ }
+
+ [Test]
+ public void AuthorizationContextFlags_Values ()
+ {
+ Assert.That ((uint) AuthorizationContextFlags.Extractable, Is.EqualTo (1u));
+ Assert.That ((uint) AuthorizationContextFlags.Volatile, Is.EqualTo (2u));
+ Assert.That ((uint) AuthorizationContextFlags.Sticky, Is.EqualTo (4u));
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SFKeychainPanelTest.cs b/tests/monotouch-test/SecurityInterface/SFKeychainPanelTest.cs
new file mode 100644
index 000000000000..7dbde4ddaa24
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SFKeychainPanelTest.cs
@@ -0,0 +1,67 @@
+#if __MACOS__
+using System;
+using NUnit.Framework;
+using AppKit;
+using SecurityInterface;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFKeychainSavePanelTest {
+
+ [Test]
+ public void SharedKeychainSavePanel ()
+ {
+ var panel = SFKeychainSavePanel.SharedKeychainSavePanel;
+ Assert.That (panel, Is.Not.Null, "SharedKeychainSavePanel should not be null");
+ Assert.That (panel.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+
+ [Test]
+ public void SetPassword ()
+ {
+ // SFKeychainSavePanel inherits from NSSavePanel which may require window server access.
+ TestRuntime.IgnoreInCI ("SFKeychainSavePanel operations may trigger UI on headless CI.");
+ var panel = SFKeychainSavePanel.SharedKeychainSavePanel;
+ Assert.DoesNotThrow (() => panel.SetPassword ("test-password"), "SetPassword");
+ Assert.DoesNotThrow (() => panel.SetPassword (null), "SetPassword null");
+ }
+
+ [Test]
+ public void Keychain_BeforeCreation ()
+ {
+ // SFKeychainSavePanel inherits from NSSavePanel which may require window server access.
+ TestRuntime.IgnoreInCI ("SFKeychainSavePanel operations may trigger UI on headless CI.");
+ var panel = SFKeychainSavePanel.SharedKeychainSavePanel;
+ // Keychain is null until a user creates one via the panel
+ var keychain = panel.Keychain;
+ // May or may not be null depending on previous panel usage
+ }
+
+ [Test]
+ public void Error_BeforeCreation ()
+ {
+ // SFKeychainSavePanel inherits from NSSavePanel which may require window server access.
+ TestRuntime.IgnoreInCI ("SFKeychainSavePanel operations may trigger UI on headless CI.");
+ var panel = SFKeychainSavePanel.SharedKeychainSavePanel;
+ // Error should be null if no operation has been attempted
+ var error = panel.Error;
+ // May or may not be null depending on previous panel usage
+ }
+ }
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SFKeychainSettingsPanelTest {
+
+ [Test]
+ public void SharedKeychainSettingsPanel ()
+ {
+ var panel = SFKeychainSettingsPanel.SharedKeychainSettingsPanel;
+ Assert.That (panel, Is.Not.Null, "SharedKeychainSettingsPanel should not be null");
+ Assert.That (panel.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SecKeychainSettingsTest.cs b/tests/monotouch-test/SecurityInterface/SecKeychainSettingsTest.cs
new file mode 100644
index 000000000000..845d3d3086d0
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SecKeychainSettingsTest.cs
@@ -0,0 +1,61 @@
+#if __MACOS__
+using System;
+using System.Runtime.InteropServices;
+using NUnit.Framework;
+using Security;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SecKeychainSettingsTest {
+
+ [Test]
+ public void Create_DefaultValues ()
+ {
+ var settings = SecKeychainSettings.Create ();
+ Assert.That (settings.Version, Is.EqualTo (1), "Version should be 1");
+ Assert.That (settings.LockOnSleep, Is.False, "LockOnSleep should default to false");
+ Assert.That (settings.UseLockInterval, Is.False, "UseLockInterval should default to false");
+ Assert.That (settings.LockInterval, Is.EqualTo (0), "LockInterval should default to 0");
+ }
+
+ [Test]
+ public void Properties_RoundTrip ()
+ {
+ var settings = SecKeychainSettings.Create ();
+
+ settings.LockOnSleep = true;
+ Assert.That (settings.LockOnSleep, Is.True, "LockOnSleep");
+
+ settings.UseLockInterval = true;
+ Assert.That (settings.UseLockInterval, Is.True, "UseLockInterval");
+
+ settings.LockInterval = 300;
+ Assert.That (settings.LockInterval, Is.EqualTo (300), "LockInterval");
+
+ settings.Version = 2;
+ Assert.That (settings.Version, Is.EqualTo (2), "Version");
+ }
+
+ [Test]
+ public void LockOnSleep_FalseRoundTrip ()
+ {
+ var settings = SecKeychainSettings.Create ();
+ settings.LockOnSleep = true;
+ settings.LockOnSleep = false;
+ Assert.That (settings.LockOnSleep, Is.False, "LockOnSleep should be false after reset");
+ }
+
+ [Test]
+ public void StructSize_IsBlittable ()
+ {
+ // SecKeychainSettings has 4 fields: version(4) + lockOnSleep(1) + useLockInterval(1) + lockInterval(4) = 10
+ // But with alignment it may be padded
+ var size = Marshal.SizeOf ();
+ Assert.That (size, Is.GreaterThanOrEqualTo (10), "Struct should be at least 10 bytes");
+ Assert.That (size, Is.LessThanOrEqualTo (16), "Struct should not exceed 16 bytes with padding");
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/monotouch-test/SecurityInterface/SecKeychainTest.cs b/tests/monotouch-test/SecurityInterface/SecKeychainTest.cs
new file mode 100644
index 000000000000..854be2fe7f9d
--- /dev/null
+++ b/tests/monotouch-test/SecurityInterface/SecKeychainTest.cs
@@ -0,0 +1,73 @@
+#if __MACOS__
+using System;
+using System.IO;
+using NUnit.Framework;
+using Security;
+
+namespace MonoTouchFixtures.SecurityInterface {
+
+ [TestFixture]
+ [Preserve (AllMembers = true)]
+ public class SecKeychainTest {
+
+ [Test]
+ public void GetTypeID ()
+ {
+ var typeId = SecKeychain.GetTypeID ();
+ Assert.That ((int) typeId, Is.GreaterThan (0), "TypeID should be positive");
+ }
+
+ [Test]
+ public void GetDefault ()
+ {
+ using var keychain = SecKeychain.GetDefault ();
+ Assert.That (keychain, Is.Not.Null, "Default keychain should exist");
+ Assert.That (keychain!.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle should be non-zero");
+ }
+
+ [Test]
+ public void GetDefault_GetPath ()
+ {
+ using var keychain = SecKeychain.GetDefault ();
+ Assert.That (keychain, Is.Not.Null, "Default keychain should exist");
+ var path = keychain!.GetPath ();
+ Assert.That (path, Is.Not.Null, "Path should not be null");
+ Assert.That (path, Does.EndWith (".keychain-db").Or.EndWith (".keychain"), "Path should end with .keychain or .keychain-db");
+ }
+
+ [Test]
+ public void Open_InvalidPath_ReturnsNull ()
+ {
+ using var keychain = SecKeychain.Open ("/nonexistent/path/fake.keychain");
+ // SecKeychainOpen may succeed even for nonexistent paths (lazy open)
+ // so we just verify it doesn't crash
+ }
+
+ [Test]
+ public void Open_NullPath_Throws ()
+ {
+ Assert.Throws (() => SecKeychain.Open (null!));
+ }
+
+ [Test]
+ public void CreateAndDelete_Keychain ()
+ {
+ var tempPath = Path.Combine (Path.GetTempPath (), $"test-keychain-{Guid.NewGuid ()}.keychain");
+ try {
+ using var defaultKc = SecKeychain.GetDefault ();
+ Assert.That (defaultKc, Is.Not.Null, "Default keychain should exist");
+
+ using var opened = SecKeychain.Open (tempPath);
+ // SecKeychainOpen doesn't create the file; it just prepares a reference
+ // We can verify the handle is valid
+ if (opened is not null) {
+ Assert.That (opened.Handle, Is.Not.EqualTo (IntPtr.Zero));
+ }
+ } finally {
+ if (File.Exists (tempPath))
+ File.Delete (tempPath);
+ }
+ }
+ }
+}
+#endif // __MACOS__
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-Security.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-Security.ignore
index d93f9bedbf27..a06bbd3250a3 100644
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-Security.ignore
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-Security.ignore
@@ -11,8 +11,6 @@
!missing-enum! __CE_DataType not bound
!missing-enum! __CE_GeneralNameType not bound
!missing-enum! _SecureDownloadTrustCallbackResult not bound
-!missing-enum! AuthorizationContextFlags not bound
-!missing-enum! AuthorizationResult not bound
!missing-enum! CMSCertificateChainMode not bound
!missing-enum! CMSSignedAttributes not bound
!missing-enum! CMSSignerStatus not bound
@@ -492,4 +490,3 @@
!missing-pinvoke! SecCodeValidateFileResource is not bound
!missing-field! kSecCFErrorResourceRecursive not bound
!missing-field! kSecCodeInfoStapledNotarizationTicket not bound
-
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.ignore b/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.ignore
new file mode 100644
index 000000000000..b97f5e692977
--- /dev/null
+++ b/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.ignore
@@ -0,0 +1,14 @@
+# Informal protocol selectors bound via [Protocol (IsInformal = true), Model] interfaces
+# SFAuthorizationViewDelegate informal protocol
+!missing-selector! NSObject::authorizationViewCreatedAuthorization: not bound
+!missing-selector! NSObject::authorizationViewDidAuthorize: not bound
+!missing-selector! NSObject::authorizationViewDidDeauthorize: not bound
+!missing-selector! NSObject::authorizationViewDidHide: not bound
+!missing-selector! NSObject::authorizationViewReleasedAuthorization: not bound
+!missing-selector! NSObject::authorizationViewShouldDeauthorize: not bound
+
+# SFCertificatePanelDelegate informal protocol
+!missing-selector! NSObject::certificatePanelShowHelp: not bound
+
+# SFChooseIdentityPanelDelegate informal protocol
+!missing-selector! NSObject::chooseIdentityPanelShowHelp: not bound
diff --git a/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.todo b/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.todo
deleted file mode 100644
index 4a23e01921ad..000000000000
--- a/tests/xtro-sharpie/api-annotations-dotnet/macOS-SecurityInterface.todo
+++ /dev/null
@@ -1,118 +0,0 @@
-!missing-field! SFAuthorizationPluginViewUserNameKey not bound
-!missing-field! SFAuthorizationPluginViewUserShortNameKey not bound
-!missing-field! SFCertificateViewDisclosureStateDidChange not bound
-!missing-field! SFDisplayViewException not bound
-!missing-selector! +SFCertificatePanel::sharedCertificatePanel not bound
-!missing-selector! +SFCertificateTrustPanel::sharedCertificateTrustPanel not bound
-!missing-selector! +SFChooseIdentityPanel::sharedChooseIdentityPanel not bound
-!missing-selector! +SFKeychainSavePanel::sharedKeychainSavePanel not bound
-!missing-selector! +SFKeychainSettingsPanel::sharedKeychainSettingsPanel not bound
-!missing-selector! NSObject::authorizationViewCreatedAuthorization: not bound
-!missing-selector! NSObject::authorizationViewDidAuthorize: not bound
-!missing-selector! NSObject::authorizationViewDidDeauthorize: not bound
-!missing-selector! NSObject::authorizationViewDidHide: not bound
-!missing-selector! NSObject::authorizationViewReleasedAuthorization: not bound
-!missing-selector! NSObject::authorizationViewShouldDeauthorize: not bound
-!missing-selector! NSObject::certificatePanelShowHelp: not bound
-!missing-selector! NSObject::chooseIdentityPanelShowHelp: not bound
-!missing-selector! SFAuthorizationPluginView::buttonPressed: not bound
-!missing-selector! SFAuthorizationPluginView::callbacks not bound
-!missing-selector! SFAuthorizationPluginView::didActivate not bound
-!missing-selector! SFAuthorizationPluginView::didDeactivate not bound
-!missing-selector! SFAuthorizationPluginView::displayView not bound
-!missing-selector! SFAuthorizationPluginView::engineRef not bound
-!missing-selector! SFAuthorizationPluginView::firstKeyView not bound
-!missing-selector! SFAuthorizationPluginView::firstResponder not bound
-!missing-selector! SFAuthorizationPluginView::initWithCallbacks:andEngineRef: not bound
-!missing-selector! SFAuthorizationPluginView::lastError not bound
-!missing-selector! SFAuthorizationPluginView::lastKeyView not bound
-!missing-selector! SFAuthorizationPluginView::setButton:enabled: not bound
-!missing-selector! SFAuthorizationPluginView::setEnabled: not bound
-!missing-selector! SFAuthorizationPluginView::updateView not bound
-!missing-selector! SFAuthorizationPluginView::viewForType: not bound
-!missing-selector! SFAuthorizationPluginView::willActivateWithUser: not bound
-!missing-selector! SFAuthorizationView::authorization not bound
-!missing-selector! SFAuthorizationView::authorizationRights not bound
-!missing-selector! SFAuthorizationView::authorizationState not bound
-!missing-selector! SFAuthorizationView::authorize: not bound
-!missing-selector! SFAuthorizationView::deauthorize: not bound
-!missing-selector! SFAuthorizationView::delegate not bound
-!missing-selector! SFAuthorizationView::isEnabled not bound
-!missing-selector! SFAuthorizationView::setAuthorizationRights: not bound
-!missing-selector! SFAuthorizationView::setAutoupdate: not bound
-!missing-selector! SFAuthorizationView::setAutoupdate:interval: not bound
-!missing-selector! SFAuthorizationView::setDelegate: not bound
-!missing-selector! SFAuthorizationView::setEnabled: not bound
-!missing-selector! SFAuthorizationView::setFlags: not bound
-!missing-selector! SFAuthorizationView::setString: not bound
-!missing-selector! SFAuthorizationView::updateStatus: not bound
-!missing-selector! SFCertificatePanel::beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:certificates:showGroup: not bound
-!missing-selector! SFCertificatePanel::beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:trust:showGroup: not bound
-!missing-selector! SFCertificatePanel::certificateView not bound
-!missing-selector! SFCertificatePanel::helpAnchor not bound
-!missing-selector! SFCertificatePanel::policies not bound
-!missing-selector! SFCertificatePanel::runModalForCertificates:showGroup: not bound
-!missing-selector! SFCertificatePanel::runModalForTrust:showGroup: not bound
-!missing-selector! SFCertificatePanel::setAlternateButtonTitle: not bound
-!missing-selector! SFCertificatePanel::setDefaultButtonTitle: not bound
-!missing-selector! SFCertificatePanel::setHelpAnchor: not bound
-!missing-selector! SFCertificatePanel::setPolicies: not bound
-!missing-selector! SFCertificatePanel::setShowsHelp: not bound
-!missing-selector! SFCertificatePanel::showsHelp not bound
-!missing-selector! SFCertificateTrustPanel::beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:trust:message: not bound
-!missing-selector! SFCertificateTrustPanel::informativeText not bound
-!missing-selector! SFCertificateTrustPanel::runModalForTrust:message: not bound
-!missing-selector! SFCertificateTrustPanel::setInformativeText: not bound
-!missing-selector! SFCertificateView::certificate not bound
-!missing-selector! SFCertificateView::detailsDisclosed not bound
-!missing-selector! SFCertificateView::detailsDisplayed not bound
-!missing-selector! SFCertificateView::isEditable not bound
-!missing-selector! SFCertificateView::isTrustDisplayed not bound
-!missing-selector! SFCertificateView::policies not bound
-!missing-selector! SFCertificateView::policiesDisclosed not bound
-!missing-selector! SFCertificateView::saveTrustSettings not bound
-!missing-selector! SFCertificateView::setCertificate: not bound
-!missing-selector! SFCertificateView::setDetailsDisclosed: not bound
-!missing-selector! SFCertificateView::setDisplayDetails: not bound
-!missing-selector! SFCertificateView::setDisplayTrust: not bound
-!missing-selector! SFCertificateView::setEditableTrust: not bound
-!missing-selector! SFCertificateView::setPolicies: not bound
-!missing-selector! SFCertificateView::setPoliciesDisclosed: not bound
-!missing-selector! SFChooseIdentityPanel::beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:identities:message: not bound
-!missing-selector! SFChooseIdentityPanel::domain not bound
-!missing-selector! SFChooseIdentityPanel::helpAnchor not bound
-!missing-selector! SFChooseIdentityPanel::identity not bound
-!missing-selector! SFChooseIdentityPanel::informativeText not bound
-!missing-selector! SFChooseIdentityPanel::policies not bound
-!missing-selector! SFChooseIdentityPanel::runModalForIdentities:message: not bound
-!missing-selector! SFChooseIdentityPanel::setAlternateButtonTitle: not bound
-!missing-selector! SFChooseIdentityPanel::setDefaultButtonTitle: not bound
-!missing-selector! SFChooseIdentityPanel::setDomain: not bound
-!missing-selector! SFChooseIdentityPanel::setHelpAnchor: not bound
-!missing-selector! SFChooseIdentityPanel::setInformativeText: not bound
-!missing-selector! SFChooseIdentityPanel::setPolicies: not bound
-!missing-selector! SFChooseIdentityPanel::setShowsHelp: not bound
-!missing-selector! SFChooseIdentityPanel::showsHelp not bound
-!missing-selector! SFChooseIdentityTableCellView::issuerTextField not bound
-!missing-selector! SFChooseIdentityTableCellView::setIssuerTextField: not bound
-!missing-selector! SFKeychainSavePanel::beginSheetForDirectory:file:modalForWindow:modalDelegate:didEndSelector:contextInfo: not bound
-!missing-selector! SFKeychainSavePanel::error not bound
-!missing-selector! SFKeychainSavePanel::keychain not bound
-!missing-selector! SFKeychainSavePanel::runModalForDirectory:file: not bound
-!missing-selector! SFKeychainSavePanel::setPassword: not bound
-!missing-selector! SFKeychainSettingsPanel::beginSheetForWindow:modalDelegate:didEndSelector:contextInfo:settings:keychain: not bound
-!missing-selector! SFKeychainSettingsPanel::runModalForSettings:keychain: not bound
-!missing-type! SFAuthorizationPluginView not bound
-!missing-type! SFAuthorizationView not bound
-!missing-type! SFCertificatePanel not bound
-!missing-type! SFCertificateTrustPanel not bound
-!missing-type! SFCertificateView not bound
-!missing-type! SFChooseIdentityPanel not bound
-!missing-type! SFChooseIdentityTableCellView not bound
-!missing-type! SFKeychainSavePanel not bound
-!missing-type! SFKeychainSettingsPanel not bound
-
-# updated sharpie results
-!missing-enum! SFAuthorizationViewState not bound
-!missing-enum! SFButtonType not bound
-!missing-enum! SFViewType not bound
diff --git a/tools/common/Frameworks.cs b/tools/common/Frameworks.cs
index 3ae4d13d039f..ec990a781b43 100644
--- a/tools/common/Frameworks.cs
+++ b/tools/common/Frameworks.cs
@@ -145,6 +145,7 @@ public static Frameworks MacFrameworks {
{ "MobileCoreServices", "CoreServices", 10, 3 },
{ "OpenGL", 10, 3 },
{ "SearchKit", "CoreServices", 10,3, "SearchKit" },
+ { "SecurityInterface", 10, 3 },
{ "SystemConfiguration", 10, 3 },
{ "CoreData", 10, 4 },