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