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