private const int FrameOverhead = 64;
private const int ReadBufferSize = 4096 * 4 + FrameOverhead; // We read in 16K chunks + headers.
private const int InitialHandshakeBufferSize = 4096 + FrameOverhead; // try to fit at least 4K ServerCertificate
+ private const int HandshakeTypeOffsetSsl2 = 2; // Offset of HelloType in Sslv2 and Unified frames
+ private const int HandshakeTypeOffsetTls = 5; // Offset of HelloType in Sslv3 and TLS frames
private ArrayBuffer _handshakeBuffer;
private bool _receivedEOF;
#pragma warning disable 0618
_lastFrame.Header.Version = SslProtocols.Ssl2;
#pragma warning restore 0618
+ _lastFrame.Header.Type = TlsContentType.Handshake; // Implied. We only call this during handshake and SSL2 does not have framing layer.
_lastFrame.Header.Length = GetFrameSize(_handshakeBuffer.ActiveReadOnlySpan) - TlsFrameHelper.HeaderSize;
}
else
}
break;
case TlsContentType.Handshake:
- if (!_isRenego && _handshakeBuffer.ActiveReadOnlySpan[TlsFrameHelper.HeaderSize] == (byte)TlsHandshakeType.ClientHello &&
- (_sslAuthenticationOptions!.ServerCertSelectionDelegate != null ||
- _sslAuthenticationOptions!.ServerOptionDelegate != null))
+ byte handshakeType = _handshakeBuffer.ActiveReadOnlySpan[_framing == Framing.SinceSSL3 ? HandshakeTypeOffsetTls : HandshakeTypeOffsetSsl2];
+
+ if (!_isRenego &&
+ (_sslAuthenticationOptions!.ServerCertSelectionDelegate != null || _sslAuthenticationOptions!.ServerOptionDelegate != null) &&
+ (handshakeType == (byte)TlsHandshakeType.ClientHello))
{
TlsFrameHelper.ProcessingOptions options = NetEventSource.Log.IsEnabled() ?
TlsFrameHelper.ProcessingOptions.All :
public static bool TryGetFrameHeader(ReadOnlySpan<byte> frame, ref TlsFrameHeader header)
{
- bool result = frame.Length > 4;
-
- if (frame.Length >= 1)
+ header.Type = (TlsContentType)(frame.Length >= 1 ? frame[0] : 0);
+ if (frame.Length < TlsFrameHelper.HeaderSize)
{
- header.Type = (TlsContentType)frame[0];
-
- if (frame.Length >= 3)
- {
- // SSLv3, TLS or later
- if (frame[1] == 3)
- {
- if (frame.Length > 4)
- {
- header.Length = ((frame[3] << 8) | frame[4]);
- }
+ header.Length = -1;
+ header.Version = SslProtocols.None;
+ return false;
+ }
- header.Version = TlsMinorVersionToProtocol(frame[2]);
- }
- else
- {
- header.Length = -1;
- header.Version = SslProtocols.None;
- }
- }
+ // SSLv3, TLS or later
+ if (frame[1] == ProtocolVersionTlsMajorValue)
+ {
+ header.Length = ((frame[3] << 8) | frame[4]);
+ header.Version = TlsMinorVersionToProtocol(frame[2]);
+ }
+ // Sslv2 or Unified
+ else if (frame[2] == (byte)TlsHandshakeType.ClientHello &&
+ frame[3] == ProtocolVersionTlsMajorValue) // SSL3 or above
+ {
+ header.Length = (frame[0] & 0x80) != 0 ?
+ (((frame[0] & 0x7f) << 8) | frame[1]) + 2 : // two bytes
+ (((frame[0] & 0x3f) << 8) | frame[1]) + 3; // three bytes
+#pragma warning disable CS0618 // Ssl2 and Ssl3 are obsolete
+ header.Version = SslProtocols.Ssl2;
+#pragma warning restore CS0618
+ header.Type = TlsContentType.Handshake;
+ }
+ else
+ {
+ // neither looks like TLS nor Ssl2 Hello
+ header.Length = -1;
+ header.Version = SslProtocols.None;
+ return false;
}
- return result;
+ return true;
}
// Returns frame size e.g. header + content
}
info.HandshakeType = (TlsHandshakeType)frame[HandshakeTypeOffset];
+#pragma warning disable CS0618 // Ssl2 and Ssl3 are obsolete
+ if (info.Header.Version == SslProtocols.Ssl2)
+ {
+ // This is safe. We would not get here if the length is too small.
+ info.SupportedVersions |= TlsMinorVersionToProtocol(frame[4]);
+ // We only recognize Unified ClientHello at the moment.
+ // This is needed to trigger certificate selection callback in SslStream.
+ info.HandshakeType = TlsHandshakeType.ClientHello;
+ // There is no more parsing for old protocols.
+ return true;
+ }
+#pragma warning restore CS0618
// Check if we have full frame.
bool isComplete = frame.Length >= HeaderSize + info.Header.Length;
// Skip compression methods (max size 2^8-1 => size fits in 1 byte)
p = SkipOpaqueType1(p);
- // is invalid structure or no extensions?
+ // no extensions
if (p.IsEmpty)
{
- return false;
+ return true;
}
// client_hello_extension_list (max size 2^16-1 => size fits in 2 bytes)