remove support for Ssl2 (#64322)
authorTomas Weinfurt <tweinfurt@yahoo.com>
Fri, 28 Jan 2022 23:44:55 +0000 (15:44 -0800)
committerGitHub <noreply@github.com>
Fri, 28 Jan 2022 23:44:55 +0000 (15:44 -0800)
* remove support for Ssl2

* update test

* update exeception type

* remove Sslv2 test

src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs
src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs

index 3455083..58156e3 100644 (file)
@@ -21,18 +21,6 @@ namespace System.Net.Security
         private int _nestedAuth;
         private bool _isRenego;
 
-        private enum Framing
-        {
-            Unknown = 0,    // Initial before any frame is processed.
-            BeforeSSL3,     // SSlv2
-            SinceSSL3,      // SSlv3 & TLS
-            Unified,        // Intermediate on first frame until response is processes.
-            Invalid         // Something is wrong.
-        }
-
-        // This is set on the first packet to figure out the framing style.
-        private Framing _framing = Framing.Unknown;
-
         private TlsFrameHelper.TlsFrameInfo _lastFrame;
 
         private object _handshakeLock => _sslAuthenticationOptions!;
@@ -460,27 +448,12 @@ namespace System.Net.Security
                  where TIOAdapter : IReadWriteAdapter
         {
             await FillHandshakeBufferAsync(adapter, SecureChannel.ReadHeaderSize).ConfigureAwait(false);
-            if (_framing == Framing.Unified || _framing == Framing.Unknown)
-            {
-                _framing = DetectFraming(_handshakeBuffer.ActiveReadOnlySpan);
-            }
-
-            if (_framing != Framing.SinceSSL3)
-            {
-#pragma warning disable 0618
-                _lastFrame.Header.Version = SslProtocols.Ssl2;
-#pragma warning restore 0618
-                _lastFrame.Header.Length = GetFrameSize(_handshakeBuffer.ActiveReadOnlySpan) - TlsFrameHelper.HeaderSize;
-            }
-            else
-            {
-                TlsFrameHelper.TryGetFrameHeader(_handshakeBuffer.ActiveReadOnlySpan, ref _lastFrame.Header);
-            }
+            TlsFrameHelper.TryGetFrameHeader(_handshakeBuffer.ActiveReadOnlySpan, ref _lastFrame.Header);
 
             if (_lastFrame.Header.Length < 0)
             {
                 if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, "invalid TLS frame size");
-                throw new IOException(SR.net_frame_read_size);
+                throw new AuthenticationException(SR.net_frame_read_size);
             }
 
             // Header length is content only so we must add header size as well.
@@ -560,29 +533,26 @@ namespace System.Net.Security
             // ActiveSpan will exclude the "discarded" data.
             _handshakeBuffer.Discard(frameSize);
 
-            if (_framing == Framing.SinceSSL3)
+            // Often more TLS messages fit into same packet. Get as many complete frames as we can.
+            while (_handshakeBuffer.ActiveLength > TlsFrameHelper.HeaderSize)
             {
-                // Often more TLS messages fit into same packet. Get as many complete frames as we can.
-                while (_handshakeBuffer.ActiveLength > TlsFrameHelper.HeaderSize)
-                {
-                    TlsFrameHeader nextHeader = default;
-
-                    if (!TlsFrameHelper.TryGetFrameHeader(_handshakeBuffer.ActiveReadOnlySpan, ref nextHeader))
-                    {
-                        break;
-                    }
+                TlsFrameHeader nextHeader = default;
 
-                    frameSize = nextHeader.Length + TlsFrameHelper.HeaderSize;
-                    // Can process more handshake frames in single step, but we should avoid processing too much so as to preserve API boundary between handshake and I/O.
-                    if ((nextHeader.Type != TlsContentType.Handshake && nextHeader.Type != TlsContentType.ChangeCipherSpec) || frameSize > _handshakeBuffer.ActiveLength)
-                    {
-                        // We don't have full frame left or we already have app data which needs to be processed by decrypt.
-                        break;
-                    }
+                if (!TlsFrameHelper.TryGetFrameHeader(_handshakeBuffer.ActiveReadOnlySpan, ref nextHeader))
+                {
+                    break;
+                }
 
-                    chunkSize += frameSize;
-                    _handshakeBuffer.Discard(frameSize);
+                frameSize = nextHeader.Length + TlsFrameHelper.HeaderSize;
+                // Can process more handshake frames in single step, but we should avoid processing too much so as to preserve API boundary between handshake and I/O.
+                if ((nextHeader.Type != TlsContentType.Handshake && nextHeader.Type != TlsContentType.ChangeCipherSpec) || frameSize > _handshakeBuffer.ActiveLength)
+                {
+                    // We don't have full frame left or we already have app data which needs to be processed by decrypt.
+                    break;
                 }
+
+                chunkSize += frameSize;
+                _handshakeBuffer.Discard(frameSize);
             }
 
             return _context!.NextMessage(availableData.Slice(0, chunkSize));
@@ -1199,204 +1169,15 @@ namespace System.Net.Security
             }
         }
 
