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