Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c062e18
Native Interop Layer
liveans Jun 16, 2025
ecba3f7
Native Layer Compilation fix for Mono + NativeAOT + templates
liveans Jun 16, 2025
bf130f3
First shape of new native + interop
liveans Jun 25, 2025
0dcc599
Newlines at the end of files
liveans Jun 25, 2025
44b3597
Default constructor ownsHandle to true
liveans Jun 25, 2025
3cbcea7
Delete couple of unsafe keyword in Interop
liveans Jun 25, 2025
3defe85
Update src/native/libs/System.Net.Security.Native.Apple/pal_networkfr…
liveans Jun 25, 2025
57a7069
Merge branch 'main' into network_framework_integration_native_interop
liveans Jun 25, 2025
c1a2b6b
Fix PlatformManifestFileEntry
liveans Jun 25, 2025
0977679
Review feedback
liveans Jun 25, 2025
fe343b0
Apply suggestions from code review
liveans Jun 26, 2025
0fff060
Update src/libraries/Common/src/Interop/OSX/Interop.Network.Tls.cs
liveans Jun 26, 2025
3441093
Review feedbacks
liveans Jun 28, 2025
3e547c5
Merge branch 'main' into network_framework_integration_native_interop
liveans Jun 28, 2025
25b8950
Further review feedback
liveans Jun 28, 2025
91238c5
Add new library name to nativeaot build target file
liveans Jun 28, 2025
a250b67
Merge branch 'main' into network_framework_integration_native_interop
liveans Jun 28, 2025
beb5f93
Merge System.Net.Security.Native.Apple with System.Security.Cryptogra…
rzikm Jul 1, 2025
0ab06b2
fixup! Merge System.Net.Security.Native.Apple with System.Security.Cr…
rzikm Jul 1, 2025
39bef6d
Shared OSStatus
rzikm Jul 1, 2025
8267454
Correctly release some handles
rzikm Jul 1, 2025
4bf6eb9
Remove printf
rzikm Jul 1, 2025
f771ea9
Add comments
rzikm Jul 1, 2025
6ab3942
Fix build
rzikm Jul 2, 2025
cc950a1
Merge branch 'main' into network_framework_integration_native_interop
liveans Jul 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<NativeFramework Include="CoreFoundation" />
<NativeFramework Include="CryptoKit" />
<NativeFramework Include="Foundation" />
<NativeFramework Include="Network" />
<NativeFramework Include="Security" />
<!-- The library builds don't reference the GSS API on tvOS builds. -->
<NativeFramework Condition="!$(_targetOS.StartsWith('tvos'))" Include="GSS" />
Expand Down
1 change: 1 addition & 0 deletions src/libraries/Common/src/Interop/OSX/Interop.Libraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal static partial class Libraries
internal const string OpenLdap = "libldap.dylib";
internal const string SystemConfigurationLibrary = "/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration";
internal const string AppleCryptoNative = "libSystem.Security.Cryptography.Native.Apple";
internal const string NetworkFramework = "/System/Library/Frameworks/Network.framework/Network";
internal const string MsQuic = "libmsquic.dylib";
}
}
142 changes: 142 additions & 0 deletions src/libraries/Common/src/Interop/OSX/Interop.NetworkFramework.Tls.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
{
// TLS 1.3 specific Network Framework implementation for macOS
internal static partial class NetworkFramework
{
internal static partial class Tls
{
// Initialize internal shim for NetworkFramework integration
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwInit")]
[return: MarshalAs(UnmanagedType.I4)]
internal static unsafe partial bool Init(
delegate* unmanaged<IntPtr, StatusUpdates, IntPtr, IntPtr, void> statusCallback,
delegate* unmanaged<IntPtr, byte*, void**, int> readCallback,
delegate* unmanaged<IntPtr, byte*, void**, int> writeCallback);

// Create a new connection context
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwCreateContext")]
internal static partial SafeNwHandle CreateContext([MarshalAs(UnmanagedType.I4)] bool isServer);

// Set TLS options for a connection
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwSetTlsOptions", StringMarshalling = StringMarshalling.Utf8)]
private static partial void SetTlsOptions(SafeNwHandle connection, IntPtr state,
string targetName, Span<byte> alpnBuffer, int alpnLength, SslProtocols minTlsProtocol, SslProtocols maxTlsProtocol);

internal static void SetTlsOptions(SafeNwHandle nwHandle, IntPtr state, string targetName, List<SslApplicationProtocol>? applicationProtocols, SslProtocols minTlsVersion, SslProtocols maxTlsVersion)
{
int alpnLength = GetAlpnProtocolListSerializedLength(applicationProtocols);
Span<byte> alpn = stackalloc byte[256];
SerializeAlpnProtocolList(applicationProtocols, alpn);

SetTlsOptions(nwHandle, state, targetName, alpn, alpnLength, minTlsVersion, maxTlsVersion);
}

// Start the TLS handshake, notifications are received via the status callback (potentially from a different thread).
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwStartTlsHandshake")]
internal static partial int StartTlsHandshake(SafeNwHandle connection, IntPtr state);

// takes encrypted input from underlying stream and feed it to the connection.
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwProcessInputData")]
internal static unsafe partial int ProcessInputData(SafeNwHandle connection, SafeNwHandle framer, byte* buffer, int bufferLength);

// sends plaintext data to the connection.
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwSendToConnection")]
internal static unsafe partial void SendToConnection(SafeNwHandle connection, IntPtr state, void* buffer, int bufferLength);

// read plaintext data from the connection.
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwReadFromConnection")]
internal static partial void ReadFromConnection(SafeNwHandle connection, IntPtr state);

// starts connection cleanup
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwCancelConnection")]
internal static partial void CancelConnection(SafeNwHandle connection);

// gets TLS connection information
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwGetConnectionInfo")]
internal static unsafe partial int GetConnectionInfo(SafeNwHandle connection, out SslProtocols pProtocol, out TlsCipherSuite pCipherSuiteOut, ref byte* negotiatedAlpn, out int negotiatedAlpnLength);

// copies the certificate chain from the connection
[LibraryImport(Interop.Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_NwCopyCertChain")]
internal static partial void CopyCertChain(SafeNwHandle connection, out SafeCFArrayHandle certificates, out int count);

internal static int GetAlpnProtocolListSerializedLength(List<SslApplicationProtocol>? applicationProtocols)
{
if (applicationProtocols is null)
{
return 0;
}

int protocolSize = 0;

foreach (SslApplicationProtocol protocol in applicationProtocols)
{
protocolSize += protocol.Protocol.Length + 2;
}

return protocolSize;
}

private static void SerializeAlpnProtocolList(List<SslApplicationProtocol>? applicationProtocols, Span<byte> buffer)
{
if (applicationProtocols is null)
{
return;
}

Debug.Assert(GetAlpnProtocolListSerializedLength(applicationProtocols) == buffer.Length);

int offset = 0;
foreach (SslApplicationProtocol protocol in applicationProtocols)
{
buffer[offset++] = (byte)protocol.Protocol.Length;
protocol.Protocol.Span.CopyTo(buffer.Slice(offset));
offset += protocol.Protocol.Length;
buffer[offset++] = 0;
}
}
}

// Status enumeration for Network Framework TLS operations
internal enum StatusUpdates
{
UnknownError = 0,
FramerStart = 1,
FramerStop = 2,
HandshakeFinished = 3,
HandshakeFailed = 4,
ConnectionReadFinished = 100,
ConnectionWriteFinished = 101,
ConnectionWriteFailed = 102,
ConnectionCancelled = 103,
}
}

// Safe handle classes for Network Framework TLS resources
internal sealed class SafeNwHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeNwHandle() : base(ownsHandle: true) { }

public SafeNwHandle(IntPtr handle, bool ownsHandle) : base(ownsHandle)
{
SetHandle(handle);
}

protected override bool ReleaseHandle()
{
NetworkFramework.Release(handle);
SetHandle(IntPtr.Zero);
return true;
}
}
}
18 changes: 18 additions & 0 deletions src/libraries/Common/src/Interop/OSX/Interop.NetworkFramework.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class NetworkFramework
{
// Network Framework reference counting functions
[LibraryImport(Libraries.NetworkFramework, EntryPoint = "nw_retain")]
internal static partial IntPtr Retain(IntPtr obj);

[LibraryImport(Libraries.NetworkFramework, EntryPoint = "nw_release")]
internal static partial void Release(IntPtr obj);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

internal static partial class Interop
{
internal static partial class AppleCrypto
{
internal static class OSStatus
{
public const int NoErr = 0;
public const int ReadErr = -19;
public const int WritErr = -20;
public const int ErrSSLWouldBlock = -9803;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,12 @@
Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Ssl.cs" />
<Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.X509Chain.cs"
Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.X509Chain.cs" />
<Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.OSStatus.cs"
Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.OSStatus.cs" />
<Compile Include="$(CommonPath)Interop\OSX\Interop.NetworkFramework.cs"
Link="Common\Interop\OSX\Interop.NetworkFramework.cs" />
<Compile Include="$(CommonPath)Interop\OSX\Interop.NetworkFramework.Tls.cs"
Link="Common\Interop\OSX\Interop.NetworkFramework.Tls.cs" />
<Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs"
Link="Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs" />
<Compile Include="System\Net\CertificateValidationPal.OSX.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Win32.SafeHandles;
using OSStatus = Interop.AppleCrypto.OSStatus;

namespace System.Net
{
internal sealed class SafeDeleteSslContext : SafeDeleteContext
{
// mapped from OSX error codes
private const int OSStatus_writErr = -20;
private const int OSStatus_readErr = -19;
private const int OSStatus_noErr = 0;
private const int OSStatus_errSSLWouldBlock = -9803;
private const int InitialBufferSize = 2048;
private readonly SafeSslHandle _sslContext;
private ArrayBuffer _inputBuffer = new ArrayBuffer(InitialBufferSize);
Expand Down Expand Up @@ -241,14 +238,14 @@ private static unsafe int WriteToConnection(IntPtr connection, byte* data, void*
context._outputBuffer.Commit(toWrite);
// Since we can enqueue everything, no need to re-assign *dataLength.

return OSStatus_noErr;
return OSStatus.NoErr;
}
}
catch (Exception e)
{
if (NetEventSource.Log.IsEnabled())
NetEventSource.Error(context, $"WritingToConnection failed: {e.Message}");
return OSStatus_writErr;
return OSStatus.WritErr;
}
}

Expand All @@ -266,15 +263,15 @@ private static unsafe int ReadFromConnection(IntPtr connection, byte* data, void

if (toRead == 0)
{
return OSStatus_noErr;
return OSStatus.NoErr;
}

uint transferred = 0;

if (context._inputBuffer.ActiveLength == 0)
{
*dataLength = (void*)0;
return OSStatus_errSSLWouldBlock;
return OSStatus.ErrSSLWouldBlock;
}

int limit = Math.Min((int)toRead, context._inputBuffer.ActiveLength);
Expand All @@ -284,14 +281,14 @@ private static unsafe int ReadFromConnection(IntPtr connection, byte* data, void
transferred = (uint)limit;

*dataLength = (void*)transferred;
return OSStatus_noErr;
return OSStatus.NoErr;
}
}
catch (Exception e)
{
if (NetEventSource.Log.IsEnabled())
NetEventSource.Error(context, $"ReadFromConnectionfailed: {e.Message}");
return OSStatus_readErr;
return OSStatus.ReadErr;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/mono/msbuild/apple/build/AppleBuild.targets
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<_CommonLinkerArgs Include="-lswiftCore" />
<_CommonLinkerArgs Include="-lswiftFoundation" />
<_CommonLinkerArgs Include="-framework Foundation" />
<_CommonLinkerArgs Include="-framework Network" />
<_CommonLinkerArgs Include="-framework Security" />
<_CommonLinkerArgs Include="-framework CryptoKit" />
<_CommonLinkerArgs Include="-framework UIKit" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ set(NATIVECRYPTO_SOURCES
pal_x509.c
pal_x509chain.c
pal_swiftbindings.o
pal_networkframework.m
)

if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "pal_x509.h"
#include "pal_x509_macos.h"
#include "pal_x509chain.h"
#include "pal_networkframework.h"

static const Entry s_cryptoAppleNative[] =
{
Expand Down Expand Up @@ -137,6 +138,16 @@ static const Entry s_cryptoAppleNative[] =
DllImportEntry(AppleCryptoNative_X509StoreRemoveCertificate)
DllImportEntry(AppleCryptoNative_Pbkdf2)
DllImportEntry(AppleCryptoNative_X509GetSubjectSummary)
DllImportEntry(AppleCryptoNative_NwInit)
DllImportEntry(AppleCryptoNative_NwCreateContext)
DllImportEntry(AppleCryptoNative_NwSetTlsOptions)
DllImportEntry(AppleCryptoNative_NwStartTlsHandshake)
DllImportEntry(AppleCryptoNative_NwProcessInputData)
DllImportEntry(AppleCryptoNative_NwSendToConnection)
DllImportEntry(AppleCryptoNative_NwReadFromConnection)
DllImportEntry(AppleCryptoNative_NwCancelConnection)
DllImportEntry(AppleCryptoNative_NwGetConnectionInfo)
DllImportEntry(AppleCryptoNative_NwCopyCertChain)
};

EXTERN_C const void* CryptoAppleResolveDllImport(const char* name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
macro(append_extra_cryptography_apple_libs NativeLibsExtra)
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
find_library(SECURITY_LIBRARY Security)
find_library(NETWORK_LIBRARY Network)
find_library(CRYPTOKIT_LIBRARY CryptoKit)

list(APPEND ${NativeLibsExtra} ${COREFOUNDATION_LIBRARY} ${SECURITY_LIBRARY} ${CRYPTOKIT_LIBRARY} -L/usr/lib/swift -lobjc -lswiftCore -lswiftFoundation)
list(APPEND ${NativeLibsExtra} ${COREFOUNDATION_LIBRARY} ${SECURITY_LIBRARY} ${NETWORK_LIBRARY} ${CRYPTOKIT_LIBRARY} -L/usr/lib/swift -lobjc -lswiftCore -lswiftFoundation)
endmacro()
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma once

#include "pal_compiler.h"
#include <pal_ssl_types.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h> // for intptr_t

#ifdef __OBJC__
#import <Network/Network.h>
#else
#include <Network/Network.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

// Status update enumeration for TLS operations
typedef enum
{
PAL_NwStatusUpdates_UnknownError = 0,
PAL_NwStatusUpdates_FramerStart = 1,
PAL_NwStatusUpdates_FramerStop = 2,
PAL_NwStatusUpdates_HandshakeFinished = 3,
PAL_NwStatusUpdates_HandshakeFailed = 4,

PAL_NwStatusUpdates_ConnectionReadFinished = 100,
PAL_NwStatusUpdates_ConnectionWriteFinished = 101,
PAL_NwStatusUpdates_ConnectionWriteFailed = 102,
PAL_NwStatusUpdates_ConnectionCancelled = 103,
} PAL_NwStatusUpdates;

// Callback type definitions that match the implementation usage
typedef void (*StatusUpdateCallback)(size_t context, PAL_NwStatusUpdates status, size_t data1, size_t data2);
typedef int32_t (*ReadCallback)(void* context, uint8_t* buffer, size_t* length);
typedef int32_t (*WriteCallback)(void* context, uint8_t* buffer, size_t length);

// Only TLS-specific Network Framework functions are exported
PALEXPORT nw_connection_t AppleCryptoNative_NwCreateContext(int32_t isServer);
PALEXPORT int32_t AppleCryptoNative_NwStartTlsHandshake(nw_connection_t connection, size_t gcHandle);
PALEXPORT int32_t AppleCryptoNative_NwInit(StatusUpdateCallback statusFunc, ReadCallback readFunc, WriteCallback writeFunc);
PALEXPORT void AppleCryptoNative_NwSendToConnection(nw_connection_t connection, size_t gcHandle, uint8_t* buffer, int length);
PALEXPORT void AppleCryptoNative_NwReadFromConnection(nw_connection_t connection, size_t gcHandle);
PALEXPORT int32_t AppleCryptoNative_NwProcessInputData(nw_connection_t connection, nw_framer_t framer, const uint8_t * data, int dataLength);
PALEXPORT void AppleCryptoNative_NwSetTlsOptions(nw_connection_t connection, size_t gcHandle, char* targetName, const uint8_t* alpnBuffer, int alpnLength, PAL_SslProtocol minTlsProtocol, PAL_SslProtocol maxTlsProtocol);
PALEXPORT int32_t AppleCryptoNative_NwGetConnectionInfo(nw_connection_t connection, PAL_SslProtocol* pProtocol, uint16_t* pCipherSuiteOut, const char** negotiatedAlpn, int32_t* negotiatedAlpnLength);
PALEXPORT void AppleCryptoNative_NwCopyCertChain(nw_connection_t connection, CFArrayRef* certificates, int* count);
PALEXPORT void AppleCryptoNative_NwCancelConnection(nw_connection_t connection);

#ifdef __cplusplus
}
#endif
Loading
Loading