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