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