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