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.handler.ssl.util.LazyX509Certificate;
21 import io.netty.internal.tcnative.AsyncSSLPrivateKeyMethod;
22 import io.netty.internal.tcnative.CertificateCompressionAlgo;
23 import io.netty.internal.tcnative.CertificateVerifier;
24 import io.netty.internal.tcnative.ResultCallback;
25 import io.netty.internal.tcnative.SSL;
26 import io.netty.internal.tcnative.SSLContext;
27 import io.netty.internal.tcnative.SSLPrivateKeyMethod;
28 import io.netty.util.AbstractReferenceCounted;
29 import io.netty.util.ReferenceCounted;
30 import io.netty.util.ResourceLeakDetector;
31 import io.netty.util.ResourceLeakDetectorFactory;
32 import io.netty.util.ResourceLeakTracker;
33 import io.netty.util.concurrent.Future;
34 import io.netty.util.concurrent.FutureListener;
35 import io.netty.util.concurrent.ImmediateExecutor;
36 import io.netty.util.internal.EmptyArrays;
37 import io.netty.util.internal.PlatformDependent;
38 import io.netty.util.internal.StringUtil;
39 import io.netty.util.internal.SystemPropertyUtil;
40 import io.netty.util.internal.UnstableApi;
41 import io.netty.util.internal.logging.InternalLogger;
42 import io.netty.util.internal.logging.InternalLoggerFactory;
43
44 import java.security.PrivateKey;
45 import java.security.SignatureException;
46 import java.security.cert.CertPathValidatorException;
47 import java.security.cert.Certificate;
48 import java.security.cert.CertificateExpiredException;
49 import java.security.cert.CertificateNotYetValidException;
50 import java.security.cert.CertificateRevokedException;
51 import java.security.cert.X509Certificate;
52 import java.util.ArrayList;
53 import java.util.Collections;
54 import java.util.LinkedHashSet;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.concurrent.Executor;
58 import java.util.concurrent.locks.Lock;
59 import java.util.concurrent.locks.ReadWriteLock;
60 import java.util.concurrent.locks.ReentrantReadWriteLock;
61 import javax.net.ssl.KeyManager;
62 import javax.net.ssl.KeyManagerFactory;
63 import javax.net.ssl.SSLEngine;
64 import javax.net.ssl.SSLException;
65 import javax.net.ssl.SSLHandshakeException;
66 import javax.net.ssl.TrustManager;
67 import javax.net.ssl.X509ExtendedTrustManager;
68 import javax.net.ssl.X509KeyManager;
69 import javax.net.ssl.X509TrustManager;
70
71 import static io.netty.handler.ssl.OpenSsl.DEFAULT_CIPHERS;
72 import static io.netty.handler.ssl.OpenSsl.availableJavaCipherSuites;
73 import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
74 import static io.netty.util.internal.ObjectUtil.checkNotNull;
75 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
76
77
78
79
80
81
82
83
84
85
86 public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted {
87 private static final InternalLogger logger =
88 InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
89
90 private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = Math.max(1,
91 SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
92 2048));
93
94 static final boolean USE_TASKS =
95 SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.useTasks", true);
96 private static final Integer DH_KEY_LENGTH;
97 private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector =
98 ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
99
100
101 protected static final int VERIFY_DEPTH = 10;
102
103 static final boolean CLIENT_ENABLE_SESSION_TICKET =
104 SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", false);
105
106 static final boolean CLIENT_ENABLE_SESSION_TICKET_TLSV13 =
107 SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", true);
108
109 static final boolean SERVER_ENABLE_SESSION_TICKET =
110 SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", false);
111
112 static final boolean SERVER_ENABLE_SESSION_TICKET_TLSV13 =
113 SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", true);
114
115 static final boolean SERVER_ENABLE_SESSION_CACHE =
116 SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.sessionCacheServer", true);
117 static final boolean CLIENT_ENABLE_SESSION_CACHE =
118 SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.sessionCacheClient", true);
119
120
121
122
123
124
125 protected long ctx;
126 private final List<String> unmodifiableCiphers;
127 private final OpenSslApplicationProtocolNegotiator apn;
128 private final int mode;
129
130
131 private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
132 private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
133 @Override
134 public ReferenceCounted touch(Object hint) {
135 if (leak != null) {
136 leak.record(hint);
137 }
138
139 return ReferenceCountedOpenSslContext.this;
140 }
141
142 @Override
143 protected void deallocate() {
144 destroy();
145 if (leak != null) {
146 boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
147 assert closed;
148 }
149 }
150 };
151
152 final Certificate[] keyCertChain;
153 final ClientAuth clientAuth;
154 final String[] protocols;
155 final String endpointIdentificationAlgorithm;
156 final boolean hasTLSv13Cipher;
157
158 final boolean enableOcsp;
159 final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
160 final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
161
162 private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
163
164 @SuppressWarnings("deprecation")
165 static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
166 new OpenSslApplicationProtocolNegotiator() {
167 @Override
168 public ApplicationProtocolConfig.Protocol protocol() {
169 return ApplicationProtocolConfig.Protocol.NONE;
170 }
171
172 @Override
173 public List<String> protocols() {
174 return Collections.emptyList();
175 }
176
177 @Override
178 public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() {
179 return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
180 }
181
182 @Override
183 public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
184 return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
185 }
186 };
187
188 static {
189 Integer dhLen = null;
190
191 try {
192 String dhKeySize = SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
193 if (dhKeySize != null) {
194 try {
195 dhLen = Integer.valueOf(dhKeySize);
196 } catch (NumberFormatException e) {
197 logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: "
198 + dhKeySize);
199 }
200 }
201 } catch (Throwable ignore) {
202
203 }
204 DH_KEY_LENGTH = dhLen;
205 }
206
207 final boolean tlsFalseStart;
208
209 ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
210 OpenSslApplicationProtocolNegotiator apn, int mode, Certificate[] keyCertChain,
211 ClientAuth clientAuth, String[] protocols, boolean startTls,
212 String endpointIdentificationAlgorithm, boolean enableOcsp,
213 boolean leakDetection, ResumptionController resumptionController,
214 Map.Entry<SslContextOption<?>, Object>... ctxOptions)
215 throws SSLException {
216 super(startTls, resumptionController);
217
218 OpenSsl.ensureAvailability();
219
220 if (enableOcsp && !OpenSsl.isOcspSupported()) {
221 throw new IllegalStateException("OCSP is not supported.");
222 }
223
224 if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
225 throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
226 }
227
228 boolean tlsFalseStart = false;
229 boolean useTasks = USE_TASKS;
230 OpenSslPrivateKeyMethod privateKeyMethod = null;
231 OpenSslAsyncPrivateKeyMethod asyncPrivateKeyMethod = null;
232 OpenSslCertificateCompressionConfig certCompressionConfig = null;
233 Integer maxCertificateList = null;
234
235 if (ctxOptions != null) {
236 for (Map.Entry<SslContextOption<?>, Object> ctxOpt : ctxOptions) {
237 SslContextOption<?> option = ctxOpt.getKey();
238
239 if (option == OpenSslContextOption.TLS_FALSE_START) {
240 tlsFalseStart = (Boolean) ctxOpt.getValue();
241 } else if (option == OpenSslContextOption.USE_TASKS) {
242 useTasks = (Boolean) ctxOpt.getValue();
243 } else if (option == OpenSslContextOption.PRIVATE_KEY_METHOD) {
244 privateKeyMethod = (OpenSslPrivateKeyMethod) ctxOpt.getValue();
245 } else if (option == OpenSslContextOption.ASYNC_PRIVATE_KEY_METHOD) {
246 asyncPrivateKeyMethod = (OpenSslAsyncPrivateKeyMethod) ctxOpt.getValue();
247 } else if (option == OpenSslContextOption.CERTIFICATE_COMPRESSION_ALGORITHMS) {
248 certCompressionConfig = (OpenSslCertificateCompressionConfig) ctxOpt.getValue();
249 } else if (option == OpenSslContextOption.MAX_CERTIFICATE_LIST_BYTES) {
250 maxCertificateList = (Integer) ctxOpt.getValue();
251 } else {
252 logger.debug("Skipping unsupported " + SslContextOption.class.getSimpleName()
253 + ": " + ctxOpt.getKey());
254 }
255 }
256 }
257 if (privateKeyMethod != null && asyncPrivateKeyMethod != null) {
258 throw new IllegalArgumentException("You can either only use "
259 + OpenSslAsyncPrivateKeyMethod.class.getSimpleName() + " or "
260 + OpenSslPrivateKeyMethod.class.getSimpleName());
261 }
262
263 this.tlsFalseStart = tlsFalseStart;
264
265 leak = leakDetection ? leakDetector.track(this) : null;
266 this.mode = mode;
267 this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
268 this.protocols = protocols == null ? OpenSsl.defaultProtocols(mode == SSL.SSL_MODE_CLIENT) : protocols;
269 this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
270 this.enableOcsp = enableOcsp;
271
272 this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
273
274 String[] suites = checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
275 ciphers, DEFAULT_CIPHERS, availableJavaCipherSuites());
276
277 LinkedHashSet<String> suitesSet = new LinkedHashSet<String>(suites.length);
278 Collections.addAll(suitesSet, suites);
279 unmodifiableCiphers = new ArrayList<String>(suitesSet);
280
281 this.apn = checkNotNull(apn, "apn");
282
283
284 boolean success = false;
285 try {
286 boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
287 boolean anyTlsv13Ciphers = false;
288 try {
289 int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 |
290 SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
291 if (tlsv13Supported) {
292 protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3;
293 }
294 ctx = SSLContext.make(protocolOpts, mode);
295 } catch (Exception e) {
296 throw new SSLException("failed to create an SSL_CTX", e);
297 }
298
299 StringBuilder cipherBuilder = new StringBuilder();
300 StringBuilder cipherTLSv13Builder = new StringBuilder();
301
302
303 try {
304 if (unmodifiableCiphers.isEmpty()) {
305
306 SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, false);
307 if (tlsv13Supported) {
308
309 SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, true);
310 }
311 } else {
312 CipherSuiteConverter.convertToCipherStrings(
313 unmodifiableCiphers, cipherBuilder, cipherTLSv13Builder, OpenSsl.isBoringSSL());
314
315
316 SSLContext.setCipherSuite(ctx, cipherBuilder.toString(), false);
317 if (tlsv13Supported) {
318
319 String tlsv13Ciphers = OpenSsl.checkTls13Ciphers(logger, cipherTLSv13Builder.toString());
320 SSLContext.setCipherSuite(ctx, tlsv13Ciphers, true);
321 if (!tlsv13Ciphers.isEmpty()) {
322 anyTlsv13Ciphers = true;
323 }
324 }
325 }
326 } catch (SSLException e) {
327 throw e;
328 } catch (Exception e) {
329 throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
330 }
331
332 int options = SSLContext.getOptions(ctx) |
333 SSL.SSL_OP_NO_SSLv2 |
334 SSL.SSL_OP_NO_SSLv3 |
335
336
337
338 SSL.SSL_OP_NO_TLSv1 |
339 SSL.SSL_OP_NO_TLSv1_1 |
340
341 SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
342
343
344 SSL.SSL_OP_NO_COMPRESSION |
345
346
347
348
349
350 SSL.SSL_OP_NO_TICKET;
351
352 if (cipherBuilder.length() == 0) {
353
354 options |= SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1
355 | SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2;
356 }
357
358 if (!tlsv13Supported) {
359
360
361
362 options |= SSL.SSL_OP_NO_TLSv1_3;
363 }
364
365 hasTLSv13Cipher = anyTlsv13Ciphers;
366 SSLContext.setOptions(ctx, options);
367
368
369
370
371 SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
372
373 if (DH_KEY_LENGTH != null) {
374 SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
375 }
376
377 List<String> nextProtoList = apn.protocols();
378
379 if (!nextProtoList.isEmpty()) {
380 String[] appProtocols = nextProtoList.toArray(EmptyArrays.EMPTY_STRINGS);
381 int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
382
383 switch (apn.protocol()) {
384 case NPN:
385 SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
386 break;
387 case ALPN:
388 SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
389 break;
390 case NPN_AND_ALPN:
391 SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
392 SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
393 break;
394 default:
395 throw new Error();
396 }
397 }
398
399 if (enableOcsp) {
400 SSLContext.enableOcsp(ctx, isClient());
401 }
402
403 SSLContext.setUseTasks(ctx, useTasks);
404 if (privateKeyMethod != null) {
405 SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, privateKeyMethod));
406 }
407 if (asyncPrivateKeyMethod != null) {
408 SSLContext.setPrivateKeyMethod(ctx, new AsyncPrivateKeyMethod(engineMap, asyncPrivateKeyMethod));
409 }
410 if (certCompressionConfig != null) {
411 for (OpenSslCertificateCompressionConfig.AlgorithmConfig configPair : certCompressionConfig) {
412 final CertificateCompressionAlgo algo = new CompressionAlgorithm(engineMap, configPair.algorithm());
413 switch (configPair.mode()) {
414 case Decompress:
415 SSLContext.addCertificateCompressionAlgorithm(
416 ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_DECOMPRESS, algo);
417 break;
418 case Compress:
419 SSLContext.addCertificateCompressionAlgorithm(
420 ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_COMPRESS, algo);
421 break;
422 case Both:
423 SSLContext.addCertificateCompressionAlgorithm(
424 ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_BOTH, algo);
425 break;
426 default:
427 throw new IllegalStateException();
428 }
429 }
430 }
431 if (maxCertificateList != null) {
432 SSLContext.setMaxCertList(ctx, maxCertificateList);
433 }
434
435 SSLContext.setCurvesList(ctx, OpenSsl.NAMED_GROUPS);
436 success = true;
437 } finally {
438 if (!success) {
439 release();
440 }
441 }
442 }
443
444 private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) {
445 switch (behavior) {
446 case NO_ADVERTISE:
447 return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
448 case CHOOSE_MY_LAST_PROTOCOL:
449 return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
450 default:
451 throw new Error();
452 }
453 }
454
455 @Override
456 public final List<String> cipherSuites() {
457 return unmodifiableCiphers;
458 }
459
460 @Override
461 public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
462 return apn;
463 }
464
465 @Override
466 public final boolean isClient() {
467 return mode == SSL.SSL_MODE_CLIENT;
468 }
469
470 @Override
471 public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
472 return newEngine0(alloc, peerHost, peerPort, true);
473 }
474
475 @Override
476 protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
477 return new SslHandler(newEngine0(alloc, null, -1, false), startTls, ImmediateExecutor.INSTANCE,
478 resumptionController);
479 }
480
481 @Override
482 protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
483 return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls, ImmediateExecutor.INSTANCE,
484 resumptionController);
485 }
486
487 @Override
488 protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
489 return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor, resumptionController);
490 }
491
492 @Override
493 protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
494 boolean startTls, Executor executor) {
495 return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), false, executor, resumptionController);
496 }
497
498 SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
499 return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode, true,
500 endpointIdentificationAlgorithm);
501 }
502
503
504
505
506 @Override
507 public final SSLEngine newEngine(ByteBufAllocator alloc) {
508 return newEngine(alloc, null, -1);
509 }
510
511
512
513
514
515
516
517
518 @Deprecated
519 public final long context() {
520 return sslCtxPointer();
521 }
522
523
524
525
526
527
528 @Deprecated
529 public final OpenSslSessionStats stats() {
530 return sessionContext().stats();
531 }
532
533
534
535
536
537
538 @Deprecated
539 public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
540 if (!rejectRemoteInitiatedRenegotiation) {
541 throw new UnsupportedOperationException("Renegotiation is not supported");
542 }
543 }
544
545
546
547
548
549 @Deprecated
550 public boolean getRejectRemoteInitiatedRenegotiation() {
551 return true;
552 }
553
554
555
556
557
558 public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
559 this.bioNonApplicationBufferSize =
560 checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize");
561 }
562
563
564
565
566 public int getBioNonApplicationBufferSize() {
567 return bioNonApplicationBufferSize;
568 }
569
570
571
572
573
574
575 @Deprecated
576 public final void setTicketKeys(byte[] keys) {
577 sessionContext().setTicketKeys(keys);
578 }
579
580 @Override
581 public abstract OpenSslSessionContext sessionContext();
582
583
584
585
586
587
588
589
590 @Deprecated
591 public final long sslCtxPointer() {
592 Lock readerLock = ctxLock.readLock();
593 readerLock.lock();
594 try {
595 return SSLContext.getSslCtx(ctx);
596 } finally {
597 readerLock.unlock();
598 }
599 }
600
601
602
603
604
605
606
607
608
609
610
611 @Deprecated
612 @UnstableApi
613 public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) {
614 checkNotNull(method, "method");
615 Lock writerLock = ctxLock.writeLock();
616 writerLock.lock();
617 try {
618 SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, method));
619 } finally {
620 writerLock.unlock();
621 }
622 }
623
624
625
626
627
628 @Deprecated
629 public final void setUseTasks(boolean useTasks) {
630 Lock writerLock = ctxLock.writeLock();
631 writerLock.lock();
632 try {
633 SSLContext.setUseTasks(ctx, useTasks);
634 } finally {
635 writerLock.unlock();
636 }
637 }
638
639
640
641
642 private void destroy() {
643 Lock writerLock = ctxLock.writeLock();
644 writerLock.lock();
645 try {
646 if (ctx != 0) {
647 if (enableOcsp) {
648 SSLContext.disableOcsp(ctx);
649 }
650
651 SSLContext.free(ctx);
652 ctx = 0;
653
654 OpenSslSessionContext context = sessionContext();
655 if (context != null) {
656 context.destroy();
657 }
658 }
659 } finally {
660 writerLock.unlock();
661 }
662 }
663
664 protected static X509Certificate[] certificates(byte[][] chain) {
665 X509Certificate[] peerCerts = new X509Certificate[chain.length];
666 for (int i = 0; i < peerCerts.length; i++) {
667 peerCerts[i] = new LazyX509Certificate(chain[i]);
668 }
669 return peerCerts;
670 }
671
672
673
674
675 @Deprecated
676 protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
677 return chooseTrustManager(managers, null);
678 }
679
680 static X509TrustManager chooseTrustManager(TrustManager[] managers,
681 ResumptionController resumptionController) {
682 for (TrustManager m : managers) {
683 if (m instanceof X509TrustManager) {
684 X509TrustManager tm = (X509TrustManager) m;
685 if (resumptionController != null) {
686 tm = (X509TrustManager) resumptionController.wrapIfNeeded(tm);
687 }
688 tm = OpenSslX509TrustManagerWrapper.wrapIfNeeded((X509TrustManager) m);
689 if (useExtendedTrustManager(tm)) {
690
691
692 tm = new EnhancingX509ExtendedTrustManager(tm);
693 }
694 return tm;
695 }
696 }
697 throw new IllegalStateException("no X509TrustManager found");
698 }
699
700 protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
701 for (KeyManager km : kms) {
702 if (km instanceof X509KeyManager) {
703 return (X509KeyManager) km;
704 }
705 }
706 throw new IllegalStateException("no X509KeyManager found");
707 }
708
709
710
711
712
713
714
715
716 @SuppressWarnings("deprecation")
717 static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
718 if (config == null) {
719 return NONE_PROTOCOL_NEGOTIATOR;
720 }
721
722 switch (config.protocol()) {
723 case NONE:
724 return NONE_PROTOCOL_NEGOTIATOR;
725 case ALPN:
726 case NPN:
727 case NPN_AND_ALPN:
728 switch (config.selectedListenerFailureBehavior()) {
729 case CHOOSE_MY_LAST_PROTOCOL:
730 case ACCEPT:
731 switch (config.selectorFailureBehavior()) {
732 case CHOOSE_MY_LAST_PROTOCOL:
733 case NO_ADVERTISE:
734 return new OpenSslDefaultApplicationProtocolNegotiator(
735 config);
736 default:
737 throw new UnsupportedOperationException(
738 new StringBuilder("OpenSSL provider does not support ")
739 .append(config.selectorFailureBehavior())
740 .append(" behavior").toString());
741 }
742 default:
743 throw new UnsupportedOperationException(
744 new StringBuilder("OpenSSL provider does not support ")
745 .append(config.selectedListenerFailureBehavior())
746 .append(" behavior").toString());
747 }
748 default:
749 throw new Error();
750 }
751 }
752
753 static boolean useExtendedTrustManager(X509TrustManager trustManager) {
754 return trustManager instanceof X509ExtendedTrustManager;
755 }
756
757 @Override
758 public final int refCnt() {
759 return refCnt.refCnt();
760 }
761
762 @Override
763 public final ReferenceCounted retain() {
764 refCnt.retain();
765 return this;
766 }
767
768 @Override
769 public final ReferenceCounted retain(int increment) {
770 refCnt.retain(increment);
771 return this;
772 }
773
774 @Override
775 public final ReferenceCounted touch() {
776 refCnt.touch();
777 return this;
778 }
779
780 @Override
781 public final ReferenceCounted touch(Object hint) {
782 refCnt.touch(hint);
783 return this;
784 }
785
786 @Override
787 public final boolean release() {
788 return refCnt.release();
789 }
790
791 @Override
792 public final boolean release(int decrement) {
793 return refCnt.release(decrement);
794 }
795
796 abstract static class AbstractCertificateVerifier extends CertificateVerifier {
797 private final OpenSslEngineMap engineMap;
798
799 AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
800 this.engineMap = engineMap;
801 }
802
803 @Override
804 public final int verify(long ssl, byte[][] chain, String auth) {
805 final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
806 if (engine == null) {
807
808 return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
809 }
810 X509Certificate[] peerCerts = certificates(chain);
811 try {
812 verify(engine, peerCerts, auth);
813 return CertificateVerifier.X509_V_OK;
814 } catch (Throwable cause) {
815 logger.debug("verification of certificate failed", cause);
816 engine.initHandshakeException(cause);
817
818
819 if (cause instanceof OpenSslCertificateException) {
820
821
822 return ((OpenSslCertificateException) cause).errorCode();
823 }
824 if (cause instanceof CertificateExpiredException) {
825 return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
826 }
827 if (cause instanceof CertificateNotYetValidException) {
828 return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
829 }
830 return translateToError(cause);
831 }
832 }
833
834 private static int translateToError(Throwable cause) {
835 if (cause instanceof CertificateRevokedException) {
836 return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
837 }
838
839
840
841
842 Throwable wrapped = cause.getCause();
843 while (wrapped != null) {
844 if (wrapped instanceof CertPathValidatorException) {
845 CertPathValidatorException ex = (CertPathValidatorException) wrapped;
846 CertPathValidatorException.Reason reason = ex.getReason();
847 if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
848 return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
849 }
850 if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
851 return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
852 }
853 if (reason == CertPathValidatorException.BasicReason.REVOKED) {
854 return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
855 }
856 }
857 wrapped = wrapped.getCause();
858 }
859 return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
860 }
861
862 abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
863 String auth) throws Exception;
864 }
865
866 private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
867 private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
868
869 @Override
870 public ReferenceCountedOpenSslEngine remove(long ssl) {
871 return engines.remove(ssl);
872 }
873
874 @Override
875 public void add(ReferenceCountedOpenSslEngine engine) {
876 engines.put(engine.sslPointer(), engine);
877 }
878
879 @Override
880 public ReferenceCountedOpenSslEngine get(long ssl) {
881 return engines.get(ssl);
882 }
883 }
884
885 static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
886 throws SSLException {
887
888 long keyBio = 0;
889 long keyCertChainBio = 0;
890 long keyCertChainBio2 = 0;
891 PemEncoded encoded = null;
892 try {
893
894 encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain);
895 keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
896 keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
897
898 if (key != null) {
899 keyBio = toBIO(ByteBufAllocator.DEFAULT, key);
900 }
901
902 SSLContext.setCertificateBio(
903 ctx, keyCertChainBio, keyBio,
904 keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
905
906 SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
907 } catch (SSLException e) {
908 throw e;
909 } catch (Exception e) {
910 throw new SSLException("failed to set certificate and key", e);
911 } finally {
912 freeBio(keyBio);
913 freeBio(keyCertChainBio);
914 freeBio(keyCertChainBio2);
915 if (encoded != null) {
916 encoded.release();
917 }
918 }
919 }
920
921 static void freeBio(long bio) {
922 if (bio != 0) {
923 SSL.freeBIO(bio);
924 }
925 }
926
927
928
929
930
931 static long toBIO(ByteBufAllocator allocator, PrivateKey key) throws Exception {
932 if (key == null) {
933 return 0;
934 }
935
936 PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
937 try {
938 return toBIO(allocator, pem.retain());
939 } finally {
940 pem.release();
941 }
942 }
943
944
945
946
947
948 static long toBIO(ByteBufAllocator allocator, X509Certificate... certChain) throws Exception {
949 if (certChain == null) {
950 return 0;
951 }
952
953 checkNonEmpty(certChain, "certChain");
954
955 PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
956 try {
957 return toBIO(allocator, pem.retain());
958 } finally {
959 pem.release();
960 }
961 }
962
963 static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
964 try {
965
966
967 ByteBuf content = pem.content();
968
969 if (content.isDirect()) {
970 return newBIO(content.retainedSlice());
971 }
972
973 ByteBuf buffer = allocator.directBuffer(content.readableBytes());
974 try {
975 buffer.writeBytes(content, content.readerIndex(), content.readableBytes());
976 return newBIO(buffer.retainedSlice());
977 } finally {
978 try {
979
980
981 if (pem.isSensitive()) {
982 SslUtils.zeroout(buffer);
983 }
984 } finally {
985 buffer.release();
986 }
987 }
988 } finally {
989 pem.release();
990 }
991 }
992
993 private static long newBIO(ByteBuf buffer) throws Exception {
994 try {
995 long bio = SSL.newMemBIO();
996 int readable = buffer.readableBytes();
997 if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) {
998 SSL.freeBIO(bio);
999 throw new IllegalStateException("Could not write data to memory BIO");
1000 }
1001 return bio;
1002 } finally {
1003 buffer.release();
1004 }
1005 }
1006
1007
1008
1009
1010
1011
1012 static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String password) {
1013 if (factory instanceof OpenSslX509KeyManagerFactory) {
1014 return ((OpenSslX509KeyManagerFactory) factory).newProvider();
1015 }
1016
1017 if (factory instanceof OpenSslCachingX509KeyManagerFactory) {
1018
1019 return ((OpenSslCachingX509KeyManagerFactory) factory).newProvider(password);
1020 }
1021
1022 return new OpenSslKeyMaterialProvider(chooseX509KeyManager(factory.getKeyManagers()), password);
1023 }
1024
1025 private static ReferenceCountedOpenSslEngine retrieveEngine(OpenSslEngineMap engineMap, long ssl)
1026 throws SSLException {
1027 ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
1028 if (engine == null) {
1029 throw new SSLException("Could not find a " +
1030 StringUtil.simpleClassName(ReferenceCountedOpenSslEngine.class) + " for sslPointer " + ssl);
1031 }
1032 return engine;
1033 }
1034
1035 private static final class PrivateKeyMethod implements SSLPrivateKeyMethod {
1036
1037 private final OpenSslEngineMap engineMap;
1038 private final OpenSslPrivateKeyMethod keyMethod;
1039 PrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslPrivateKeyMethod keyMethod) {
1040 this.engineMap = engineMap;
1041 this.keyMethod = keyMethod;
1042 }
1043
1044 @Override
1045 public byte[] sign(long ssl, int signatureAlgorithm, byte[] digest) throws Exception {
1046 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1047 try {
1048 return verifyResult(keyMethod.sign(engine, signatureAlgorithm, digest));
1049 } catch (Exception e) {
1050 engine.initHandshakeException(e);
1051 throw e;
1052 }
1053 }
1054
1055 @Override
1056 public byte[] decrypt(long ssl, byte[] input) throws Exception {
1057 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1058 try {
1059 return verifyResult(keyMethod.decrypt(engine, input));
1060 } catch (Exception e) {
1061 engine.initHandshakeException(e);
1062 throw e;
1063 }
1064 }
1065 }
1066
1067 private static final class AsyncPrivateKeyMethod implements AsyncSSLPrivateKeyMethod {
1068
1069 private final OpenSslEngineMap engineMap;
1070 private final OpenSslAsyncPrivateKeyMethod keyMethod;
1071
1072 AsyncPrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslAsyncPrivateKeyMethod keyMethod) {
1073 this.engineMap = engineMap;
1074 this.keyMethod = keyMethod;
1075 }
1076
1077 @Override
1078 public void sign(long ssl, int signatureAlgorithm, byte[] bytes, ResultCallback<byte[]> resultCallback) {
1079 try {
1080 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1081 keyMethod.sign(engine, signatureAlgorithm, bytes)
1082 .addListener(new ResultCallbackListener(engine, ssl, resultCallback));
1083 } catch (SSLException e) {
1084 resultCallback.onError(ssl, e);
1085 }
1086 }
1087
1088 @Override
1089 public void decrypt(long ssl, byte[] bytes, ResultCallback<byte[]> resultCallback) {
1090 try {
1091 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1092 keyMethod.decrypt(engine, bytes)
1093 .addListener(new ResultCallbackListener(engine, ssl, resultCallback));
1094 } catch (SSLException e) {
1095 resultCallback.onError(ssl, e);
1096 }
1097 }
1098
1099 private static final class ResultCallbackListener implements FutureListener<byte[]> {
1100 private final ReferenceCountedOpenSslEngine engine;
1101 private final long ssl;
1102 private final ResultCallback<byte[]> resultCallback;
1103
1104 ResultCallbackListener(ReferenceCountedOpenSslEngine engine, long ssl,
1105 ResultCallback<byte[]> resultCallback) {
1106 this.engine = engine;
1107 this.ssl = ssl;
1108 this.resultCallback = resultCallback;
1109 }
1110
1111 @Override
1112 public void operationComplete(Future<byte[]> future) {
1113 Throwable cause = future.cause();
1114 if (cause == null) {
1115 try {
1116 byte[] result = verifyResult(future.getNow());
1117 resultCallback.onSuccess(ssl, result);
1118 return;
1119 } catch (SignatureException e) {
1120 cause = e;
1121 engine.initHandshakeException(e);
1122 }
1123 }
1124 resultCallback.onError(ssl, cause);
1125 }
1126 }
1127 }
1128
1129 private static byte[] verifyResult(byte[] result) throws SignatureException {
1130 if (result == null) {
1131 throw new SignatureException();
1132 }
1133 return result;
1134 }
1135
1136 private static final class CompressionAlgorithm implements CertificateCompressionAlgo {
1137 private final OpenSslEngineMap engineMap;
1138 private final OpenSslCertificateCompressionAlgorithm compressionAlgorithm;
1139
1140 CompressionAlgorithm(OpenSslEngineMap engineMap, OpenSslCertificateCompressionAlgorithm compressionAlgorithm) {
1141 this.engineMap = engineMap;
1142 this.compressionAlgorithm = compressionAlgorithm;
1143 }
1144
1145 @Override
1146 public byte[] compress(long ssl, byte[] bytes) throws Exception {
1147 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1148 return compressionAlgorithm.compress(engine, bytes);
1149 }
1150
1151 @Override
1152 public byte[] decompress(long ssl, int len, byte[] bytes) throws Exception {
1153 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1154 return compressionAlgorithm.decompress(engine, len, bytes);
1155 }
1156
1157 @Override
1158 public int algorithmId() {
1159 return compressionAlgorithm.algorithmId();
1160 }
1161 }
1162 }