Skip to content

Commit d64c653

Browse files
authored
avoid some allocations during TLS handshake (#97348)
* avoid some allocations during TLS handshake * SafeFreeCertContext * feedback
1 parent cdd2273 commit d64c653

File tree

7 files changed

+64
-26
lines changed

7 files changed

+64
-26
lines changed

src/libraries/Common/src/Interop/Windows/SspiCli/ISSPIInterface.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal interface ISSPIInterface
2222

2323
int QueryContextChannelBinding(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, out SafeFreeContextBufferChannelBinding refHandle);
2424
int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, Span<byte> buffer, Type? handleType, out SafeHandle? refHandle);
25+
unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, IntPtr* refHandle);
2526
int QuerySecurityContextToken(SafeDeleteContext phContext, out SecurityContextTokenHandle phToken);
2627
int CompleteAuthToken(ref SafeDeleteSslContext? refContext, in InputSecurityBuffer inputBuffer);
2728
int ApplyControlToken(ref SafeDeleteSslContext? refContext, in SecurityBuffer inputBuffer);

src/libraries/Common/src/Interop/Windows/SspiCli/SSPIAuthType.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ public int QueryContextChannelBinding(SafeDeleteContext context, Interop.SspiCli
106106
throw new NotSupportedException();
107107
}
108108

109+
public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.SspiCli.ContextAttribute attribute, IntPtr* refHandle)
110+
{
111+
return SafeFreeContextBuffer.QueryContextAttributes(context, attribute, refHandle);
112+
}
113+
109114
public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.SspiCli.ContextAttribute attribute, Span<byte> buffer, Type? handleType, out SafeHandle? refHandle)
110115
{
111116
refHandle = null;
@@ -115,10 +120,6 @@ public unsafe int QueryContextAttributes(SafeDeleteContext context, Interop.Sspi
115120
{
116121
refHandle = SafeFreeContextBuffer.CreateEmptyHandle();
117122
}
118-
else if (handleType == typeof(SafeFreeCertContext))
119-
{
120-
refHandle = new SafeFreeCertContext();
121-
}
122123
else
123124
{
124125
throw new ArgumentException(SR.Format(SR.SSPIInvalidHandleType, handleType.FullName), nameof(handleType));

src/libraries/Common/src/Interop/Windows/SspiCli/SSPISecureChannelType.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ public unsafe int QueryContextChannelBinding(SafeDeleteContext phContext, Intero
108108
return SafeFreeContextBufferChannelBinding.QueryContextChannelBinding(phContext, attribute, &bindings, refHandle);
109109
}
110110

111+
public unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, IntPtr* refHandle)
112+
{
113+
return SafeFreeContextBuffer.QueryContextAttributes(phContext, attribute, refHandle);
114+
}
115+
111116
public unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute attribute, Span<byte> buffer, Type? handleType, out SafeHandle? refHandle)
112117
{
113118
refHandle = null;

src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -270,29 +270,42 @@ public static bool QueryBlittableContextAttributes<T>(ISSPIInterface secModule,
270270
}
271271
}
272272

273-
private static bool QueryCertContextAttribute(ISSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute attribute, out SafeFreeCertContext? certContext)
273+
private static unsafe bool QueryCertContextAttribute(ISSPIInterface secModule, SafeDeleteContext securityContext, Interop.SspiCli.ContextAttribute attribute, out SafeFreeCertContext? certContext)
274274
{
275-
Span<IntPtr> buffer = stackalloc IntPtr[1];
276-
int errorCode = secModule.QueryContextAttributes(
277-
securityContext,
278-
attribute,
279-
MemoryMarshal.AsBytes(buffer),
280-
typeof(SafeFreeCertContext),
281-
out SafeHandle? sspiHandle);
275+
IntPtr handle = IntPtr.Zero;
276+
certContext = null;
282277

283-
// certificate is not always present (e.g. on server when querying client certificate)
284-
// but we still want to consider such case as a success.
285-
bool success = errorCode == 0 || errorCode == (int)Interop.SECURITY_STATUS.NoCredentials;
278+
try
279+
{
280+
int errorCode = secModule.QueryContextAttributes(
281+
securityContext,
282+
attribute,
283+
&handle);
284+
285+
// certificate is not always present (e.g. on server when querying client certificate)
286+
// but we still want to consider such case as a success.
287+
bool success = errorCode == 0 || errorCode == (int)Interop.SECURITY_STATUS.NoCredentials;
286288

287-
if (!success)
289+
if (errorCode == 0 && handle != IntPtr.Zero)
290+
{
291+
certContext = new SafeFreeCertContext();
292+
certContext.Set(handle);
293+
// Handle was successfully transferred to SafeHandle
294+
handle = IntPtr.Zero;
295+
}
296+
if (!success)
297+
{
298+
if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(null, $"ERROR = {ErrorDescription(errorCode)}");
299+
}
300+
return success;
301+
}
302+
finally
288303
{
289-
sspiHandle?.Dispose();
290-
sspiHandle = null;
291-
if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(null, $"ERROR = {ErrorDescription(errorCode)}");
304+
if (handle != IntPtr.Zero)
305+
{
306+
Interop.Crypt32.CertFreeCertificateContext(handle);
307+
}
292308
}
293-
294-
certContext = sspiHandle as SafeFreeCertContext;
295-
return success;
296309
}
297310

298311
public static bool QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(ISSPIInterface secModule, SafeDeleteContext securityContext, out SafeFreeCertContext? certContext)

src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,23 @@ internal static SafeFreeContextBuffer CreateEmptyHandle()
6565
return new SafeFreeContextBuffer_SECURITY();
6666
}
6767

68+
public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, Interop.SspiCli.ContextAttribute contextAttribute, IntPtr* handle)
69+
{
70+
bool mustRelease = false;
71+
try
72+
{
73+
phContext.DangerousAddRef(ref mustRelease);
74+
return Interop.SspiCli.QueryContextAttributesW(ref phContext._handle, contextAttribute, handle);
75+
}
76+
finally
77+
{
78+
if (mustRelease)
79+
{
80+
phContext.DangerousRelease();
81+
}
82+
}
83+
}
84+
6885
//
6986
// After PInvoke call the method will fix the refHandle.handle with the returned value.
7087
// The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned.
@@ -98,7 +115,7 @@ public static unsafe int QueryContextAttributes(SafeDeleteContext phContext, Int
98115
}
99116
else
100117
{
101-
((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer);
118+
Debug.Assert(false);
102119
}
103120
}
104121

src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,9 @@ internal static bool IsLocalCertificateUsed(SafeFreeCredentials? _credentialsHan
111111
SafeFreeCertContext? localContext = null;
112112
try
113113
{
114-
if (SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_LOCAL_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out localContext) &&
115-
localContext != null)
114+
if (SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_LOCAL_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out localContext))
116115
{
117-
return !localContext.IsInvalid;
116+
return localContext != null ? !localContext.IsInvalid : false;
118117
}
119118
}
120119
finally

src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ public static ProtocolToken AcceptSecurityContext(
119119
}
120120

121121
ProtocolToken token = default;
122+
token.RentBuffer = true;
122123

123124
int errorCode = SSPIWrapper.AcceptSecurityContext(
124125
GlobalSSPI.SSPISecureChannel,
@@ -163,6 +164,7 @@ public static ProtocolToken InitializeSecurityContext(
163164
}
164165

165166
ProtocolToken token = default;
167+
token.RentBuffer = true;
166168
int errorCode = SSPIWrapper.InitializeSecurityContext(
167169
GlobalSSPI.SSPISecureChannel,
168170
ref credentialsHandle,

0 commit comments

Comments
 (0)