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