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