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