1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufUtil;
20 import io.netty.channel.ChannelHandlerContext;
21 import io.netty.channel.ChannelOutboundHandler;
22 import io.netty.channel.ChannelPromise;
23 import io.netty.handler.codec.ByteToMessageDecoder;
24 import io.netty.handler.codec.DecoderException;
25 import io.netty.handler.codec.TooLongFrameException;
26 import io.netty.util.concurrent.Future;
27 import io.netty.util.concurrent.FutureListener;
28 import io.netty.util.internal.ObjectUtil;
29 import io.netty.util.internal.PlatformDependent;
30 import io.netty.util.internal.logging.InternalLogger;
31 import io.netty.util.internal.logging.InternalLoggerFactory;
32
33 import java.net.SocketAddress;
34 import java.util.List;
35
36
37
38
39 public abstract class SslClientHelloHandler<T> extends ByteToMessageDecoder implements ChannelOutboundHandler {
40
41
42
43
44
45 public static final int MAX_CLIENT_HELLO_LENGTH = 0xFFFFFF;
46
47
48
49 static final int DEFAULT_MAX_CLIENT_HELLO_LENGTH = 64 * 1024;
50
51 private static final InternalLogger logger =
52 InternalLoggerFactory.getInstance(SslClientHelloHandler.class);
53
54 private final int maxClientHelloLength;
55 private boolean handshakeFailed;
56 private boolean suppressRead;
57 private boolean readPending;
58 private ByteBuf handshakeBuffer;
59 private int aggregatedBytes;
60 private int handshakeLength = -1;
61
62 public SslClientHelloHandler() {
63 this(DEFAULT_MAX_CLIENT_HELLO_LENGTH);
64 }
65
66 protected SslClientHelloHandler(int maxClientHelloLength) {
67
68
69 this.maxClientHelloLength =
70 ObjectUtil.checkInRange(maxClientHelloLength, 0, MAX_CLIENT_HELLO_LENGTH, "maxClientHelloLength");
71 }
72
73 @Override
74 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
75 if (!suppressRead && !handshakeFailed) {
76 try {
77 int readerIndex = in.readerIndex() + aggregatedBytes;
78 int readableBytes = in.readableBytes() - aggregatedBytes;
79
80
81 while (readableBytes >= SslUtils.SSL_RECORD_HEADER_LENGTH) {
82 final int contentType = in.getUnsignedByte(readerIndex);
83 switch (contentType) {
84 case SslUtils.SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
85
86 case SslUtils.SSL_CONTENT_TYPE_ALERT:
87 final int len = SslUtils.getEncryptedPacketLength(in, readerIndex, true);
88
89
90 if (len == SslUtils.NOT_ENCRYPTED) {
91 handshakeFailed = true;
92 NotSslRecordException e = new NotSslRecordException(
93 "not an SSL/TLS record: " + ByteBufUtil.hexDump(in));
94 in.skipBytes(in.readableBytes());
95 ctx.fireUserEventTriggered(new SniCompletionEvent(e));
96 SslUtils.handleHandshakeFailure(ctx, e, true);
97 throw e;
98 }
99 if (len == SslUtils.NOT_ENOUGH_DATA) {
100
101 return;
102 }
103
104 select(ctx, null);
105 return;
106 case SslUtils.SSL_CONTENT_TYPE_HANDSHAKE:
107 final int majorVersion = in.getUnsignedByte(readerIndex + 1);
108
109 if (majorVersion == 3) {
110 int packetLength = in.getUnsignedShort(readerIndex + 3) +
111 SslUtils.SSL_RECORD_HEADER_LENGTH;
112
113 if (readableBytes < packetLength) {
114
115 return;
116 } else if (packetLength == SslUtils.SSL_RECORD_HEADER_LENGTH) {
117 select(ctx, null);
118 return;
119 }
120
121 final int endOffset = readerIndex + packetLength;
122
123
124 if (handshakeLength == -1) {
125 if (handshakeBuffer == null &&
126 readerIndex + SslUtils.SSL_RECORD_HEADER_LENGTH + 4 <= endOffset) {
127 final int handshakeType = in.getUnsignedByte(readerIndex +
128 SslUtils.SSL_RECORD_HEADER_LENGTH);
129
130
131
132 if (handshakeType != 1) {
133 select(ctx, null);
134 return;
135 }
136
137
138
139 handshakeLength = in.getUnsignedMedium(readerIndex +
140 SslUtils.SSL_RECORD_HEADER_LENGTH + 1);
141
142 if (handshakeLength > maxClientHelloLength && maxClientHelloLength != 0) {
143 TooLongFrameException e = new TooLongFrameException(
144 "ClientHello length exceeds " + maxClientHelloLength +
145 ": " + handshakeLength);
146 in.skipBytes(in.readableBytes());
147 ctx.fireUserEventTriggered(new SniCompletionEvent(e));
148 SslUtils.handleHandshakeFailure(ctx, e, true);
149 throw e;
150 }
151
152 if (handshakeLength + 4 + SslUtils.SSL_RECORD_HEADER_LENGTH <= packetLength) {
153
154
155 readerIndex += SslUtils.SSL_RECORD_HEADER_LENGTH + 4;
156 final int clientHelloLength = handshakeLength;
157 handshakeLength = -1;
158 select(ctx, in.retainedSlice(readerIndex, clientHelloLength));
159 return;
160 }
161 }
162 }
163
164 if (handshakeBuffer == null) {
165 handshakeBuffer = ctx.alloc().buffer();
166 }
167
168
169 handshakeBuffer.writeBytes(in, readerIndex + SslUtils.SSL_RECORD_HEADER_LENGTH,
170 packetLength - SslUtils.SSL_RECORD_HEADER_LENGTH);
171 readerIndex += packetLength;
172 readableBytes -= packetLength;
173 aggregatedBytes += packetLength;
174 if (handshakeLength == -1) {
175 if (handshakeBuffer.readableBytes() < 4) {
176 continue;
177 }
178
179 final int handshakeType = handshakeBuffer.getUnsignedByte(0);
180 handshakeLength = handshakeBuffer.getUnsignedMedium(1);
181
182
183
184 if (handshakeType != 1) {
185 select(ctx, null);
186 return;
187 }
188
189 if (handshakeLength > maxClientHelloLength && maxClientHelloLength != 0) {
190 TooLongFrameException e = new TooLongFrameException(
191 "ClientHello length exceeds " + maxClientHelloLength +
192 ": " + handshakeLength);
193 in.skipBytes(in.readableBytes());
194 ctx.fireUserEventTriggered(new SniCompletionEvent(e));
195 SslUtils.handleHandshakeFailure(ctx, e, true);
196 throw e;
197 }
198 }
199
200 if (handshakeBuffer.readableBytes() >= handshakeLength + 4) {
201 ByteBuf clientHello = handshakeBuffer.setIndex(4, handshakeLength + 4).slice();
202 handshakeBuffer = null;
203 handshakeLength = -1;
204
205 select(ctx, clientHello);
206 return;
207 }
208 break;
209 }
210
211 default:
212
213 select(ctx, null);
214 return;
215 }
216 }
217 } catch (NotSslRecordException e) {
218
219 throw e;
220 } catch (TooLongFrameException e) {
221
222 throw e;
223 } catch (Exception e) {
224
225 if (logger.isDebugEnabled()) {
226 logger.debug("Unexpected client hello packet: " + ByteBufUtil.hexDump(in), e);
227 }
228 select(ctx, null);
229 }
230 }
231 }
232
233 private void releaseHandshakeBuffer() {
234 releaseIfNotNull(handshakeBuffer);
235 handshakeBuffer = null;
236 handshakeLength = -1;
237 }
238
239 private static void releaseIfNotNull(ByteBuf buffer) {
240 if (buffer != null) {
241 buffer.release();
242 }
243 }
244
245 private void select(final ChannelHandlerContext ctx, ByteBuf clientHello) throws Exception {
246 final Future<T> future;
247 try {
248 future = lookup(ctx, clientHello);
249 if (future.isDone()) {
250 try {
251 onLookupComplete(ctx, future);
252 } catch (DecoderException err) {
253 ctx.fireExceptionCaught(err);
254 } catch (Exception cause) {
255 ctx.fireExceptionCaught(new DecoderException(cause));
256 } catch (Throwable cause) {
257 ctx.fireExceptionCaught(cause);
258 }
259 } else {
260 suppressRead = true;
261 final ByteBuf finalClientHello = clientHello;
262 future.addListener((FutureListener<T>) future1 -> {
263 releaseIfNotNull(finalClientHello);
264 try {
265 suppressRead = false;
266 try {
267 onLookupComplete(ctx, future1);
268 } catch (DecoderException err) {
269 ctx.fireExceptionCaught(err);
270 } catch (Exception cause) {
271 ctx.fireExceptionCaught(new DecoderException(cause));
272 } catch (Throwable cause) {
273 ctx.fireExceptionCaught(cause);
274 }
275 } finally {
276 if (readPending) {
277 readPending = false;
278 ctx.read();
279 }
280 }
281 });
282
283
284 clientHello = null;
285 }
286 } catch (Throwable cause) {
287 PlatformDependent.throwException(cause);
288 } finally {
289 releaseIfNotNull(clientHello);
290 }
291 }
292
293 @Override
294 protected void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
295 releaseHandshakeBuffer();
296
297 super.handlerRemoved0(ctx);
298 }
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324 protected abstract Future<T> lookup(ChannelHandlerContext ctx, ByteBuf clientHello) throws Exception;
325
326
327
328
329
330
331 protected abstract void onLookupComplete(ChannelHandlerContext ctx, Future<T> future) throws Exception;
332
333 @Override
334 public void read(ChannelHandlerContext ctx) throws Exception {
335 if (suppressRead) {
336 readPending = true;
337 } else {
338 ctx.read();
339 }
340 }
341
342 @Override
343 public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
344 ctx.bind(localAddress, promise);
345 }
346
347 @Override
348 public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
349 ChannelPromise promise) throws Exception {
350 ctx.connect(remoteAddress, localAddress, promise);
351 }
352
353 @Override
354 public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
355 ctx.disconnect(promise);
356 }
357
358 @Override
359 public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
360 ctx.close(promise);
361 }
362
363 @Override
364 public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
365 ctx.deregister(promise);
366 }
367
368 @Override
369 public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
370 ctx.write(msg, promise);
371 }
372
373 @Override
374 public void flush(ChannelHandlerContext ctx) throws Exception {
375 ctx.flush();
376 }
377 }