-        // We need at least 5 bytes to determine what we have.
-        private Framing DetectFraming(ReadOnlySpan<byte> bytes)
-        {
-            /* PCTv1.0 Hello starts with
-             * RECORD_LENGTH_MSB  (ignore)
-             * RECORD_LENGTH_LSB  (ignore)
-             * PCT1_CLIENT_HELLO  (must be equal)
-             * PCT1_CLIENT_VERSION_MSB (if version greater than PCTv1)
-             * PCT1_CLIENT_VERSION_LSB (if version greater than PCTv1)
-             *
-             * ... PCT hello ...
-             */
-
-            /* Microsoft Unihello starts with
-             * RECORD_LENGTH_MSB  (ignore)
-             * RECORD_LENGTH_LSB  (ignore)
-             * SSL2_CLIENT_HELLO  (must be equal)
-             * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3)
-             * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3)
-             *
-             * ... SSLv2 Compatible Hello ...
-             */
-
-            /* SSLv2 CLIENT_HELLO starts with
-             * RECORD_LENGTH_MSB  (ignore)
-             * RECORD_LENGTH_LSB  (ignore)
-             * SSL2_CLIENT_HELLO  (must be equal)
-             * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3)
-             * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3)
-             *
-             * ... SSLv2 CLIENT_HELLO ...
-             */
-
-            /* SSLv2 SERVER_HELLO starts with
-             * RECORD_LENGTH_MSB  (ignore)
-             * RECORD_LENGTH_LSB  (ignore)
-             * SSL2_SERVER_HELLO  (must be equal)
-             * SSL2_SESSION_ID_HIT (ignore)
-             * SSL2_CERTIFICATE_TYPE (ignore)
-             * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv2) ( or v3)
-             * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv2) ( or v3)
-             *
-             * ... SSLv2 SERVER_HELLO ...
-             */
-
-            /* SSLv3 Type 2 Hello starts with
-              * RECORD_LENGTH_MSB  (ignore)
-              * RECORD_LENGTH_LSB  (ignore)
-              * SSL2_CLIENT_HELLO  (must be equal)
-              * SSL2_CLIENT_VERSION_MSB (if version greater than SSLv3)
-              * SSL2_CLIENT_VERSION_LSB (if version greater than SSLv3)
-              *
-              * ... SSLv2 Compatible Hello ...
-              */
-
-            /* SSLv3 Type 3 Hello starts with
-             * 22 (HANDSHAKE MESSAGE)
-             * VERSION MSB
-             * VERSION LSB
-             * RECORD_LENGTH_MSB  (ignore)
-             * RECORD_LENGTH_LSB  (ignore)
-             * HS TYPE (CLIENT_HELLO)
-             * 3 bytes HS record length
-             * HS Version
-             * HS Version
-             */
-
-            /* SSLv2 message codes
-             * SSL_MT_ERROR                0
-             * SSL_MT_CLIENT_HELLO         1
-             * SSL_MT_CLIENT_MASTER_KEY    2
-             * SSL_MT_CLIENT_FINISHED      3
-             * SSL_MT_SERVER_HELLO         4
-             * SSL_MT_SERVER_VERIFY        5
-             * SSL_MT_SERVER_FINISHED      6
-             * SSL_MT_REQUEST_CERTIFICATE  7
-             * SSL_MT_CLIENT_CERTIFICATE   8
-             */
-
-            int version = -1;
-
-            Debug.Assert(bytes.Length != 0, "Header buffer is not allocated.");
-
-            // If the first byte is SSL3 HandShake, then check if we have a SSLv3 Type3 client hello.
-            if (bytes[0] == (byte)TlsContentType.Handshake || bytes[0] == (byte)TlsContentType.AppData
-                || bytes[0] == (byte)TlsContentType.Alert)
-            {
-                if (bytes.Length < 3)
-                {
-                    return Framing.Invalid;
-                }
-
-                version = (bytes[1] << 8) | bytes[2];
-                if (version < 0x300 || version >= 0x500)
-                {
-                    return Framing.Invalid;
-                }
-
-                //
-                // This is an SSL3 Framing
-                //
-                return Framing.SinceSSL3;
-            }
-
-            if (bytes.Length < 3)
-            {
-                return Framing.Invalid;
-            }
-
-            if (bytes[2] > 8)
-            {
-                return Framing.Invalid;
-            }
-
-            if (bytes[2] == 0x1)  // SSL_MT_CLIENT_HELLO
-            {
-                if (bytes.Length >= 5)
-                {
-                    version = (bytes[3] << 8) | bytes[4];
-                }
-            }
-            else if (bytes[2] == 0x4) // SSL_MT_SERVER_HELLO
-            {
-                if (bytes.Length >= 7)
-                {
-                    version = (bytes[5] << 8) | bytes[6];
-                }
-            }
-
-            if (version != -1)
-            {
-                // If this is the first packet, the client may start with an SSL2 packet
-                // but stating that the version is 3.x, so check the full range.
-                // For the subsequent packets we assume that an SSL2 packet should have a 2.x version.
-                if (_framing == Framing.Unknown)
-                {
-                    if (version != 0x0002 && (version < 0x200 || version >= 0x500))
-                    {
-                        return Framing.Invalid;
-                    }
-                }
-                else
-                {
-                    if (version != 0x0002)
-                    {
-                        return Framing.Invalid;
-                    }
-                }
-            }
-
-            // When server has replied the framing is already fixed depending on the prior client packet
-            if (!_context!.IsServer || _framing == Framing.Unified)
-            {
-                return Framing.BeforeSSL3;
-            }
-
-            return Framing.Unified; // Will use Ssl2 just for this frame.
-        }
-
-        // Returns TLS Frame size.
+        // Returns TLS Frame size including header size.
         private int GetFrameSize(ReadOnlySpan<byte> buffer)
         {
-            int payloadSize;
-            switch (_framing)
+            if (buffer.Length < SecureChannel.ReadHeaderSize)
             {
-                case Framing.Unified:
-                case Framing.BeforeSSL3:
-                    if (buffer.Length < 2)
-                    {
-                        throw new IOException(SR.net_ssl_io_frame);
-                    }
-                    // Note: Cannot detect version mismatch for <= SSL2
-
-                    if ((buffer[0] & 0x80) != 0)
-                    {
-                        // Two bytes
-                        payloadSize = (((buffer[0] & 0x7f) << 8) | buffer[1]) + 2;
-                    }
-                    else
-                    {
-                        // Three bytes
-                        payloadSize = (((buffer[0] & 0x3f) << 8) | buffer[1]) + 3;
-                    }
-
-                    break;
-                case Framing.SinceSSL3:
-                    if (buffer.Length < 5)
-                    {
-                        throw new IOException(SR.net_ssl_io_frame);
-                    }
-
-                    payloadSize = ((buffer[3] << 8) | buffer[4]) + 5;
-                    break;
-                default:
-                    throw new IOException(SR.net_frame_read_size);
+                throw new IOException(SR.net_ssl_io_frame);
             }
 
-            return payloadSize;
+            return ((buffer[3] << 8) | buffer[4]) + SecureChannel.ReadHeaderSize;
         }
     }
 }
