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