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    *   https://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.StringUtil;
27  import io.netty.util.internal.SystemPropertyUtil;
28  import io.netty.util.internal.logging.InternalLogger;
29  import io.netty.util.internal.logging.InternalLoggerFactory;
30  
31  import java.nio.ByteBuffer;
32  import java.nio.ByteOrder;
33  import java.security.KeyManagementException;
34  import java.security.NoSuchAlgorithmException;
35  import java.security.NoSuchProviderException;
36  import java.security.Provider;
37  import java.security.SecureRandom;
38  import java.util.Collections;
39  import java.util.LinkedHashSet;
40  import java.util.List;
41  import java.util.Set;
42  
43  import javax.net.ssl.SSLContext;
44  import javax.net.ssl.SSLHandshakeException;
45  import javax.net.ssl.TrustManager;
46  
47  import static java.util.Arrays.asList;
48  
49  /**
50   * Constants for SSL packets.
51   */
52  final class SslUtils {
53      private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslUtils.class);
54  
55      // See https://tools.ietf.org/html/rfc8446#appendix-B.4
56      static final Set<String> TLSV13_CIPHERS = Collections.unmodifiableSet(new LinkedHashSet<String>(
57              asList("TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256",
58                            "TLS_AES_128_GCM_SHA256", "TLS_AES_128_CCM_8_SHA256",
59                            "TLS_AES_128_CCM_SHA256")));
60  
61      static final short DTLS_1_0 = (short) 0xFEFF;
62      static final short DTLS_1_2 = (short) 0xFEFD;
63      static final short DTLS_1_3 = (short) 0xFEFC;
64      static final short DTLS_RECORD_HEADER_LENGTH = 13;
65  
66      private static final String DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY =
67              "io.netty.handler.ssl.defaultEndpointVerificationAlgorithm";
68      /**
69       * Endpoint verification is enabled by default from Netty 4.2 onward, but it wasn't in Netty 4.1 and earlier.
70       * The {@value #DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY} can be set to one of the following
71       * values to control this behavior:
72       * <ul>
73       *     <li>{@code "HTTPS"} — verify subject by DNS hostnames; this is the Netty 4.2 default.</li>
74       *     <li>{@code "LDAP"} — verify subject by LDAP identity.</li>
75       *     <li>{@code "NONE"} — don't enable endpoint verification by default; this is the Netty 4.1 behavior.</li>
76       * </ul>
77       */
78      static final String defaultEndpointVerificationAlgorithm;
79  
80      /**
81       * GMSSL Protocol Version
82       */
83      static final int GMSSL_PROTOCOL_VERSION = 0x101;
84  
85      static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
86  
87      /**
88       * change cipher spec
89       */
90      static final int SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20;
91  
92      /**
93       * alert
94       */
95      static final int SSL_CONTENT_TYPE_ALERT = 21;
96  
97      /**
98       * handshake
99       */
100     static final int SSL_CONTENT_TYPE_HANDSHAKE = 22;
101 
102     /**
103      * application data
104      */
105     static final int SSL_CONTENT_TYPE_APPLICATION_DATA = 23;
106 
107     /**
108      * HeartBeat Extension
109      */
110     static final int SSL_CONTENT_TYPE_EXTENSION_HEARTBEAT = 24;
111 
112     /**
113      * the length of the ssl record header (in bytes)
114      */
115     static final int SSL_RECORD_HEADER_LENGTH = 5;
116 
117     /**
118      * Not enough data in buffer to parse the record length
119      */
120     static final int NOT_ENOUGH_DATA = -1;
121 
122     /**
123      * data is not encrypted
124      */
125     static final int NOT_ENCRYPTED = -2;
126 
127     static final String[] DEFAULT_CIPHER_SUITES;
128     static final String[] DEFAULT_TLSV13_CIPHER_SUITES;
129     static final String[] TLSV13_CIPHER_SUITES = { "TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384" };
130 
131     // self-signed certificate for netty.io and the matching private-key
132     static final String PROBING_CERT = "-----BEGIN CERTIFICATE-----\n" +
133             "MIICrjCCAZagAwIBAgIIdSvQPv1QAZQwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAxMLZXhhbXBs\n" +
134             "ZS5jb20wIBcNMTgwNDA2MjIwNjU5WhgPOTk5OTEyMzEyMzU5NTlaMBYxFDASBgNVBAMTC2V4YW1w\n" +
135             "bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAggbWsmDQ6zNzRZ5AW8E3eoGl\n" +
136             "qWvOBDb5Fs1oBRrVQHuYmVAoaqwDzXYJ0LOwa293AgWEQ1jpcbZ2hpoYQzqEZBTLnFhMrhRFlH6K\n" +
137             "bJND8Y33kZ/iSVBBDuGbdSbJShlM+4WwQ9IAso4MZ4vW3S1iv5fGGpLgbtXRmBf/RU8omN0Gijlv\n" +
138             "WlLWHWijLN8xQtySFuBQ7ssW8RcKAary3pUm6UUQB+Co6lnfti0Tzag8PgjhAJq2Z3wbsGRnP2YS\n" +
139             "vYoaK6qzmHXRYlp/PxrjBAZAmkLJs4YTm/XFF+fkeYx4i9zqHbyone5yerRibsHaXZWLnUL+rFoe\n" +
140             "MdKvr0VS3sGmhQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQADQi441pKmXf9FvUV5EHU4v8nJT9Iq\n" +
141             "yqwsKwXnr7AsUlDGHBD7jGrjAXnG5rGxuNKBQ35wRxJATKrUtyaquFUL6H8O6aGQehiFTk6zmPbe\n" +
142             "12Gu44vqqTgIUxnv3JQJiox8S2hMxsSddpeCmSdvmalvD6WG4NthH6B9ZaBEiep1+0s0RUaBYn73\n" +
143             "I7CCUaAtbjfR6pcJjrFk5ei7uwdQZFSJtkP2z8r7zfeANJddAKFlkaMWn7u+OIVuB4XPooWicObk\n" +
144             "NAHFtP65bocUYnDpTVdiyvn8DdqyZ/EO8n1bBKBzuSLplk2msW4pdgaFgY7Vw/0wzcFXfUXmL1uy\n" +
145             "G8sQD/wx\n" +
146             "-----END CERTIFICATE-----";
147     static final String PROBING_KEY = "-----BEGIN PRIVATE KEY-----\n" +
148             "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCCBtayYNDrM3NFnkBbwTd6gaWp\n" +
149             "a84ENvkWzWgFGtVAe5iZUChqrAPNdgnQs7Brb3cCBYRDWOlxtnaGmhhDOoRkFMucWEyuFEWUfops\n" +
150             "k0PxjfeRn+JJUEEO4Zt1JslKGUz7hbBD0gCyjgxni9bdLWK/l8YakuBu1dGYF/9FTyiY3QaKOW9a\n" +
151             "UtYdaKMs3zFC3JIW4FDuyxbxFwoBqvLelSbpRRAH4KjqWd+2LRPNqDw+COEAmrZnfBuwZGc/ZhK9\n" +
152             "ihorqrOYddFiWn8/GuMEBkCaQsmzhhOb9cUX5+R5jHiL3OodvKid7nJ6tGJuwdpdlYudQv6sWh4x\n" +
153             "0q+vRVLewaaFAgMBAAECggEAP8tPJvFtTxhNJAkCloHz0D0vpDHqQBMgntlkgayqmBqLwhyb18pR\n" +
154             "i0qwgh7HHc7wWqOOQuSqlEnrWRrdcI6TSe8R/sErzfTQNoznKWIPYcI/hskk4sdnQ//Yn9/Jvnsv\n" +
155             "U/BBjOTJxtD+sQbhAl80JcA3R+5sArURQkfzzHOL/YMqzAsn5hTzp7HZCxUqBk3KaHRxV7NefeOE\n" +
156             "xlZuWSmxYWfbFIs4kx19/1t7h8CHQWezw+G60G2VBtSBBxDnhBWvqG6R/wpzJ3nEhPLLY9T+XIHe\n" +
157             "ipzdMOOOUZorfIg7M+pyYPji+ZIZxIpY5OjrOzXHciAjRtr5Y7l99K1CG1LguQKBgQDrQfIMxxtZ\n" +
158             "vxU/1cRmUV9l7pt5bjV5R6byXq178LxPKVYNjdZ840Q0/OpZEVqaT1xKVi35ohP1QfNjxPLlHD+K\n" +
159             "iDAR9z6zkwjIrbwPCnb5kuXy4lpwPcmmmkva25fI7qlpHtbcuQdoBdCfr/KkKaUCMPyY89LCXgEw\n" +
160             "5KTDj64UywKBgQCNfbO+eZLGzhiHhtNJurresCsIGWlInv322gL8CSfBMYl6eNfUTZvUDdFhPISL\n" +
161             "UljKWzXDrjw0ujFSPR0XhUGtiq89H+HUTuPPYv25gVXO+HTgBFZEPl4PpA+BUsSVZy0NddneyqLk\n" +
162             "42Wey9omY9Q8WsdNQS5cbUvy0uG6WFoX7wKBgQDZ1jpW8pa0x2bZsQsm4vo+3G5CRnZlUp+XlWt2\n" +
163             "dDcp5dC0xD1zbs1dc0NcLeGDOTDv9FSl7hok42iHXXq8AygjEm/QcuwwQ1nC2HxmQP5holAiUs4D\n" +
164             "WHM8PWs3wFYPzE459EBoKTxeaeP/uWAn+he8q7d5uWvSZlEcANs/6e77eQKBgD21Ar0hfFfj7mK8\n" +
165             "9E0FeRZBsqK3omkfnhcYgZC11Xa2SgT1yvs2Va2n0RcdM5kncr3eBZav2GYOhhAdwyBM55XuE/sO\n" +
166             "eokDVutNeuZ6d5fqV96TRaRBpvgfTvvRwxZ9hvKF4Vz+9wfn/JvCwANaKmegF6ejs7pvmF3whq2k\n" +
167             "drZVAoGAX5YxQ5XMTD0QbMAl7/6qp6S58xNoVdfCkmkj1ZLKaHKIjS/benkKGlySVQVPexPfnkZx\n" +
168             "p/Vv9yyphBoudiTBS9Uog66ueLYZqpgxlM/6OhYg86Gm3U2ycvMxYjBM1NFiyze21AqAhI+HX+Ot\n" +
169             "mraV2/guSgDgZAhukRZzeQ2RucI=\n" +
170             "-----END PRIVATE KEY-----";
171 
172     private static final boolean TLSV1_3_JDK_SUPPORTED;
173     private static final boolean TLSV1_3_JDK_DEFAULT_ENABLED;
174 
175     static {
176         TLSV1_3_JDK_SUPPORTED = isTLSv13SupportedByJDK0(null);
177         TLSV1_3_JDK_DEFAULT_ENABLED = isTLSv13EnabledByJDK0(null);
178         if (TLSV1_3_JDK_SUPPORTED) {
179             DEFAULT_TLSV13_CIPHER_SUITES = TLSV13_CIPHER_SUITES;
180         } else {
181             DEFAULT_TLSV13_CIPHER_SUITES = EmptyArrays.EMPTY_STRINGS;
182         }
183 
184         Set<String> defaultCiphers = new LinkedHashSet<String>();
185         // GCM (Galois/Counter Mode) requires JDK 8.
186         defaultCiphers.add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
187         defaultCiphers.add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
188         defaultCiphers.add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
189         defaultCiphers.add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");
190         defaultCiphers.add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
191         // AES256 requires JCE unlimited strength jurisdiction policy files.
192         defaultCiphers.add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA");
193         // GCM (Galois/Counter Mode) requires JDK 8.
194         defaultCiphers.add("TLS_RSA_WITH_AES_128_GCM_SHA256");
195         defaultCiphers.add("TLS_RSA_WITH_AES_128_CBC_SHA");
196         // AES256 requires JCE unlimited strength jurisdiction policy files.
197         defaultCiphers.add("TLS_RSA_WITH_AES_256_CBC_SHA");
198 
199         Collections.addAll(defaultCiphers, DEFAULT_TLSV13_CIPHER_SUITES);
200 
201         DEFAULT_CIPHER_SUITES = defaultCiphers.toArray(EmptyArrays.EMPTY_STRINGS);
202 
203         String defaultEndpointVerification = SystemPropertyUtil.get(DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY);
204         if ("LDAP".equalsIgnoreCase(defaultEndpointVerification)) {
205             defaultEndpointVerificationAlgorithm = "LDAP";
206         } else if ("NONE".equalsIgnoreCase(defaultEndpointVerification)) {
207             logger.info("Default SSL endpoint verification has been disabled:  -D{}=\"{}\"",
208                     DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY, defaultEndpointVerification);
209             defaultEndpointVerificationAlgorithm = null;
210         } else {
211             if (defaultEndpointVerification != null && !"HTTPS".equalsIgnoreCase(defaultEndpointVerification)) {
212                 logger.warn("Unknown default SSL endpoint verification algorithm: -D{}=\"{}\", " +
213                                 "will use \"HTTPS\" instead.",
214                         DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY, defaultEndpointVerification);
215             }
216             defaultEndpointVerificationAlgorithm = "HTTPS";
217         }
218     }
219 
220     /**
221      * Returns {@code true} if the JDK itself supports TLSv1.3, {@code false} otherwise.
222      */
223     static boolean isTLSv13SupportedByJDK(Provider provider) {
224         if (provider == null) {
225             return TLSV1_3_JDK_SUPPORTED;
226         }
227         return isTLSv13SupportedByJDK0(provider);
228     }
229 
230     private static boolean isTLSv13SupportedByJDK0(Provider provider) {
231         try {
232             return arrayContains(newInitContext(provider)
233                     .getSupportedSSLParameters().getProtocols(), SslProtocols.TLS_v1_3);
234         } catch (Throwable cause) {
235             logger.debug("Unable to detect if JDK SSLEngine with provider {} supports TLSv1.3, assuming no",
236                     provider, cause);
237             return false;
238         }
239     }
240 
241     /**
242      * Returns {@code true} if the JDK itself supports TLSv1.3 and enabled it by default, {@code false} otherwise.
243      */
244     static boolean isTLSv13EnabledByJDK(Provider provider) {
245         if (provider == null) {
246             return TLSV1_3_JDK_DEFAULT_ENABLED;
247         }
248         return isTLSv13EnabledByJDK0(provider);
249     }
250 
251     private static boolean isTLSv13EnabledByJDK0(Provider provider) {
252         try {
253             return arrayContains(newInitContext(provider)
254                     .getDefaultSSLParameters().getProtocols(), SslProtocols.TLS_v1_3);
255         } catch (Throwable cause) {
256             logger.debug("Unable to detect if JDK SSLEngine with provider {} enables TLSv1.3 by default," +
257                     " assuming no", provider, cause);
258             return false;
259         }
260     }
261 
262     private static SSLContext newInitContext(Provider provider)
263             throws NoSuchAlgorithmException, KeyManagementException {
264         final SSLContext context;
265         if (provider == null) {
266             context = SSLContext.getInstance("TLS");
267         } else {
268             context = SSLContext.getInstance("TLS", provider);
269         }
270         context.init(null, new TrustManager[0], null);
271         return context;
272     }
273 
274     static SSLContext getSSLContext(Provider provider)
275             throws NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException {
276         return getSSLContext(provider, null);
277     }
278 
279     static SSLContext getSSLContext(Provider provider, SecureRandom secureRandom)
280             throws NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException {
281         final SSLContext context;
282         if (provider == null) {
283             context = SSLContext.getInstance(getTlsVersion());
284         } else {
285             context = SSLContext.getInstance(getTlsVersion(), provider);
286         }
287         context.init(null, new TrustManager[0], secureRandom);
288         return context;
289     }
290 
291     private static String getTlsVersion() {
292         return TLSV1_3_JDK_SUPPORTED ? SslProtocols.TLS_v1_3 : SslProtocols.TLS_v1_2;
293     }
294 
295     static boolean arrayContains(String[] array, String value) {
296         for (String v: array) {
297             if (value.equals(v)) {
298                 return true;
299             }
300         }
301         return false;
302     }
303 
304     /**
305      * Add elements from {@code names} into {@code enabled} if they are in {@code supported}.
306      */
307     static void addIfSupported(Set<String> supported, List<String> enabled, String... names) {
308         for (String n: names) {
309             if (supported.contains(n)) {
310                 enabled.add(n);
311             }
312         }
313     }
314 
315     static void useFallbackCiphersIfDefaultIsEmpty(List<String> defaultCiphers, Iterable<String> fallbackCiphers) {
316         if (defaultCiphers.isEmpty()) {
317             for (String cipher : fallbackCiphers) {
318                 if (cipher.startsWith("SSL_") || cipher.contains("_RC4_")) {
319                     continue;
320                 }
321                 defaultCiphers.add(cipher);
322             }
323         }
324     }
325 
326     static void useFallbackCiphersIfDefaultIsEmpty(List<String> defaultCiphers, String... fallbackCiphers) {
327         useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, asList(fallbackCiphers));
328     }
329 
330     /**
331      * Converts the given exception to a {@link SSLHandshakeException}, if it isn't already.
332      */
333     static SSLHandshakeException toSSLHandshakeException(Throwable e) {
334         if (e instanceof SSLHandshakeException) {
335             return (SSLHandshakeException) e;
336         }
337 
338         return (SSLHandshakeException) new SSLHandshakeException(e.getMessage()).initCause(e);
339     }
340 
341     /**
342      * Return how much bytes can be read out of the encrypted data. Be aware that this method will not increase
343      * the readerIndex of the given {@link ByteBuf}.
344      *
345      * @param   buffer      The {@link ByteBuf} to read from.
346      * @param   offset      The offset to start from.
347      * @param   probeSSLv2  {@code true} if the input {@code buffer} might be SSLv2.
348      * @return              The length of the encrypted packet that is included in the buffer or
349      *                      {@link #SslUtils#NOT_ENOUGH_DATA} if not enough data is present in the
350      *                      {@link ByteBuf}. This will return {@link SslUtils#NOT_ENCRYPTED} if
351      *                      the given {@link ByteBuf} is not encrypted at all.
352      */
353     static int getEncryptedPacketLength(ByteBuf buffer, int offset, boolean probeSSLv2) {
354         assert offset >= buffer.readerIndex();
355         int remaining = buffer.writerIndex() - offset;
356         if (remaining < SSL_RECORD_HEADER_LENGTH) {
357             return NOT_ENOUGH_DATA;
358         }
359         int packetLength = 0;
360         // SSLv3 or TLS - Check ContentType
361         boolean tls;
362         switch (buffer.getUnsignedByte(offset)) {
363             case SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
364             case SSL_CONTENT_TYPE_ALERT:
365             case SSL_CONTENT_TYPE_HANDSHAKE:
366             case SSL_CONTENT_TYPE_APPLICATION_DATA:
367             case SSL_CONTENT_TYPE_EXTENSION_HEARTBEAT:
368                 tls = true;
369                 break;
370             default:
371                 // SSLv2 or bad data
372                 if (!probeSSLv2) {
373                     return NOT_ENCRYPTED;
374                 }
375                 tls = false;
376         }
377 
378         if (tls) {
379             // SSLv3 or TLS or GMSSLv1.0 or GMSSLv1.1 - Check ProtocolVersion
380             int majorVersion = buffer.getUnsignedByte(offset + 1);
381             int version = buffer.getShort(offset + 1);
382             if (majorVersion == 3 || version == GMSSL_PROTOCOL_VERSION) {
383                 // SSLv3 or TLS or GMSSLv1.0 or GMSSLv1.1
384                 packetLength = unsignedShortBE(buffer, offset + 3) + SSL_RECORD_HEADER_LENGTH;
385                 if (packetLength <= SSL_RECORD_HEADER_LENGTH) {
386                     // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
387                     tls = false;
388                 }
389             } else if (version == DTLS_1_0 || version == DTLS_1_2 || version == DTLS_1_3) {
390                 if (remaining < DTLS_RECORD_HEADER_LENGTH) {
391                     return NOT_ENOUGH_DATA;
392                 }
393                 // length is the last 2 bytes in the 13 byte header.
394                 packetLength = unsignedShortBE(buffer, offset + DTLS_RECORD_HEADER_LENGTH - 2) +
395                         DTLS_RECORD_HEADER_LENGTH;
396             } else {
397                 // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
398                 tls = false;
399             }
400         }
401 
402         if (!tls) {
403             // SSLv2 or bad data - Check the version
404             int headerLength = (buffer.getUnsignedByte(offset) & 0x80) != 0 ? 2 : 3;
405             int majorVersion = buffer.getUnsignedByte(offset + headerLength + 1);
406             if (majorVersion == 2 || majorVersion == 3) {
407                 // SSLv2
408                 packetLength = headerLength == 2 ?
409                         (shortBE(buffer, offset) & 0x7FFF) + 2 : (shortBE(buffer, offset) & 0x3FFF) + 3;
410                 if (packetLength <= headerLength) {
411                     // If there's no data then consider this package as not encrypted.
412                     return NOT_ENCRYPTED;
413                 }
414             } else {
415                 return NOT_ENCRYPTED;
416             }
417         }
418         return packetLength;
419     }
420 
421     // Reads a big-endian unsigned short integer from the buffer
422     @SuppressWarnings("deprecation")
423     private static int unsignedShortBE(ByteBuf buffer, int offset) {
424         int value = buffer.getUnsignedShort(offset);
425         if (buffer.order() == ByteOrder.LITTLE_ENDIAN) {
426             value = Integer.reverseBytes(value) >>> Short.SIZE;
427         }
428         return value;
429     }
430 
431     // Reads a big-endian short integer from the buffer
432     @SuppressWarnings("deprecation")
433     private static short shortBE(ByteBuf buffer, int offset) {
434         short value = buffer.getShort(offset);
435         if (buffer.order() == ByteOrder.LITTLE_ENDIAN) {
436             value = Short.reverseBytes(value);
437         }
438         return value;
439     }
440 
441     private static short unsignedByte(byte b) {
442         return (short) (b & 0xFF);
443     }
444 
445     // Reads a big-endian unsigned short integer from the buffer
446     private static int unsignedShortBE(ByteBuffer buffer, int offset) {
447         return shortBE(buffer, offset) & 0xFFFF;
448     }
449 
450     // Reads a big-endian short integer from the buffer
451     private static short shortBE(ByteBuffer buffer, int offset) {
452         return buffer.order() == ByteOrder.BIG_ENDIAN ?
453                 buffer.getShort(offset) : ByteBufUtil.swapShort(buffer.getShort(offset));
454     }
455 
456     static int getEncryptedPacketLength(ByteBuffer[] buffers, int offset) {
457         ByteBuffer buffer = buffers[offset];
458 
459         // Check if everything we need is in one ByteBuffer. If so we can make use of the fast-path.
460         if (buffer.remaining() >= SSL_RECORD_HEADER_LENGTH) {
461             return getEncryptedPacketLength(buffer);
462         }
463 
464         // We need to copy 5 bytes into a temporary buffer so we can parse out the packet length easily.
465         ByteBuffer tmp = ByteBuffer.allocate(SSL_RECORD_HEADER_LENGTH);
466 
467         do {
468             buffer = buffers[offset++].duplicate();
469             if (buffer.remaining() > tmp.remaining()) {
470                 buffer.limit(buffer.position() + tmp.remaining());
471             }
472             tmp.put(buffer);
473         } while (tmp.hasRemaining() && offset < buffers.length);
474 
475         // Done, flip the buffer so we can read from it.
476         tmp.flip();
477         return getEncryptedPacketLength(tmp);
478     }
479 
480     private static int getEncryptedPacketLength(ByteBuffer buffer) {
481         int remaining = buffer.remaining();
482         if (remaining < SSL_RECORD_HEADER_LENGTH) {
483             return NOT_ENOUGH_DATA;
484         }
485         int packetLength = 0;
486         int pos = buffer.position();
487 
488         // SSLv3 or TLS - Check ContentType
489         boolean tls;
490         switch (unsignedByte(buffer.get(pos))) {
491             case SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC:
492             case SSL_CONTENT_TYPE_ALERT:
493             case SSL_CONTENT_TYPE_HANDSHAKE:
494             case SSL_CONTENT_TYPE_APPLICATION_DATA:
495             case SSL_CONTENT_TYPE_EXTENSION_HEARTBEAT:
496                 tls = true;
497                 break;
498             default:
499                 // SSLv2 or bad data
500                 tls = false;
501         }
502 
503         if (tls) {
504             // SSLv3 or TLS or GMSSLv1.0 or GMSSLv1.1 - Check ProtocolVersion
505             int majorVersion = unsignedByte(buffer.get(pos + 1));
506             if (majorVersion == 3 || buffer.getShort(pos + 1) == GMSSL_PROTOCOL_VERSION) {
507                 // SSLv3 or TLS or GMSSLv1.0 or GMSSLv1.1
508                 packetLength = unsignedShortBE(buffer, pos + 3) + SSL_RECORD_HEADER_LENGTH;
509                 if (packetLength <= SSL_RECORD_HEADER_LENGTH) {
510                     // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
511                     tls = false;
512                 }
513             } else {
514                 // Neither SSLv3 or TLSv1 (i.e. SSLv2 or bad data)
515                 tls = false;
516             }
517         }
518 
519         if (!tls) {
520             // SSLv2 or bad data - Check the version
521             int headerLength = (unsignedByte(buffer.get(pos)) & 0x80) != 0 ? 2 : 3;
522             int majorVersion = unsignedByte(buffer.get(pos + headerLength + 1));
523             if (majorVersion == 2 || majorVersion == 3) {
524                 // SSLv2
525                 packetLength = headerLength == 2 ?
526                         (shortBE(buffer, pos) & 0x7FFF) + 2 : (shortBE(buffer, pos) & 0x3FFF) + 3;
527                 if (packetLength <= headerLength) {
528                     // If there's no data then consider this package as not encrypted.
529                     return NOT_ENCRYPTED;
530                 }
531             } else {
532                 return NOT_ENCRYPTED;
533             }
534         }
535         return packetLength;
536     }
537 
538     static void handleHandshakeFailure(ChannelHandlerContext ctx, Throwable cause, boolean notify) {
539         // We have may haven written some parts of data before an exception was thrown so ensure we always flush.
540         // See https://github.com/netty/netty/issues/3900#issuecomment-172481830
541         ctx.flush();
542         if (notify) {
543             ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
544         }
545         ctx.close();
546     }
547 
548     /**
549      * Fills the {@link ByteBuf} with zero bytes.
550      */
551     static void zeroout(ByteBuf buffer) {
552         if (!buffer.isReadOnly()) {
553             buffer.setZero(0, buffer.capacity());
554         }
555     }
556 
557     /**
558      * Fills the {@link ByteBuf} with zero bytes and releases it.
559      */
560     static void zerooutAndRelease(ByteBuf buffer) {
561         zeroout(buffer);
562         buffer.release();
563     }
564 
565     /**
566      * Same as {@link Base64#encode(ByteBuf, boolean)} but allows the use of a custom {@link ByteBufAllocator}.
567      *
568      * @see Base64#encode(ByteBuf, boolean)
569      */
570     static ByteBuf toBase64(ByteBufAllocator allocator, ByteBuf src) {
571         ByteBuf dst = Base64.encode(src, src.readerIndex(),
572                 src.readableBytes(), true, Base64Dialect.STANDARD, allocator);
573         src.readerIndex(src.writerIndex());
574         return dst;
575     }
576 
577     /**
578      * Validate that the given hostname can be used in SNI extension.
579      */
580     static boolean isValidHostNameForSNI(String hostname) {
581         // See  https://datatracker.ietf.org/doc/html/rfc6066#section-3
582         return hostname != null &&
583                 // SNI HostName has to be a FQDN according to TLS SNI Extension spec (see [1]),
584                 // which means that is has to have at least a host name and a domain part.
585                 hostname.indexOf('.') > 0 &&
586                 !hostname.endsWith(".") && !hostname.startsWith("/") &&
587                 !NetUtil.isValidIpV4Address(hostname) &&
588                 !NetUtil.isValidIpV6Address(hostname);
589     }
590 
591     /**
592      * Returns {@code true} if the given cipher (in openssl format) is for TLSv1.3, {@code false} otherwise.
593      */
594     static boolean isTLSv13Cipher(String cipher) {
595         // See https://tools.ietf.org/html/rfc8446#appendix-B.4
596         return TLSV13_CIPHERS.contains(cipher);
597     }
598 
599     private SslUtils() {
600     }
601 }