index 50dd158..a0e76e4 100644 (file)
@@ -52,20 +52,6 @@ namespace System.Net.Security.Tests
             await ClientAsyncSslHelper(protocol, protocol);
         }
 
-        [Fact]
-        [PlatformSpecific(TestPlatforms.Windows)]
-        public async Task ClientAsyncAuthenticate_Ssl2WithSelf_Success()
-        {
-            // Test Ssl2 against itself. This is a standalone test as even on versions where Windows supports Ssl2,
-            // it appears to have rules around not using it when other protocols are mentioned.
-            if (PlatformDetection.SupportsSsl2)
-            {
-#pragma warning disable 0618
-                await ClientAsyncSslHelper(SslProtocols.Ssl2, SslProtocols.Ssl2);
-#pragma warning restore 0618
-            }
-        }
-
         [Theory]
         [MemberData(nameof(ProtocolMismatchData))]
         public async Task ClientAsyncAuthenticate_MismatchProtocols_Fails(
index 6edcace..1e01be3 100644 (file)
@@ -317,14 +317,7 @@ namespace System.Net.Security.Tests
                     await t2.WaitAsync(TestConfiguration.PassingTestTimeout);
                 }
 
-                if (close)
-                {
-                    await Assert.ThrowsAsync<IOException>(() => t1);
-                }
-                else
-                {
-                    await Assert.ThrowsAsync<AuthenticationException>(() => t1);
-                }
+                await Assert.ThrowsAsync<AuthenticationException>(() => t1);
             }
         }