Skip to content

Commit 6253efe

Browse files
authored
Use full TLS record size for application data on Windows (#95595)
* Replace pointers by spans and refs in SslStreamPal.Windows * Correctly calculate the MaxDataSize * Remove unwanted change * Fixes after rebase * Remove couple of unsafe usages
1 parent e5c0cbc commit 6253efe

File tree

2 files changed

+49
-58
lines changed

2 files changed

+49
-58
lines changed

src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,7 @@ internal void ProcessHandshakeSuccess()
928928

929929
_headerSize = streamSizes.Header;
930930
_trailerSize = streamSizes.Trailer;
931-
_maxDataSize = checked(streamSizes.MaximumMessage - (_headerSize + _trailerSize));
931+
_maxDataSize = streamSizes.MaximumMessage;
932932
Debug.Assert(_maxDataSize > 0, "_maxDataSize > 0");
933933

934934
SslStreamPal.QueryContextConnectionInfo(_securityContext!, ref _connectionInfo);
@@ -942,18 +942,6 @@ internal void ProcessHandshakeSuccess()
942942
#endif
943943
}
944944

945-
/*++
946-
Encrypt - Encrypts our bytes before we send them over the wire
947-
948-
PERF: make more efficient, this does an extra copy when the offset
949-
is non-zero.
950-
951-
Input:
952-
buffer - bytes for sending
953-
offset -
954-
size -
955-
output - Encrypted bytes
956-
--*/
957945
internal ProtocolToken Encrypt(ReadOnlyMemory<byte> buffer)
958946
{
959947
if (NetEventSource.Log.IsEnabled()) NetEventSource.DumpBuffer(this, buffer.Span);
@@ -1337,7 +1325,7 @@ internal void EnsureAvailableSpace(int size)
13371325

13381326
var oldPayload = Payload;
13391327

1340-
Payload = RentBuffer? ArrayPool<byte>.Shared.Rent(Size + size) : new byte[Size + size];
1328+
Payload = RentBuffer ? ArrayPool<byte>.Shared.Rent(Size + size) : new byte[Size + size];
13411329
if (oldPayload != null)
13421330
{
13431331
oldPayload.AsSpan<byte>().CopyTo(Payload);

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

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.ComponentModel;
66
using System.Diagnostics;
7+
using System.Runtime.CompilerServices;
78
using System.Runtime.InteropServices;
89
using System.Security.Authentication;
910
using System.Security.Authentication.ExtendedProtection;
@@ -49,7 +50,8 @@ public static Exception GetException(SecurityStatusPal status)
4950

5051
private static byte[] InitSessionTokenBuffer()
5152
{
52-
var schannelSessionToken = new Interop.SChannel.SCHANNEL_SESSION_TOKEN() {
53+
var schannelSessionToken = new Interop.SChannel.SCHANNEL_SESSION_TOKEN()
54+
{
5355
dwTokenType = Interop.SChannel.SCHANNEL_SESSION,
5456
dwFlags = Interop.SChannel.SSL_SESSION_DISABLE_RECONNECTS,
5557
};
@@ -61,7 +63,7 @@ public static void VerifyPackageInfo()
6163
SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPISecureChannel, SecurityPackage, true);
6264
}
6365

64-
private static unsafe void SetAlpn(ref InputSecurityBuffers inputBuffers, List<SslApplicationProtocol> alpn, Span<byte> localBuffer)
66+
private static void SetAlpn(ref InputSecurityBuffers inputBuffers, List<SslApplicationProtocol> alpn, Span<byte> localBuffer)
6567
{
6668
if (alpn.Count == 1 && alpn[0] == SslApplicationProtocol.Http11)
6769
{
@@ -82,7 +84,7 @@ private static unsafe void SetAlpn(ref InputSecurityBuffers inputBuffers, List<S
8284
else
8385
{
8486
int protocolLength = Interop.Sec_Application_Protocols.GetProtocolLength(alpn);
85-
int bufferLength = sizeof(Interop.Sec_Application_Protocols) + protocolLength;
87+
int bufferLength = Unsafe.SizeOf<Interop.Sec_Application_Protocols>() + protocolLength;
8688

8789
Span<byte> alpnBuffer = bufferLength <= localBuffer.Length ? localBuffer : new byte[bufferLength];
8890
Interop.Sec_Application_Protocols.SetProtocols(alpnBuffer, alpn, protocolLength);
@@ -99,7 +101,7 @@ public static SecurityStatusPal SelectApplicationProtocol(
99101
throw new PlatformNotSupportedException(nameof(SelectApplicationProtocol));
100102
}
101103

102-
public static unsafe ProtocolToken AcceptSecurityContext(
104+
public static ProtocolToken AcceptSecurityContext(
103105
ref SafeFreeCredentials? credentialsHandle,
104106
ref SafeDeleteSslContext? context,
105107
ReadOnlySpan<byte> inputBuffer,
@@ -141,7 +143,7 @@ public static bool TryUpdateClintCertificate(
141143
return false;
142144
}
143145

144-
public static unsafe ProtocolToken InitializeSecurityContext(
146+
public static ProtocolToken InitializeSecurityContext(
145147
ref SafeFreeCredentials? credentialsHandle,
146148
ref SafeDeleteSslContext? context,
147149
string? targetName,
@@ -445,32 +447,32 @@ public static unsafe ProtocolToken EncryptMessage(SafeDeleteSslContext securityC
445447
input.Span.CopyTo(token.AvailableSpan.Slice(headerSize, input.Length));
446448

447449
const int NumSecBuffers = 4; // header + data + trailer + empty
448-
Interop.SspiCli.SecBuffer* unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers];
450+
Span<Interop.SspiCli.SecBuffer> unmanagedBuffers = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers];
449451
Interop.SspiCli.SecBufferDesc sdcInOut = new Interop.SspiCli.SecBufferDesc(NumSecBuffers)
450452
{
451-
pBuffers = unmanagedBuffer
453+
pBuffers = Unsafe.AsPointer(ref MemoryMarshal.GetReference(unmanagedBuffers))
452454
};
453455
fixed (byte* outputPtr = token.Payload)
454456
{
455-
Interop.SspiCli.SecBuffer* headerSecBuffer = &unmanagedBuffer[0];
456-
headerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_HEADER;
457-
headerSecBuffer->pvBuffer = (IntPtr)outputPtr;
458-
headerSecBuffer->cbBuffer = headerSize;
457+
ref Interop.SspiCli.SecBuffer headerSecBuffer = ref unmanagedBuffers[0];
458+
headerSecBuffer.BufferType = SecurityBufferType.SECBUFFER_STREAM_HEADER;
459+
headerSecBuffer.pvBuffer = (IntPtr)outputPtr;
460+
headerSecBuffer.cbBuffer = headerSize;
459461

460-
Interop.SspiCli.SecBuffer* dataSecBuffer = &unmanagedBuffer[1];
461-
dataSecBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA;
462-
dataSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize);
463-
dataSecBuffer->cbBuffer = input.Length;
462+
ref Interop.SspiCli.SecBuffer dataSecBuffer = ref unmanagedBuffers[1];
463+
dataSecBuffer.BufferType = SecurityBufferType.SECBUFFER_DATA;
464+
dataSecBuffer.pvBuffer = (IntPtr)(outputPtr + headerSize);
465+
dataSecBuffer.cbBuffer = input.Length;
464466

465-
Interop.SspiCli.SecBuffer* trailerSecBuffer = &unmanagedBuffer[2];
466-
trailerSecBuffer->BufferType = SecurityBufferType.SECBUFFER_STREAM_TRAILER;
467-
trailerSecBuffer->pvBuffer = (IntPtr)(outputPtr + headerSize + input.Length);
468-
trailerSecBuffer->cbBuffer = trailerSize;
467+
ref Interop.SspiCli.SecBuffer trailerSecBuffer = ref unmanagedBuffers[2];
468+
trailerSecBuffer.BufferType = SecurityBufferType.SECBUFFER_STREAM_TRAILER;
469+
trailerSecBuffer.pvBuffer = (IntPtr)(outputPtr + headerSize + input.Length);
470+
trailerSecBuffer.cbBuffer = trailerSize;
469471

470-
Interop.SspiCli.SecBuffer* emptySecBuffer = &unmanagedBuffer[3];
471-
emptySecBuffer->BufferType = SecurityBufferType.SECBUFFER_EMPTY;
472-
emptySecBuffer->cbBuffer = 0;
473-
emptySecBuffer->pvBuffer = IntPtr.Zero;
472+
ref Interop.SspiCli.SecBuffer emptySecBuffer = ref unmanagedBuffers[3];
473+
emptySecBuffer.BufferType = SecurityBufferType.SECBUFFER_EMPTY;
474+
emptySecBuffer.cbBuffer = 0;
475+
emptySecBuffer.pvBuffer = IntPtr.Zero;
474476

475477
int errorCode = GlobalSSPI.SSPISecureChannel.EncryptMessage(securityContext, ref sdcInOut, 0);
476478

@@ -483,10 +485,10 @@ public static unsafe ProtocolToken EncryptMessage(SafeDeleteSslContext securityC
483485
return token;
484486
}
485487

486-
Debug.Assert(headerSecBuffer->cbBuffer >= 0 && dataSecBuffer->cbBuffer >= 0 && trailerSecBuffer->cbBuffer >= 0);
487-
Debug.Assert(checked(headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer) <= token.Payload!.Length);
488+
Debug.Assert(headerSecBuffer.cbBuffer >= 0 && dataSecBuffer.cbBuffer >= 0 && trailerSecBuffer.cbBuffer >= 0);
489+
Debug.Assert(checked(headerSecBuffer.cbBuffer + dataSecBuffer.cbBuffer + trailerSecBuffer.cbBuffer) <= token.Payload!.Length);
488490

489-
token.Size = checked(headerSecBuffer->cbBuffer + dataSecBuffer->cbBuffer + trailerSecBuffer->cbBuffer);
491+
token.Size = checked(headerSecBuffer.cbBuffer + dataSecBuffer.cbBuffer + trailerSecBuffer.cbBuffer);
490492
token.Status = new SecurityStatusPal(SecurityStatusPalErrorCode.OK);
491493
}
492494

@@ -496,25 +498,26 @@ public static unsafe ProtocolToken EncryptMessage(SafeDeleteSslContext securityC
496498
public static unsafe SecurityStatusPal DecryptMessage(SafeDeleteSslContext? securityContext, Span<byte> buffer, out int offset, out int count)
497499
{
498500
const int NumSecBuffers = 4; // data + empty + empty + empty
499-
fixed (byte* bufferPtr = buffer)
501+
502+
Span<Interop.SspiCli.SecBuffer> unmanagedBuffers = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers];
503+
for (int i = 1; i < NumSecBuffers; i++)
500504
{
501-
Interop.SspiCli.SecBuffer* unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[NumSecBuffers];
502-
Interop.SspiCli.SecBuffer* dataBuffer = &unmanagedBuffer[0];
503-
dataBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA;
504-
dataBuffer->pvBuffer = (IntPtr)bufferPtr;
505-
dataBuffer->cbBuffer = buffer.Length;
505+
ref Interop.SspiCli.SecBuffer emptyBuffer = ref unmanagedBuffers[i];
506+
emptyBuffer.BufferType = SecurityBufferType.SECBUFFER_EMPTY;
507+
emptyBuffer.pvBuffer = IntPtr.Zero;
508+
emptyBuffer.cbBuffer = 0;
509+
}
506510

507-
for (int i = 1; i < NumSecBuffers; i++)
508-
{
509-
Interop.SspiCli.SecBuffer* emptyBuffer = &unmanagedBuffer[i];
510-
emptyBuffer->BufferType = SecurityBufferType.SECBUFFER_EMPTY;
511-
emptyBuffer->pvBuffer = IntPtr.Zero;
512-
emptyBuffer->cbBuffer = 0;
513-
}
511+
fixed (byte* bufferPtr = buffer)
512+
{
513+
ref Interop.SspiCli.SecBuffer dataBuffer = ref unmanagedBuffers[0];
514+
dataBuffer.BufferType = SecurityBufferType.SECBUFFER_DATA;
515+
dataBuffer.pvBuffer = (IntPtr)bufferPtr;
516+
dataBuffer.cbBuffer = buffer.Length;
514517

515518
Interop.SspiCli.SecBufferDesc sdcInOut = new Interop.SspiCli.SecBufferDesc(NumSecBuffers)
516519
{
517-
pBuffers = unmanagedBuffer
520+
pBuffers = Unsafe.AsPointer(ref MemoryMarshal.GetReference(unmanagedBuffers))
518521
};
519522
Interop.SECURITY_STATUS errorCode = (Interop.SECURITY_STATUS)GlobalSSPI.SSPISecureChannel.DecryptMessage(securityContext!, ref sdcInOut, out _);
520523

@@ -525,12 +528,12 @@ public static unsafe SecurityStatusPal DecryptMessage(SafeDeleteSslContext? secu
525528
for (int i = 0; i < NumSecBuffers; i++)
526529
{
527530
// Successfully decoded data and placed it at the following position in the buffer,
528-
if ((errorCode == Interop.SECURITY_STATUS.OK && unmanagedBuffer[i].BufferType == SecurityBufferType.SECBUFFER_DATA)
531+
if ((errorCode == Interop.SECURITY_STATUS.OK && unmanagedBuffers[i].BufferType == SecurityBufferType.SECBUFFER_DATA)
529532
// or we failed to decode the data, here is the encoded data.
530-
|| (errorCode != Interop.SECURITY_STATUS.OK && unmanagedBuffer[i].BufferType == SecurityBufferType.SECBUFFER_EXTRA))
533+
|| (errorCode != Interop.SECURITY_STATUS.OK && unmanagedBuffers[i].BufferType == SecurityBufferType.SECBUFFER_EXTRA))
531534
{
532-
offset = (int)((byte*)unmanagedBuffer[i].pvBuffer - bufferPtr);
533-
count = unmanagedBuffer[i].cbBuffer;
535+
offset = (int)((byte*)unmanagedBuffers[i].pvBuffer - bufferPtr);
536+
count = unmanagedBuffers[i].cbBuffer;
534537

535538
// output is ignored on Windows. We always decrypt in place and we set outputOffset to indicate where the data start.
536539
Debug.Assert(offset >= 0 && count >= 0, $"Expected offset and count greater than 0, got {offset} and {count}");

0 commit comments

Comments
 (0)