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