View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package org.jboss.netty.handler.ssl;
18  
19  import org.eclipse.jetty.npn.NextProtoNego;
20  import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
21  import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
22  
23  import javax.net.ssl.SSLEngine;
24  import javax.net.ssl.SSLEngineResult;
25  import javax.net.ssl.SSLEngineResult.HandshakeStatus;
26  import javax.net.ssl.SSLException;
27  import javax.net.ssl.SSLParameters;
28  import javax.net.ssl.SSLSession;
29  import java.nio.ByteBuffer;
30  import java.util.List;
31  
32  final class JettyNpnSslEngine extends SSLEngine {
33  
34      private static boolean available;
35  
36      static boolean isAvailable() {
37          updateAvailability();
38          return available;
39      }
40  
41      private static void updateAvailability() {
42          if (available) {
43              return;
44          }
45          try {
46              // Try to get the bootstrap class loader.
47              ClassLoader bootloader = ClassLoader.getSystemClassLoader().getParent();
48              if (bootloader == null) {
49                  // If failed, use the system class loader,
50                  // although it's not perfect to tell if NPN extension has been loaded.
51                  bootloader = ClassLoader.getSystemClassLoader();
52              }
53              Class.forName("sun.security.ssl.NextProtoNegoExtension", true, bootloader);
54              available = true;
55          } catch (Exception ignore) {
56              // npn-boot was not loaded.
57          }
58      }
59  
60      private final SSLEngine engine;
61      private final JettyNpnSslSession session;
62  
63      JettyNpnSslEngine(SSLEngine engine, final List<String> nextProtocols, boolean server) {
64          assert !nextProtocols.isEmpty();
65  
66          this.engine = engine;
67          session = new JettyNpnSslSession(engine);
68  
69          if (server) {
70              NextProtoNego.put(engine, new ServerProvider() {
71                  public void unsupported() {
72                      getSession().setApplicationProtocol(nextProtocols.get(nextProtocols.size() - 1));
73                  }
74  
75                  public List<String> protocols() {
76                      return nextProtocols;
77                  }
78  
79                  public void protocolSelected(String protocol) {
80                      getSession().setApplicationProtocol(protocol);
81                  }
82              });
83          } else {
84              final String[] list = nextProtocols.toArray(new String[nextProtocols.size()]);
85              final String fallback = list[list.length - 1];
86  
87              NextProtoNego.put(engine, new ClientProvider() {
88                  public boolean supports() {
89                      return true;
90                  }
91  
92                  public void unsupported() {
93                      session.setApplicationProtocol(null);
94                  }
95  
96                  public String selectProtocol(List<String> protocols) {
97                      for (String p: list) {
98                          if (protocols.contains(p)) {
99                              return p;
100                         }
101                     }
102                     return fallback;
103                 }
104             });
105         }
106     }
107 
108     @Override
109     public JettyNpnSslSession getSession() {
110         return session;
111     }
112 
113     @Override
114     public void closeInbound() throws SSLException {
115         NextProtoNego.remove(engine);
116         engine.closeInbound();
117     }
118 
119     @Override
120     public void closeOutbound() {
121         NextProtoNego.remove(engine);
122         engine.closeOutbound();
123     }
124 
125     @Override
126     public String getPeerHost() {
127         return engine.getPeerHost();
128     }
129 
130     @Override
131     public int getPeerPort() {
132         return engine.getPeerPort();
133     }
134 
135     @Override
136     public SSLEngineResult wrap(ByteBuffer byteBuffer, ByteBuffer byteBuffer2) throws SSLException {
137         return engine.wrap(byteBuffer, byteBuffer2);
138     }
139 
140     @Override
141     public SSLEngineResult wrap(ByteBuffer[] byteBuffers, ByteBuffer byteBuffer) throws SSLException {
142         return engine.wrap(byteBuffers, byteBuffer);
143     }
144 
145     @Override
146     public SSLEngineResult wrap(ByteBuffer[] byteBuffers, int i, int i2, ByteBuffer byteBuffer) throws SSLException {
147         return engine.wrap(byteBuffers, i, i2, byteBuffer);
148     }
149 
150     @Override
151     public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer byteBuffer2) throws SSLException {
152         return engine.unwrap(byteBuffer, byteBuffer2);
153     }
154 
155     @Override
156     public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers) throws SSLException {
157         return engine.unwrap(byteBuffer, byteBuffers);
158     }
159 
160     @Override
161     public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers, int i, int i2) throws SSLException {
162         return engine.unwrap(byteBuffer, byteBuffers, i, i2);
163     }
164 
165     @Override
166     public Runnable getDelegatedTask() {
167         return engine.getDelegatedTask();
168     }
169 
170     @Override
171     public boolean isInboundDone() {
172         return engine.isInboundDone();
173     }
174 
175     @Override
176     public boolean isOutboundDone() {
177         return engine.isOutboundDone();
178     }
179 
180     @Override
181     public String[] getSupportedCipherSuites() {
182         return engine.getSupportedCipherSuites();
183     }
184 
185     @Override
186     public String[] getEnabledCipherSuites() {
187         return engine.getEnabledCipherSuites();
188     }
189 
190     @Override
191     public void setEnabledCipherSuites(String[] strings) {
192         engine.setEnabledCipherSuites(strings);
193     }
194 
195     @Override
196     public String[] getSupportedProtocols() {
197         return engine.getSupportedProtocols();
198     }
199 
200     @Override
201     public String[] getEnabledProtocols() {
202         return engine.getEnabledProtocols();
203     }
204 
205     @Override
206     public void setEnabledProtocols(String[] strings) {
207         engine.setEnabledProtocols(strings);
208     }
209 
210     @Override
211     public SSLSession getHandshakeSession() {
212         return engine.getHandshakeSession();
213     }
214 
215     @Override
216     public void beginHandshake() throws SSLException {
217         engine.beginHandshake();
218     }
219 
220     @Override
221     public HandshakeStatus getHandshakeStatus() {
222         return engine.getHandshakeStatus();
223     }
224 
225     @Override
226     public void setUseClientMode(boolean b) {
227         engine.setUseClientMode(b);
228     }
229 
230     @Override
231     public boolean getUseClientMode() {
232         return engine.getUseClientMode();
233     }
234 
235     @Override
236     public void setNeedClientAuth(boolean b) {
237         engine.setNeedClientAuth(b);
238     }
239 
240     @Override
241     public boolean getNeedClientAuth() {
242         return engine.getNeedClientAuth();
243     }
244 
245     @Override
246     public void setWantClientAuth(boolean b) {
247         engine.setWantClientAuth(b);
248     }
249 
250     @Override
251     public boolean getWantClientAuth() {
252         return engine.getWantClientAuth();
253     }
254 
255     @Override
256     public void setEnableSessionCreation(boolean b) {
257         engine.setEnableSessionCreation(b);
258     }
259 
260     @Override
261     public boolean getEnableSessionCreation() {
262         return engine.getEnableSessionCreation();
263     }
264 
265     @Override
266     public SSLParameters getSSLParameters() {
267         return engine.getSSLParameters();
268     }
269 
270     @Override
271     public void setSSLParameters(SSLParameters sslParameters) {
272         engine.setSSLParameters(sslParameters);
273     }
274 }