Skip to content

Commit

Permalink
add AllowTlsResume to SslStream options (#86047)
Browse files Browse the repository at this point in the history
* add AllowTlsResume to SslStream options

* debug

* test

* dwSessionLifespan

* feedback

* update

* feedback
  • Loading branch information
wfurt committed Jun 28, 2023
1 parent 5ec1f15 commit 1815306
Show file tree
Hide file tree
Showing 23 changed files with 296 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ internal static SafeSslHandle AllocateSslHandle(SslAuthenticationOptions sslAuth
SafeSslContextHandle? newCtxHandle = null;
SslProtocols protocols = CalculateEffectiveProtocols(sslAuthenticationOptions);
bool hasAlpn = sslAuthenticationOptions.ApplicationProtocols != null && sslAuthenticationOptions.ApplicationProtocols.Count != 0;
bool cacheSslContext = !DisableTlsResume && sslAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.RequireEncryption && sslAuthenticationOptions.CipherSuitesPolicy == null;
bool cacheSslContext = sslAuthenticationOptions.AllowTlsResume && !DisableTlsResume && sslAuthenticationOptions.EncryptionPolicy == EncryptionPolicy.RequireEncryption && sslAuthenticationOptions.CipherSuitesPolicy == null;

if (cacheSslContext)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ internal static partial class SChannel
// to be passed into ApplyControlToken
// through a PkgParams buffer.

public const int SCHANNEL_RENEGOTIATE = 0; // renegotiate a connection
public const int SCHANNEL_SHUTDOWN = 1; // gracefully close down a connection
public const int SCHANNEL_ALERT = 2; // build an error message
public const int SCHANNEL_SESSION = 3; // session control


// Alert token structure.
[StructLayout(LayoutKind.Sequential)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class SChannel
{
// schannel.h;

public const int SCHANNEL_SESSION = 3; // session control

// Session structure.
[StructLayout(LayoutKind.Sequential)]
public struct SCHANNEL_SESSION_TOKEN
{
public uint dwTokenType; // SCHANNEL_SESSION
public uint dwFlags;
}

public const int SSL_SESSION_ENABLE_RECONNECTS = 1;
public const int SSL_SESSION_DISABLE_RECONNECTS = 2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ internal interface ISSPIInterface
int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, Span<byte> buffer, Type? handleType, out SafeHandle? refHandle);
int QuerySecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle phToken);
int CompleteAuthToken(ref SafeDeleteSslContext? refContext, in InputSecurityBuffer inputBuffer);
int ApplyControlToken(ref SafeDeleteContext? refContext, in SecurityBuffer inputBuffer);
int ApplyControlToken(ref SafeDeleteSslContext? refContext, in SecurityBuffer inputBuffer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ public enum Flags
SCH_CRED_MANUAL_CRED_VALIDATION = 0x08,
SCH_CRED_NO_DEFAULT_CREDS = 0x10,
SCH_CRED_AUTO_CRED_VALIDATION = 0x20,
SCH_CRED_DISABLE_RECONNECTS = 0x80,
SCH_CRED_REVOCATION_CHECK_END_CERT = 0x100,
SCH_CRED_IGNORE_NO_REVOCATION_CHECK = 0x800,
SCH_CRED_IGNORE_REVOCATION_OFFLINE = 0x1000,
Expand Down Expand Up @@ -239,7 +240,7 @@ public enum Flags
SCH_CRED_NO_DEFAULT_CREDS = 0x10,
SCH_CRED_AUTO_CRED_VALIDATION = 0x20,
SCH_CRED_USE_DEFAULT_CREDS = 0x40,
SCH_DISABLE_RECONNECTS = 0x80,
SCH_CRED_DISABLE_RECONNECTS = 0x80,
SCH_CRED_REVOCATION_CHECK_END_CERT = 0x100,
SCH_CRED_REVOCATION_CHECK_CHAIN = 0x200,
SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x400,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ private static int GetSecurityContextToken(SafeDeleteContext phContext, out Secu
}
}

public int ApplyControlToken(ref SafeDeleteContext? refContext, in SecurityBuffer inputBuffers)
public int ApplyControlToken(ref SafeDeleteSslContext? refContext, in SecurityBuffer inputBuffers)
{
throw new NotSupportedException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public int CompleteAuthToken(ref SafeDeleteSslContext? refContext, in InputSecur
throw new NotSupportedException();
}

public int ApplyControlToken(ref SafeDeleteContext? refContext, in SecurityBuffer inputBuffer)
public int ApplyControlToken(ref SafeDeleteSslContext? refContext, in SecurityBuffer inputBuffer)
{
return SafeDeleteContext.ApplyControlToken(ref refContext, in inputBuffer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ internal static int CompleteAuthToken(ISSPIInterface secModule, ref SafeDeleteSs
return errorCode;
}

internal static int ApplyControlToken(ISSPIInterface secModule, ref SafeDeleteContext? context, in SecurityBuffer inputBuffer)
internal static int ApplyControlToken(ISSPIInterface secModule, ref SafeDeleteSslContext? context, in SecurityBuffer inputBuffer)
{
int errorCode = secModule.ApplyControlToken(ref context, in inputBuffer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ internal static unsafe int CompleteAuthToken(
}

internal static unsafe int ApplyControlToken(
ref SafeDeleteContext? refContext,
ref SafeDeleteSslContext? refContext,
in SecurityBuffer inSecBuffer)
{
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(null, $"refContext = {refContext}, inSecBuffer = {inSecBuffer}");
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/System.Net.Security/ref/System.Net.Security.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public partial class SslClientAuthenticationOptions
{
public SslClientAuthenticationOptions() { }
public bool AllowRenegotiation { get { throw null; } set { } }
public bool AllowTlsResume { get { throw null; } set { } }
public System.Collections.Generic.List<System.Net.Security.SslApplicationProtocol>? ApplicationProtocols { get { throw null; } set { } }
public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } }
public System.Security.Cryptography.X509Certificates.X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }
Expand All @@ -223,6 +224,7 @@ public partial class SslServerAuthenticationOptions
{
public SslServerAuthenticationOptions() { }
public bool AllowRenegotiation { get { throw null; } set { } }
public bool AllowTlsResume { get { throw null; } set { } }
public System.Collections.Generic.List<System.Net.Security.SslApplicationProtocol>? ApplicationProtocols { get { throw null; } set { } }
public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } }
public System.Security.Cryptography.X509Certificates.X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@
Link="Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs" />
<Compile Include="$(CommonPath)Interop\Windows\SChannel\Interop.Alerts.cs"
Link="Common\Interop\Windows\SChannel\Interop.Alerts.cs" />
<Compile Include="$(CommonPath)Interop\Windows\SChannel\Interop.Session.cs"
Link="Common\Interop\Windows\SChannel\Interop.Session.cs" />
<Compile Include="$(CommonPath)Interop\Windows\SChannel\Interop.SchProtocols.cs"
Link="Common\Interop\Windows\SChannel\Interop.SchProtocols.cs" />
<Compile Include="$(CommonPath)Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticati

// Common options.
AllowRenegotiation = sslClientAuthenticationOptions.AllowRenegotiation;
AllowTlsResume = sslClientAuthenticationOptions.AllowTlsResume;
ApplicationProtocols = sslClientAuthenticationOptions.ApplicationProtocols;
CheckCertName = !(sslClientAuthenticationOptions.CertificateChainPolicy?.VerificationFlags.HasFlag(X509VerificationFlags.IgnoreInvalidName) == true);
EnabledSslProtocols = FilterOutIncompatibleSslProtocols(sslClientAuthenticationOptions.EnabledSslProtocols);
Expand Down Expand Up @@ -105,6 +106,7 @@ internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticati

IsServer = true;
AllowRenegotiation = sslServerAuthenticationOptions.AllowRenegotiation;
AllowTlsResume = sslServerAuthenticationOptions.AllowTlsResume;
ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols;
EnabledSslProtocols = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols);
EncryptionPolicy = sslServerAuthenticationOptions.EncryptionPolicy;
Expand Down Expand Up @@ -183,6 +185,7 @@ private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols proto
internal object? UserState { get; set; }
internal ServerOptionsSelectionCallback? ServerOptionDelegate { get; set; }
internal X509ChainPolicy? CertificateChainPolicy { get; set; }
internal bool AllowTlsResume { get; set; }

#if TARGET_ANDROID
internal SslStream.JavaProxy? SslStreamProxy { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,23 @@ public class SslClientAuthenticationOptions
private X509RevocationMode _checkCertificateRevocation = X509RevocationMode.NoCheck;
private SslProtocols _enabledSslProtocols = SecurityProtocol.SystemDefaultSecurityProtocols;
private bool _allowRenegotiation = true;
private bool _allowTlsResume = true;

public bool AllowRenegotiation
{
get => _allowRenegotiation;
set => _allowRenegotiation = value;
}

/// <summary>
/// Gets or sets a value that indicates whether the SslStream should allow TLS resumption.
/// </summary>
public bool AllowTlsResume
{
get => _allowTlsResume;
set => _allowTlsResume = value;
}

public LocalCertificateSelectionCallback? LocalCertificateSelectionCallback { get; set; }

public RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public void UpdateSslConnectionInfo(SafeSslHandle sslContext)
{
ApplicationProtocol = alpn.ToArray();
}

#if DEBUG
TlsResumed = Interop.Ssl.SslSessionReused(sslContext);
#endif
MapCipherSuite(SslGetCurrentCipherSuite(sslContext));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using static Interop.SspiCli;

namespace System.Net.Security
{
Expand Down Expand Up @@ -66,6 +67,16 @@ public void UpdateSslConnectionInfo(SafeDeleteContext securityContext)
TlsCipherSuite = cipherSuite;

ApplicationProtocol = GetNegotiatedApplicationProtocol(securityContext);

#if DEBUG
SecPkgContext_SessionInfo info = default;
TlsResumed = SSPIWrapper.QueryBlittableContextAttributes(
GlobalSSPI.SSPISecureChannel,
securityContext,
Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SESSION_INFO,
ref info) &&
((SecPkgContext_SessionInfo.Flags)info.dwFlags).HasFlag(SecPkgContext_SessionInfo.Flags.SSL_SESSION_RECONNECT);
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ internal partial struct SslConnectionInfo
public int KeyExchKeySize { get; private set; }

public byte[]? ApplicationProtocol { get; internal set; }
#if DEBUG
public bool TlsResumed { get; private set; }
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,23 @@ public class SslServerAuthenticationOptions
private SslProtocols _enabledSslProtocols = SecurityProtocol.SystemDefaultSecurityProtocols;
private EncryptionPolicy _encryptionPolicy = EncryptionPolicy.RequireEncryption;
private bool _allowRenegotiation;
private bool _allowTlsResume = true;

public bool AllowRenegotiation
{
get => _allowRenegotiation;
set => _allowRenegotiation = value;
}

/// <summary>
/// Gets or sets a value that indicates whether the SslStream should allow TLS resumption.
/// </summary>
public bool AllowTlsResume
{
get => _allowTlsResume;
set => _allowTlsResume = value;
}

public bool ClientCertificateRequired { get; set; }

public List<SslApplicationProtocol>? ApplicationProtocols { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ internal static class SslSessionsCache
private readonly bool _isServerMode;
private readonly bool _sendTrustList;
private readonly bool _checkRevocation;
private readonly bool _allowTlsResume;

//
// SECURITY: X509Certificate.GetCertHash() is virtual hence before going here,
Expand All @@ -40,46 +41,33 @@ internal SslCredKey(
bool isServerMode,
EncryptionPolicy encryptionPolicy,
bool sendTrustList,
bool checkRevocation)
bool checkRevocation,
bool allowTlsResume)
{
_thumbPrint = thumbPrint ?? Array.Empty<byte>();
_allowedProtocols = allowedProtocols;
_encryptionPolicy = encryptionPolicy;
_isServerMode = isServerMode;
_checkRevocation = checkRevocation;
_sendTrustList = sendTrustList;
_allowTlsResume = allowTlsResume;
}

public override int GetHashCode()
{
int hashCode = 0;

if (_thumbPrint.Length > 0)
if (_thumbPrint.Length > 3)
{
hashCode ^= _thumbPrint[0];
if (1 < _thumbPrint.Length)
{
hashCode ^= (_thumbPrint[1] << 8);
}

if (2 < _thumbPrint.Length)
{
hashCode ^= (_thumbPrint[2] << 16);
}

if (3 < _thumbPrint.Length)
{
hashCode ^= (_thumbPrint[3] << 24);
}
hashCode ^= _thumbPrint[0] | (_thumbPrint[1] << 8) | (_thumbPrint[2] << 16) | (_thumbPrint[3] << 24);
}

hashCode ^= _allowedProtocols;
hashCode ^= (int)_encryptionPolicy;
hashCode ^= _isServerMode ? 0x10000 : 0x20000;
hashCode ^= _sendTrustList ? 0x40000 : 0x80000;
hashCode ^= _checkRevocation ? 0x100000 : 0x200000;

return hashCode;
return HashCode.Combine(_allowedProtocols,
(int)_encryptionPolicy,
_isServerMode,
_sendTrustList,
_checkRevocation,
_allowedProtocols,
hashCode);
}

public override bool Equals([NotNullWhen(true)] object? obj) =>
Expand All @@ -97,6 +85,7 @@ public bool Equals(SslCredKey other)
_isServerMode == other._isServerMode &&
_sendTrustList == other._sendTrustList &&
_checkRevocation == other._checkRevocation &&
_allowTlsResume == other._allowTlsResume &&
thumbPrint.AsSpan().SequenceEqual(otherThumbPrint);
}
}
Expand All @@ -113,15 +102,16 @@ public bool Equals(SslCredKey other)
bool isServer,
EncryptionPolicy encryptionPolicy,
bool checkRevocation,
bool sendTrustList = false)
bool allowTlsResume,
bool sendTrustList)
{
if (s_cachedCreds.IsEmpty)
{
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(null, $"Not found, Current Cache Count = {s_cachedCreds.Count}");
return null;
}

var key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation);
var key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation, allowTlsResume);

//SafeCredentialReference? cached;
SafeFreeCredentials? credentials = GetCachedCredential(key);
Expand Down Expand Up @@ -153,7 +143,8 @@ internal static void CacheCredential(
bool isServer,
EncryptionPolicy encryptionPolicy,
bool checkRevocation,
bool sendTrustList = false)
bool allowTlsResume,
bool sendTrustList)
{
Debug.Assert(creds != null, "creds == null");

Expand All @@ -163,7 +154,7 @@ internal static void CacheCredential(
return;
}

SslCredKey key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation);
SslCredKey key = new SslCredKey(thumbPrint, (int)sslProtocols, isServer, encryptionPolicy, sendTrustList, checkRevocation, allowTlsResume);

SafeFreeCredentials? credentials = GetCachedCredential(key);

Expand Down
Loading

0 comments on commit 1815306

Please sign in to comment.