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