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.util.internal.ObjectUtil;
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.SuppressJava6Requirement;
21
22 import java.net.Socket;
23 import java.security.cert.Certificate;
24 import java.security.cert.CertificateException;
25 import java.security.cert.X509Certificate;
26 import java.util.Collections;
27 import java.util.Set;
28 import java.util.WeakHashMap;
29 import java.util.concurrent.atomic.AtomicReference;
30 import javax.net.ssl.SSLEngine;
31 import javax.net.ssl.SSLPeerUnverifiedException;
32 import javax.net.ssl.TrustManager;
33 import javax.net.ssl.X509ExtendedTrustManager;
34
35 final class ResumptionController {
36 private final Set<SSLEngine> confirmedValidations;
37 private final AtomicReference<ResumableX509ExtendedTrustManager> resumableTm;
38
39 ResumptionController() {
40 confirmedValidations = Collections.synchronizedSet(
41 Collections.newSetFromMap(new WeakHashMap<SSLEngine, Boolean>()));
42 resumableTm = new AtomicReference<ResumableX509ExtendedTrustManager>();
43 }
44
45 @SuppressJava6Requirement(reason = "Guarded by version check")
46 public TrustManager wrapIfNeeded(TrustManager tm) {
47 if (tm instanceof ResumableX509ExtendedTrustManager) {
48 if (PlatformDependent.javaVersion() < 7 || !(tm instanceof X509ExtendedTrustManager)) {
49 throw new IllegalStateException("ResumableX509ExtendedTrustManager implementation must be a " +
50 "subclass of X509ExtendedTrustManager, found: " + (tm == null ? null : tm.getClass()));
51 }
52 if (!resumableTm.compareAndSet(null, (ResumableX509ExtendedTrustManager) tm)) {
53 throw new IllegalStateException(
54 "Only one ResumableX509ExtendedTrustManager can be configured for resumed sessions");
55 }
56 return new X509ExtendedWrapTrustManager((X509ExtendedTrustManager) tm, confirmedValidations);
57 }
58 return tm;
59 }
60
61 public void remove(SSLEngine engine) {
62 if (resumableTm.get() != null) {
63 confirmedValidations.remove(unwrapEngine(engine));
64 }
65 }
66
67 public boolean validateResumeIfNeeded(SSLEngine engine)
68 throws CertificateException, SSLPeerUnverifiedException {
69 ResumableX509ExtendedTrustManager tm;
70 boolean valid = engine.getSession().isValid();
71 if (valid && (tm = resumableTm.get()) != null) {
72 Certificate[] peerCertificates = engine.getSession().getPeerCertificates();
73
74
75 engine = unwrapEngine(engine);
76
77 if (!confirmedValidations.remove(engine)) {
78
79 if (engine.getUseClientMode()) {
80
81 tm.resumeServerTrusted(chainOf(peerCertificates), engine);
82 } else {
83
84 tm.resumeClientTrusted(chainOf(peerCertificates), engine);
85 }
86 return true;
87 }
88 }
89 return false;
90 }
91
92 private static SSLEngine unwrapEngine(SSLEngine engine) {
93 if (engine instanceof JdkSslEngine) {
94 return ((JdkSslEngine) engine).getWrappedEngine();
95 }
96 return engine;
97 }
98
99 private static X509Certificate[] chainOf(Certificate[] peerCertificates) {
100 if (peerCertificates instanceof X509Certificate[]) {
101
102 return (X509Certificate[]) peerCertificates;
103 }
104 X509Certificate[] chain = new X509Certificate[peerCertificates.length];
105 for (int i = 0; i < peerCertificates.length; i++) {
106 Certificate cert = peerCertificates[i];
107 if (cert instanceof X509Certificate || cert == null) {
108 chain[i] = (X509Certificate) cert;
109 } else {
110 throw new IllegalArgumentException("Only X509Certificates are supported, found: " + cert.getClass());
111 }
112 }
113 return chain;
114 }
115
116 @SuppressJava6Requirement(reason = "Guarded by version check")
117 private static final class X509ExtendedWrapTrustManager extends X509ExtendedTrustManager {
118 private final X509ExtendedTrustManager trustManager;
119 private final Set<SSLEngine> confirmedValidations;
120
121 X509ExtendedWrapTrustManager(X509ExtendedTrustManager trustManager, Set<SSLEngine> confirmedValidations) {
122 this.trustManager = trustManager;
123 this.confirmedValidations = confirmedValidations;
124 }
125
126 private static void unsupported() throws CertificateException {
127 throw new CertificateException(
128 new UnsupportedOperationException("Resumable trust managers require the SSLEngine parameter"));
129 }
130
131 @Override
132 public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
133 throws CertificateException {
134 unsupported();
135 }
136
137 @Override
138 public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
139 throws CertificateException {
140 unsupported();
141 }
142
143 @Override
144 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
145 unsupported();
146 }
147
148 @Override
149 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
150 unsupported();
151 }
152
153 @Override
154 public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
155 throws CertificateException {
156 trustManager.checkClientTrusted(chain, authType, engine);
157 confirmedValidations.add(engine);
158 }
159
160 @Override
161 public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
162 throws CertificateException {
163 trustManager.checkServerTrusted(chain, authType, engine);
164 confirmedValidations.add(engine);
165 }
166
167 @Override
168 public X509Certificate[] getAcceptedIssuers() {
169 return trustManager.getAcceptedIssuers();
170 }
171 }
172 }