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