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