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