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