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