View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.ssl;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  import io.netty.buffer.ByteBufUtil;
21  import io.netty.channel.ChannelHandlerContext;
22  import io.netty.handler.codec.base64.Base64;
23  import io.netty.handler.codec.base64.Base64Dialect;
24  
25  import java.nio.ByteBuffer;
26  import java.nio.ByteOrder;
27  import java.util.List;
28  import java.util.Set;
29  
30  import javax.net.ssl.SSLHandshakeException;
31  
32  import static java.util.Arrays.asList;
33  
34  /**
35   * Constants for SSL packets.
36   */
37  final class SslUtils {
38  
39      // Protocols
40      static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello";
41      static final String PROTOCOL_SSL_V2 = "SSLv2";
42      static final String PROTOCOL_SSL_V3 = "SSLv3";
43      static final String PROTOCOL_TLS_V1 = "TLSv1";
44      static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
45      static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
46  
47      /**
48       * change cipher spec
49       */
50      static final int SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20;
51  
52      /**
53       * alert
54       */
55      static final int SSL_CONTENT_TYPE_ALERT = 21;
56  
57      /**
58       * handshake
59       */
60      static final int SSL_CONTENT_TYPE_HANDSHAKE = 22;
61  
62      /**
63       * application data
64       */
65      static final int SSL_CONTENT_TYPE_APPLICATION_DATA = 23;
66  
67      /**
68       * HeartBeat Extension
69       */
70      static final int SSL_CONTENT_TYPE_EXTENSION_HEARTBEAT = 24;
71  
72      /**
73       * the length of the ssl record header (in bytes)
74       */
75      static final int SSL_RECORD_HEADER_LENGTH = 5;
76  
77      /**
78       * Not enough data in buffer to parse the record length
79       */
80      static final int NOT_ENOUGH_DATA = -1;
81  
82      /**
83       * data is not encrypted
84       */
85      static final int NOT_ENCRYPTED = -2;
86  
87      static final String[] DEFAULT_CIPHER_SUITES = {
88          // GCM (Galois/Counter Mode) requires JDK 8.
89          "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
90          "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
91          "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
92          "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
93          // AES256 requires JCE unlimited strength jurisdiction policy files.
94          "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
95          // GCM (Galois/Counter Mode) requires JDK 8.
96          "TLS_RSA_WITH_AES_128_GCM_SHA256",
97          "TLS_RSA_WITH_AES_128_CBC_SHA",
98          // AES256 requires JCE unlimited strength jurisdiction policy files.
99          "TLS_RSA_WITH_AES_256_CBC_SHA"
100     };
101 
102     /**
103      * Add elements from {@code names} into {@code enabled} if they are in {@code supported}.
104      */
105     static void addIfSupported(Set<String> supported, List<String> enabled, String... names) {
106         for (String n: names) {
107             if (supported.contains(n)) {
108                 enabled.add(n);
109             }
110         }
111     }
112 
113     static void useFallbackCiphersIfDefaultIsEmpty(List<String> defaultCiphers, Iterable<String> fallbackCiphers) {
114         if (defaultCiphers.isEmpty()) {
115             for (String cipher : fallbackCiphers) {
116                 if (cipher.startsWith("SSL_") || cipher.contains("_RC4_")) {
117                     continue;
118                 }
119                 defaultCiphers.add(cipher);
120             }
121         }
122     }
123 
124     static void useFallbackCiphersIfDefaultIsEmpty(List<String> defaultCiphers, String... fallbackCiphers) {
125         useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, asList(fallbackCiphers));
126     }
127 
128     /**
129      * Converts the given exception to a {@link SSLHandshakeException}, if it isn't already.
130      */
131     static SSLHandshakeException toSSLHandshakeException(Throwable e) {
132         if (e instanceof SSLHandshakeException) {
133             return (SSLHandshakeException) e;
134         }
135 
136         return (SSLHandshakeException) new SSLHandshakeException(e.getMessage()).initCause(e);
137     }
138 
139     /**
140      * Return how much bytes can be read out of the encrypted data. Be aware that this method will not increase
141      * the readerIndex of the given {@link ByteBuf}.
142      *
143      * @param   buffer
144      *                  The {@link ByteBuf} to read from. Be aware that it must have at least
145      *                  {@link #SSL_RECORD_HEADER_LENGTH} bytes to read,
146      *                  otherwise it will throw an {@link IllegalArgumentException}.
147      * @return length
148      *                  The length of the encrypted packet that is included in the buffer or
149      *                  {@link #SslUtils#NOT_ENOUGH_DATA} if not enough data is present in the
150      *                  {@link ByteBuf}. This will return {@link SslUtils#NOT_ENCRYPTED} if
151      *                  the given {@link ByteBuf} is not encrypted at all.
152      * @throws IllegalArgumentException
153      *                  Is thrown if the given {@link ByteBuf} has not at least {@link #SSL_RECORD_HEADER_LENGTH}
154      *                  bytes to read.
155      */
156     static int getEncryptedPacketLength(ByteBuf buffer, int offset) {
157         int packetLength = 0;
158 
159         // SSLv3 or TLS - Check ContentType
160         boolean tls;
161         switch (buffer.getUnsignedByte(offset)) {
162             case SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
163             case SSL_CONTENT_TYPE_ALERT:
164             case SSL_CONTENT_TYPE_HANDSHAKE:
165             case SSL_CONTENT_TYPE_APPLICATION_DATA:
166             case SSL_CONTENT_TYPE_EXTENSION_HEARTBEAT:
167                 tls = true;
168                 break;
169             default:
170                 // SSLv2 or bad data
171                 tls = false;
172         }
173 
174         if (tls) {
175             // SSLv3 or TLS - Check ProtocolVersion
176             int majorVersion = buffer.getUnsignedByte(offset + 1);
177             if (majorVersion == 3) {
178                 // SSLv3 or TLS
179                 packetLength = unsignedShortBE(buffer, offset + 3) + SSL_RECORD_HEADER_LENGTH;
180                 if (packetLength <= SSL_RECORD_HEADER_LENGTH) {
181                     // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
182                     tls = false;
183                 }
184             } else {
185                 // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
186                 tls = false;
187             }
188         }
189 
190         if (!tls) {
191             // SSLv2 or bad data - Check the version
192             int headerLength = (buffer.getUnsignedByte(offset) & 0x80) != 0 ? 2 : 3;
193             int majorVersion = buffer.getUnsignedByte(offset + headerLength + 1);
194             if (majorVersion == 2 || majorVersion == 3) {
195                 // SSLv2
196                 packetLength = headerLength == 2 ?
197                         (shortBE(buffer, offset) & 0x7FFF) + 2 : (shortBE(buffer, offset) & 0x3FFF) + 3;
198                 if (packetLength <= headerLength) {
199                     return NOT_ENOUGH_DATA;
200                 }
201             } else {
202                 return NOT_ENCRYPTED;
203             }
204         }
205         return packetLength;
206     }
207 
208     // Reads a big-endian unsigned short integer from the buffer
209     @SuppressWarnings("deprecation")
210     private static int unsignedShortBE(ByteBuf buffer, int offset) {
211         return buffer.order() == ByteOrder.BIG_ENDIAN ?
212                 buffer.getUnsignedShort(offset) : buffer.getUnsignedShortLE(offset);
213     }
214 
215     // Reads a big-endian short integer from the buffer
216     @SuppressWarnings("deprecation")
217     private static short shortBE(ByteBuf buffer, int offset) {
218         return buffer.order() == ByteOrder.BIG_ENDIAN ?
219                 buffer.getShort(offset) : buffer.getShortLE(offset);
220     }
221 
222     private static short unsignedByte(byte b) {
223         return (short) (b & 0xFF);
224     }
225 
226     // Reads a big-endian unsigned short integer from the buffer
227     private static int unsignedShortBE(ByteBuffer buffer, int offset) {
228         return shortBE(buffer, offset) & 0xFFFF;
229     }
230 
231     // Reads a big-endian short integer from the buffer
232     private static short shortBE(ByteBuffer buffer, int offset) {
233         return buffer.order() == ByteOrder.BIG_ENDIAN ?
234                 buffer.getShort(offset) : ByteBufUtil.swapShort(buffer.getShort(offset));
235     }
236 
237     static int getEncryptedPacketLength(ByteBuffer[] buffers, int offset) {
238         ByteBuffer buffer = buffers[offset];
239 
240         // Check if everything we need is in one ByteBuffer. If so we can make use of the fast-path.
241         if (buffer.remaining() >= SSL_RECORD_HEADER_LENGTH) {
242             return getEncryptedPacketLength(buffer);
243         }
244 
245         // We need to copy 5 bytes into a temporary buffer so we can parse out the packet length easily.
246         ByteBuffer tmp = ByteBuffer.allocate(5);
247 
248         do {
249             buffer = buffers[offset++].duplicate();
250             if (buffer.remaining() > tmp.remaining()) {
251                 buffer.limit(buffer.position() + tmp.remaining());
252             }
253             tmp.put(buffer);
254         } while (tmp.hasRemaining());
255 
256         // Done, flip the buffer so we can read from it.
257         tmp.flip();
258         return getEncryptedPacketLength(tmp);
259     }
260 
261     private static int getEncryptedPacketLength(ByteBuffer buffer) {
262         int packetLength = 0;
263         int pos = buffer.position();
264         // SSLv3 or TLS - Check ContentType
265         boolean tls;
266         switch (unsignedByte(buffer.get(pos))) {
267             case SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
268             case SSL_CONTENT_TYPE_ALERT:
269             case SSL_CONTENT_TYPE_HANDSHAKE:
270             case SSL_CONTENT_TYPE_APPLICATION_DATA:
271             case SSL_CONTENT_TYPE_EXTENSION_HEARTBEAT:
272                 tls = true;
273                 break;
274             default:
275                 // SSLv2 or bad data
276                 tls = false;
277         }
278 
279         if (tls) {
280             // SSLv3 or TLS - Check ProtocolVersion
281             int majorVersion = unsignedByte(buffer.get(pos + 1));
282             if (majorVersion == 3) {
283                 // SSLv3 or TLS
284                 packetLength = unsignedShortBE(buffer, pos + 3) + SSL_RECORD_HEADER_LENGTH;
285                 if (packetLength <= SSL_RECORD_HEADER_LENGTH) {
286                     // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
287                     tls = false;
288                 }
289             } else {
290                 // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
291                 tls = false;
292             }
293         }
294 
295         if (!tls) {
296             // SSLv2 or bad data - Check the version
297             int headerLength = (unsignedByte(buffer.get(pos)) & 0x80) != 0 ? 2 : 3;
298             int majorVersion = unsignedByte(buffer.get(pos + headerLength + 1));
299             if (majorVersion == 2 || majorVersion == 3) {
300                 // SSLv2
301                 packetLength = headerLength == 2 ?
302                         (shortBE(buffer, pos) & 0x7FFF) + 2 : (shortBE(buffer, pos) & 0x3FFF) + 3;
303                 if (packetLength <= headerLength) {
304                     return NOT_ENOUGH_DATA;
305                 }
306             } else {
307                 return NOT_ENCRYPTED;
308             }
309         }
310         return packetLength;
311     }
312 
313     static void notifyHandshakeFailure(ChannelHandlerContext ctx, Throwable cause, boolean notify) {
314         // We have may haven written some parts of data before an exception was thrown so ensure we always flush.
315         // See https://github.com/netty/netty/issues/3900#issuecomment-172481830
316         ctx.flush();
317         if (notify) {
318             ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
319         }
320         ctx.close();
321     }
322 
323     /**
324      * Fills the {@link ByteBuf} with zero bytes.
325      */
326     static void zeroout(ByteBuf buffer) {
327         if (!buffer.isReadOnly()) {
328             buffer.setZero(0, buffer.capacity());
329         }
330     }
331 
332     /**
333      * Fills the {@link ByteBuf} with zero bytes and releases it.
334      */
335     static void zerooutAndRelease(ByteBuf buffer) {
336         zeroout(buffer);
337         buffer.release();
338     }
339 
340     /**
341      * Same as {@link Base64#encode(ByteBuf, boolean)} but allows the use of a custom {@link ByteBufAllocator}.
342      *
343      * @see Base64#encode(ByteBuf, boolean)
344      */
345     static ByteBuf toBase64(ByteBufAllocator allocator, ByteBuf src) {
346         ByteBuf dst = Base64.encode(src, src.readerIndex(),
347                 src.readableBytes(), true, Base64Dialect.STANDARD, allocator);
348         src.readerIndex(src.writerIndex());
349         return dst;
350     }
351 
352     private SslUtils() {
353     }
354 }