4242 */
4343public abstract class AbstractSniHandler <T > extends ByteToMessageDecoder implements ChannelOutboundHandler {
4444
45- // Maximal number of ssl records to inspect before fallback to the default SslContext.
46- private static final int MAX_SSL_RECORDS = 4 ;
47-
4845 private static final InternalLogger logger =
4946 InternalLoggerFactory .getInstance (AbstractSniHandler .class );
5047
@@ -55,83 +52,75 @@ public abstract class AbstractSniHandler<T> extends ByteToMessageDecoder impleme
5552 @ Override
5653 protected void decode (ChannelHandlerContext ctx , ByteBuf in , List <Object > out ) throws Exception {
5754 if (!suppressRead && !handshakeFailed ) {
58- final int writerIndex = in .writerIndex ();
5955 try {
60- loop :
61- for (int i = 0 ; i < MAX_SSL_RECORDS ; i ++) {
62- final int readerIndex = in .readerIndex ();
63- final int readableBytes = writerIndex - readerIndex ;
64- if (readableBytes < SslUtils .SSL_RECORD_HEADER_LENGTH ) {
65- // Not enough data to determine the record type and length.
66- return ;
67- }
56+ final int readerIndex = in .readerIndex ();
57+ final int readableBytes = in .readableBytes ();
58+ if (readableBytes < SslUtils .SSL_RECORD_HEADER_LENGTH ) {
59+ // Not enough data to determine the record type and length.
60+ return ;
61+ }
6862
69- final int command = in .getUnsignedByte (readerIndex );
70-
71- // tls, but not handshake command
72- switch (command ) {
73- case SslUtils .SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC :
74- case SslUtils .SSL_CONTENT_TYPE_ALERT :
75- final int len = SslUtils .getEncryptedPacketLength (in , readerIndex );
76-
77- // Not an SSL/TLS packet
78- if (len == SslUtils .NOT_ENCRYPTED ) {
79- handshakeFailed = true ;
80- NotSslRecordException e = new NotSslRecordException (
81- "not an SSL/TLS record: " + ByteBufUtil .hexDump (in ));
82- in .skipBytes (in .readableBytes ());
83- ctx .fireUserEventTriggered (new SniCompletionEvent (e ));
84- SslUtils .handleHandshakeFailure (ctx , e , true );
85- throw e ;
86- }
87- if (len == SslUtils .NOT_ENOUGH_DATA ||
88- writerIndex - readerIndex - SslUtils .SSL_RECORD_HEADER_LENGTH < len ) {
89- // Not enough data
63+ final int command = in .getUnsignedByte (readerIndex );
64+ switch (command ) {
65+ case SslUtils .SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC :
66+ // fall-through
67+ case SslUtils .SSL_CONTENT_TYPE_ALERT :
68+ final int len = SslUtils .getEncryptedPacketLength (in , readerIndex );
69+
70+ // Not an SSL/TLS packet
71+ if (len == SslUtils .NOT_ENCRYPTED ) {
72+ handshakeFailed = true ;
73+ NotSslRecordException e = new NotSslRecordException (
74+ "not an SSL/TLS record: " + ByteBufUtil .hexDump (in ));
75+ in .skipBytes (in .readableBytes ());
76+ ctx .fireUserEventTriggered (new SniCompletionEvent (e ));
77+ SslUtils .handleHandshakeFailure (ctx , e , true );
78+ throw e ;
79+ }
80+ if (len == SslUtils .NOT_ENOUGH_DATA ) {
81+ // Not enough data
82+ return ;
83+ }
84+ // SNI can't be present in an ALERT or CHANGE_CIPHER_SPEC record, so we'll fall back and assume
85+ // no SNI is present. Let's let the actual TLS implementation sort this out.
86+ break ;
87+
88+ case SslUtils .SSL_CONTENT_TYPE_HANDSHAKE :
89+ final int majorVersion = in .getUnsignedByte (readerIndex + 1 );
90+ // SSLv3 or TLS
91+ if (majorVersion == 3 ) {
92+ final int packetLength = in .getUnsignedShort (readerIndex + 3 ) +
93+ SslUtils .SSL_RECORD_HEADER_LENGTH ;
94+
95+ if (readableBytes < packetLength ) {
96+ // client hello incomplete; try again to decode once more data is ready.
9097 return ;
9198 }
92- // increase readerIndex and try again.
93- in .skipBytes (len );
94- continue ;
95- case SslUtils .SSL_CONTENT_TYPE_HANDSHAKE :
96- final int majorVersion = in .getUnsignedByte (readerIndex + 1 );
97-
98- // SSLv3 or TLS
99- if (majorVersion == 3 ) {
100- final int packetLength = in .getUnsignedShort (readerIndex + 3 ) +
101- SslUtils .SSL_RECORD_HEADER_LENGTH ;
102-
103- if (readableBytes < packetLength ) {
104- // client hello incomplete; try again to decode once more data is ready.
105- return ;
106- }
107-
108- // See https://tools.ietf.org/html/rfc5246#section-7.4.1.2
109- //
110- // Decode the ssl client hello packet.
111- // We have to skip bytes until SessionID (which sum to 43 bytes).
112- //
113- // struct {
114- // ProtocolVersion client_version;
115- // Random random;
116- // SessionID session_id;
117- // CipherSuite cipher_suites<2..2^16-2>;
118- // CompressionMethod compression_methods<1..2^8-1>;
119- // select (extensions_present) {
120- // case false:
121- // struct {};
122- // case true:
123- // Extension extensions<0..2^16-1>;
124- // };
125- // } ClientHello;
126- //
127-
128- final int endOffset = readerIndex + packetLength ;
129- int offset = readerIndex + 43 ;
130-
131- if (endOffset - offset < 6 ) {
132- break loop ;
133- }
13499
100+ // See https://tools.ietf.org/html/rfc5246#section-7.4.1.2
101+ //
102+ // Decode the ssl client hello packet.
103+ // We have to skip bytes until SessionID (which sum to 43 bytes).
104+ //
105+ // struct {
106+ // ProtocolVersion client_version;
107+ // Random random;
108+ // SessionID session_id;
109+ // CipherSuite cipher_suites<2..2^16-2>;
110+ // CompressionMethod compression_methods<1..2^8-1>;
111+ // select (extensions_present) {
112+ // case false:
113+ // struct {};
114+ // case true:
115+ // Extension extensions<0..2^16-1>;
116+ // };
117+ // } ClientHello;
118+ //
119+
120+ final int endOffset = readerIndex + packetLength ;
121+ int offset = readerIndex + 43 ;
122+
123+ if (endOffset - offset >= 6 ) {
135124 final int sessionIdLength = in .getUnsignedByte (offset );
136125 offset += sessionIdLength + 1 ;
137126
@@ -145,68 +134,61 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) t
145134 offset += 2 ;
146135 final int extensionsLimit = offset + extensionsLength ;
147136
148- if (extensionsLimit > endOffset ) {
149- // Extensions should never exceed the record boundary.
150- break loop ;
151- }
152-
153- for (;;) {
154- if (extensionsLimit - offset < 4 ) {
155- break loop ;
156- }
157-
158- final int extensionType = in .getUnsignedShort (offset );
159- offset += 2 ;
160-
161- final int extensionLength = in .getUnsignedShort (offset );
162- offset += 2 ;
163-
164- if (extensionsLimit - offset < extensionLength ) {
165- break loop ;
166- }
137+ // Extensions should never exceed the record boundary.
138+ if (extensionsLimit <= endOffset ) {
139+ while (extensionsLimit - offset >= 4 ) {
140+ final int extensionType = in .getUnsignedShort (offset );
141+ offset += 2 ;
167142
168- // SNI
169- // See https://tools.ietf.org/html/rfc6066#page-6
170- if (extensionType == 0 ) {
143+ final int extensionLength = in .getUnsignedShort (offset );
171144 offset += 2 ;
172- if (extensionsLimit - offset < 3 ) {
173- break loop ;
174- }
175145
176- final int serverNameType = in .getUnsignedByte (offset );
177- offset ++;
146+ if (extensionsLimit - offset < extensionLength ) {
147+ break ;
148+ }
178149
179- if (serverNameType == 0 ) {
180- final int serverNameLength = in .getUnsignedShort (offset );
150+ // SNI
151+ // See https://tools.ietf.org/html/rfc6066#page-6
152+ if (extensionType == 0 ) {
181153 offset += 2 ;
182-
183- if (extensionsLimit - offset < serverNameLength ) {
184- break loop ;
154+ if (extensionsLimit - offset < 3 ) {
155+ break ;
185156 }
186157
187- final String hostname = in .toString (offset , serverNameLength ,
188- CharsetUtil .US_ASCII );
189-
190- try {
191- select (ctx , hostname .toLowerCase (Locale .US ));
192- } catch (Throwable t ) {
193- PlatformDependent .throwException (t );
158+ final int serverNameType = in .getUnsignedByte (offset );
159+ offset ++;
160+
161+ if (serverNameType == 0 ) {
162+ final int serverNameLength = in .getUnsignedShort (offset );
163+ offset += 2 ;
164+
165+ if (extensionsLimit - offset < serverNameLength ) {
166+ break ;
167+ }
168+
169+ final String hostname =
170+ in .toString (offset , serverNameLength , CharsetUtil .US_ASCII );
171+ try {
172+ select (ctx , hostname .toLowerCase (Locale .US ));
173+ } catch (Throwable t ) {
174+ PlatformDependent .throwException (t );
175+ }
176+ return ;
177+ } else {
178+ // invalid enum value
179+ break ;
194180 }
195- return ;
196- } else {
197- // invalid enum value
198- break loop ;
199181 }
200- }
201182
202- offset += extensionLength ;
183+ offset += extensionLength ;
184+ }
203185 }
204186 }
205- // Fall-through
206- default :
207- //not tls, ssl or application data, do not try sni
208- break loop ;
209- }
187+ }
188+ break ;
189+ default :
190+ //not tls, ssl or application data, do not try sni
191+ break ;
210192 }
211193 } catch (NotSslRecordException e ) {
212194 // Just rethrow as in this case we also closed the channel and this is consistent with SslHandler.
0 commit comments