From 6265bb1d6e2bd160e27a58dda159a65525f3dd8b Mon Sep 17 00:00:00 2001 From: Radek Zikmund Date: Wed, 4 Oct 2023 18:13:26 +0200 Subject: [PATCH] Expose TLS details for QUIC connection --- .../System.Net.Quic/ref/System.Net.Quic.cs | 9 +++ .../src/System/Net/Quic/QuicConnection.cs | 80 +++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs b/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs index 96a53e2bceb155..7c2921c30bc769 100644 --- a/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs +++ b/src/libraries/System.Net.Quic/ref/System.Net.Quic.cs @@ -23,11 +23,20 @@ public QuicClientConnectionOptions() { } public sealed partial class QuicConnection : System.IAsyncDisposable { internal QuicConnection() { } + public System.Security.Authentication.CipherAlgorithmType CipherAlgorithm { get { throw null; } } + public int CipherStrength { get { throw null; } } + public System.Security.Authentication.HashAlgorithmType HashAlgorithm { get { throw null; } } + public int HashStrength { get { throw null; } } public static bool IsSupported { get { throw null; } } + public System.Security.Authentication.ExchangeAlgorithmType KeyExchangeAlgorithm { get { throw null; } } + public int KeyExchangeStrength { get { throw null; } } public System.Net.IPEndPoint LocalEndPoint { get { throw null; } } public System.Net.Security.SslApplicationProtocol NegotiatedApplicationProtocol { get { throw null; } } + [System.CLSCompliantAttribute(false)] + public System.Net.Security.TlsCipherSuite NegotiatedCipherSuite { get { throw null; } } public System.Security.Cryptography.X509Certificates.X509Certificate? RemoteCertificate { get { throw null; } } public System.Net.IPEndPoint RemoteEndPoint { get { throw null; } } + public System.Security.Authentication.SslProtocols SslProtocol { get { throw null; } } public string TargetHostName { get { throw null; } } public System.Threading.Tasks.ValueTask AcceptInboundStreamAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public System.Threading.Tasks.ValueTask CloseAsync(long errorCode, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs index 5a4f626e2f5465..003c667b4f800c 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/QuicConnection.cs @@ -7,12 +7,19 @@ using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; +using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using Microsoft.Quic; using static Microsoft.Quic.MsQuic; +using static Microsoft.Quic.QUIC_CIPHER_ALGORITHM; +using static Microsoft.Quic.QUIC_CIPHER_SUITE; +using static Microsoft.Quic.QUIC_HASH_ALGORITHM; +using static Microsoft.Quic.QUIC_KEY_EXCHANGE_ALGORITHM; +using static Microsoft.Quic.QUIC_TLS_PROTOCOL_VERSION; + using CONNECTED_DATA = Microsoft.Quic.QUIC_CONNECTION_EVENT._Anonymous_e__Union._CONNECTED_e__Struct; using LOCAL_ADDRESS_CHANGED_DATA = Microsoft.Quic.QUIC_CONNECTION_EVENT._Anonymous_e__Union._LOCAL_ADDRESS_CHANGED_e__Struct; using PEER_ADDRESS_CHANGED_DATA = Microsoft.Quic.QUIC_CONNECTION_EVENT._Anonymous_e__Union._PEER_ADDRESS_CHANGED_e__Struct; @@ -223,6 +230,40 @@ public X509Certificate? RemoteCertificate } } + /// + /// Gets the corresponding to the TLS version used during the connection handshake. + /// + public SslProtocols SslProtocol { get; private set; } + + /// + /// Gets the cipher suite which was negotiated for this connection. + /// + [CLSCompliant(false)] + public TlsCipherSuite NegotiatedCipherSuite { get; private set; } + + /// + /// Gets a value that identifies the bulk encryption algorithm used by this connection. + /// + public CipherAlgorithmType CipherAlgorithm { get; private set; } + + /// + /// Gets a value that identifies the strength of the cipher algorithm used by this connection. + /// + public int CipherStrength { get; private set; } + + // + // defined in SslStream but we don't need it as QUIC uses AEAD which don't use the hash algorithm + // from the cipher suite + // + public HashAlgorithmType HashAlgorithm { get; private set; } + public int HashStrength { get; private set; } + + // + // based on SslConnectionInfo.Unix.cs it would return 0/None in all cases + // + public ExchangeAlgorithmType KeyExchangeAlgorithm { get; private set; } + public int KeyExchangeStrength { get; private set; } + /// /// Final, negotiated application protocol. /// @@ -514,6 +555,45 @@ private unsafe int HandleEventConnected(ref CONNECTED_DATA data) _tlsSecret?.WriteSecret(); #endif + QUIC_HANDSHAKE_INFO handshakeInfo = MsQuicHelpers.GetMsQuicParameter(_handle, QUIC_PARAM_TLS_HANDSHAKE_INFO); + + SslProtocol = handshakeInfo.TlsProtocolVersion switch + { + QUIC_TLS_PROTOCOL_VERSION.TLS_1_3 => SslProtocols.Tls13, + _ => SslProtocols.None, + }; + + CipherAlgorithm = handshakeInfo.CipherAlgorithm switch + { + QUIC_CIPHER_ALGORITHM.AES_128 => CipherAlgorithmType.Aes128, + QUIC_CIPHER_ALGORITHM.AES_256 => CipherAlgorithmType.Aes256, + QUIC_CIPHER_ALGORITHM.CHACHA20 => CipherAlgorithmType.None, // TODO: CipherAlgorithmType.ChaCha20, + _ => CipherAlgorithmType.None, + }; + CipherStrength = handshakeInfo.CipherStrength; + + HashAlgorithm = handshakeInfo.Hash switch + { + QUIC_HASH_ALGORITHM.SHA_256 => HashAlgorithmType.Sha256, + QUIC_HASH_ALGORITHM.SHA_384 => HashAlgorithmType.Sha384, + _ => HashAlgorithmType.None, + }; + HashStrength = handshakeInfo.HashStrength; + + KeyExchangeAlgorithm = handshakeInfo.KeyExchangeAlgorithm switch + { + _ => ExchangeAlgorithmType.None, + }; + KeyExchangeStrength = handshakeInfo.KeyExchangeStrength; + + NegotiatedCipherSuite = handshakeInfo.CipherSuite switch + { + QUIC_CIPHER_SUITE.TLS_AES_128_GCM_SHA256 => TlsCipherSuite.TLS_AES_128_GCM_SHA256, + QUIC_CIPHER_SUITE.TLS_AES_256_GCM_SHA384 => TlsCipherSuite.TLS_AES_256_GCM_SHA384, + QUIC_CIPHER_SUITE.TLS_CHACHA20_POLY1305_SHA256 => TlsCipherSuite.TLS_CHACHA20_POLY1305_SHA256, + _ => TlsCipherSuite.TLS_AES_128_GCM_SHA256, + }; + if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"{this} Connection connected {LocalEndPoint} -> {RemoteEndPoint} for {_negotiatedApplicationProtocol} protocol");