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