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.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
51
52 final class SslUtils {
53 private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslUtils.class);
54
55
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
70
71
72
73
74
75
76
77
78 static final String defaultEndpointVerificationAlgorithm;
79
80
81
82
83 static final int GMSSL_PROTOCOL_VERSION = 0x101;
84
85 static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
86
87
88
89
90 static final int SSL_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20;
91
92
93
94
95 static final int SSL_CONTENT_TYPE_ALERT = 21;
96
97
98
99
100 static final int SSL_CONTENT_TYPE_HANDSHAKE = 22;
101
102
103
104
105 static final int SSL_CONTENT_TYPE_APPLICATION_DATA = 23;
106
107
108
109
110 static final int SSL_CONTENT_TYPE_EXTENSION_HEARTBEAT = 24;
111
112
113
114
115 static final int SSL_RECORD_HEADER_LENGTH = 5;
116
117
118
119
120 static final int NOT_ENOUGH_DATA = -1;
121
122
123
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
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
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
192 defaultCiphers.add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA");
193
194 defaultCiphers.add("TLS_RSA_WITH_AES_128_GCM_SHA256");
195 defaultCiphers.add("TLS_RSA_WITH_AES_128_CBC_SHA");
196
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
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
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
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
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
343
344
345
346
347
348
349
350
351
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
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
372 if (!probeSSLv2) {
373 return NOT_ENCRYPTED;
374 }
375 tls = false;
376 }
377
378 if (tls) {
379
380 int majorVersion = buffer.getUnsignedByte(offset + 1);
381 int version = buffer.getShort(offset + 1);
382 if (majorVersion == 3 || version == GMSSL_PROTOCOL_VERSION) {
383
384 packetLength = unsignedShortBE(buffer, offset + 3) + SSL_RECORD_HEADER_LENGTH;
385 if (packetLength <= SSL_RECORD_HEADER_LENGTH) {
386
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
394 packetLength = unsignedShortBE(buffer, offset + DTLS_RECORD_HEADER_LENGTH - 2) +
395 DTLS_RECORD_HEADER_LENGTH;
396 } else {
397
398 tls = false;
399 }
400 }
401
402 if (!tls) {
403
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
408 packetLength = headerLength == 2 ?
409 (shortBE(buffer, offset) & 0x7FFF) + 2 : (shortBE(buffer, offset) & 0x3FFF) + 3;
410 if (packetLength <= headerLength) {
411
412 return NOT_ENCRYPTED;
413 }
414 } else {
415 return NOT_ENCRYPTED;
416 }
417 }
418 return packetLength;
419 }
420
421
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
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
446 private static int unsignedShortBE(ByteBuffer buffer, int offset) {
447 return shortBE(buffer, offset) & 0xFFFF;
448 }
449
450
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
460 if (buffer.remaining() >= SSL_RECORD_HEADER_LENGTH) {
461 return getEncryptedPacketLength(buffer);
462 }
463
464
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
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
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
500 tls = false;
501 }
502
503 if (tls) {
504
505 int majorVersion = unsignedByte(buffer.get(pos + 1));
506 if (majorVersion == 3 || buffer.getShort(pos + 1) == GMSSL_PROTOCOL_VERSION) {
507
508 packetLength = unsignedShortBE(buffer, pos + 3) + SSL_RECORD_HEADER_LENGTH;
509 if (packetLength <= SSL_RECORD_HEADER_LENGTH) {
510
511 tls = false;
512 }
513 } else {
514
515 tls = false;
516 }
517 }
518
519 if (!tls) {
520
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
525 packetLength = headerLength == 2 ?
526 (shortBE(buffer, pos) & 0x7FFF) + 2 : (shortBE(buffer, pos) & 0x3FFF) + 3;
527 if (packetLength <= headerLength) {
528
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
540
541 ctx.flush();
542 if (notify) {
543 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
544 }
545 ctx.close();
546 }
547
548
549
550
551 static void zeroout(ByteBuf buffer) {
552 if (!buffer.isReadOnly()) {
553 buffer.setZero(0, buffer.capacity());
554 }
555 }
556
557
558
559
560 static void zerooutAndRelease(ByteBuf buffer) {
561 zeroout(buffer);
562 buffer.release();
563 }
564
565
566
567
568
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
579
580 static boolean isValidHostNameForSNI(String hostname) {
581
582 return hostname != null &&
583
584
585 hostname.indexOf('.') > 0 &&
586 !hostname.endsWith(".") && !hostname.startsWith("/") &&
587 !NetUtil.isValidIpV4Address(hostname) &&
588 !NetUtil.isValidIpV6Address(hostname);
589 }
590
591
592
593
594 static boolean isTLSv13Cipher(String cipher) {
595
596 return TLSV13_CIPHERS.contains(cipher);
597 }
598
599 private SslUtils() {
600 }
601 }