1 package com.sslexplorer.boot; 2 3 import java.io.EOFException ; 4 import java.io.FileNotFoundException ; 5 import java.io.IOException ; 6 import java.io.InputStream ; 7 import java.io.OutputStream ; 8 import java.nio.ByteBuffer ; 9 10 import javax.net.ssl.SSLContext; 11 import javax.net.ssl.SSLEngine; 12 import javax.net.ssl.SSLEngineResult; 13 import javax.net.ssl.SSLSession; 14 15 import org.apache.commons.logging.Log; 16 import org.apache.commons.logging.LogFactory; 17 18 import com.maverick.ssl.SSLException; 19 import com.maverick.ssl.SSLTransport; 20 21 23 public class SSLTransportJCE implements SSLTransport { 24 25 private static SSLContext sslContext; 26 private SSLSession session; 27 private SSLEngine engine; 28 private SSLEngineResult.HandshakeStatus hsStatus; 29 private boolean initialHandshake; 30 31 SSLEngineResult res; 32 static Log log = LogFactory.getLog(SSLTransportJCE.class); 33 34 private InputStream rawIn; 35 private OutputStream rawOut; 36 37 byte[] buffer; 38 39 ByteBuffer in_outputData; 40 ByteBuffer in_inputData; 41 ByteBuffer out_outputData; 42 43 InputStream sslIn = new SSLInputStream(); 44 OutputStream sslOut = new SSLOutputStream(); 45 46 47 public InputStream getInputStream() { 48 return sslIn; 49 } 50 51 public OutputStream getOutputStream() { 52 return sslOut; 53 } 54 55 public void initialize(InputStream in, OutputStream out) throws IOException { 56 this.rawIn = in; 57 this.rawOut = out; 58 59 try { 61 engine = getSSLContext().createSSLEngine(); 63 64 engine.setUseClientMode(true); 66 67 session = engine.getSession(); 69 engine.beginHandshake(); 70 hsStatus = engine.getHandshakeStatus(); 71 initialHandshake = true; 72 73 buffer = new byte[session.getPacketBufferSize()]; 76 77 performInitialHandshake(); 78 79 in_outputData = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 80 in_inputData = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 81 out_outputData = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 82 in_outputData.flip(); } catch(Exception ex) { 84 throw new IOException (ex.getMessage()); 85 } 86 } 87 88 private void performInitialHandshake() throws IOException { 89 90 93 ByteBuffer dummy = ByteBuffer.allocate(0); 94 ByteBuffer outputBuffer = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 95 ByteBuffer inputBuffer = ByteBuffer.allocateDirect(session.getPacketBufferSize()); 96 97 while(initialHandshake) { 98 99 switch (hsStatus) { 100 case FINISHED: 101 104 105 if(log.isDebugEnabled()) 106 log.debug("SSL Handshake finished"); 107 initialHandshake = false; 108 return; 109 110 case NEED_TASK: 111 112 115 if(log.isDebugEnabled()) 116 log.debug("Performing SSLEngine task"); 117 118 Runnable task; 120 while ((task = engine.getDelegatedTask()) != null) { 121 task.run(); 122 } 123 hsStatus = engine.getHandshakeStatus(); 124 break; 125 126 case NEED_UNWRAP: 127 128 132 if(log.isDebugEnabled()) 133 log.debug("Reading SSL data from raw InputStream"); 134 135 inputBuffer.flip(); 136 137 if(!inputBuffer.hasRemaining()) { 138 139 inputBuffer.compact(); 140 int read = rawIn.read(buffer); 141 142 if(read==-1) 143 throw new EOFException ("Unexpected EOF whilst waiting for SSL unwrap"); 144 145 inputBuffer.put(buffer, 0, read); 146 inputBuffer.flip(); 147 } 148 149 res = engine.unwrap(inputBuffer, outputBuffer); 150 151 inputBuffer.compact(); 152 153 if(res.getStatus()!=SSLEngineResult.Status.OK) { 154 throw new IOException (res.getStatus().toString()); 155 } 156 157 hsStatus = res.getHandshakeStatus(); 158 159 sendOutput(outputBuffer); 160 break; 161 162 case NEED_WRAP: 163 164 168 169 if(log.isDebugEnabled()) 170 log.debug("Writing SSL data to raw OutputStream"); 171 172 res = engine.wrap(dummy, outputBuffer); 173 174 if(res.getStatus()!=SSLEngineResult.Status.OK) { 175 throw new IOException (res.getStatus().toString()); 176 } 177 178 hsStatus = res.getHandshakeStatus(); 179 180 sendOutput(outputBuffer); 181 182 break; 183 184 case NOT_HANDSHAKING: 185 188 log.error("doHandshake has caught a NOT_HANDSHAKING state.. This is impossible!"); 189 } 190 } 191 } 192 193 private void sendOutput(ByteBuffer outputBuffer) throws IOException { 194 outputBuffer.flip(); 195 196 int remaining = outputBuffer.remaining(); 197 while(remaining > 0) { 198 outputBuffer.get(buffer, 0, remaining); 199 rawOut.write(buffer, 0, remaining); 200 remaining = outputBuffer.remaining(); 201 } 202 203 outputBuffer.compact(); 204 } 205 206 212 private synchronized static SSLContext getSSLContext() throws IOException { 213 if (sslContext != null) { 214 return sslContext; 215 } 216 initializeSSL(); 217 return sslContext; 218 } 219 220 226 public static void initializeSSL() throws FileNotFoundException , IOException { 227 try { 228 sslContext = SSLContext.getInstance("TLS"); 229 sslContext.init(SSLKeyManager.getKeyManagerArray(), SSLTrustManager.getTrustManagerArray(), null); 230 } catch (Exception ex) { 231 throw new IOException ("SSL initialization failed: " + ex.getMessage()); 232 } 233 } 234 235 239 public synchronized static void setSSLContext(SSLContext context) { 240 sslContext = context; 241 } 242 243 class SSLInputStream extends InputStream { 244 245 SSLInputStream() { 246 247 } 248 249 public int read() throws IOException { 250 byte[] b = new byte[1]; 251 if(readData(b,0,1)==1) 252 return (int) b[0]; 253 else 254 return -1; 255 } 256 257 public int read(byte[] buf, int off, int len) throws IOException { 258 return readData(buf, off, len); 259 } 260 261 268 public int readData(byte[] buf, int off, int len) throws IOException { 269 270 try { 271 while(true) { 272 273 if(in_outputData.hasRemaining()) { 274 int actualLen = Math.min(len, in_outputData.remaining()); 275 in_outputData.get(buf, off, actualLen); 276 return actualLen; 277 } 278 279 int read = -1; 280 281 do { 282 283 in_inputData.flip(); 284 285 if(!in_inputData.hasRemaining() || res.getStatus()==SSLEngineResult.Status.BUFFER_UNDERFLOW) { 286 287 in_inputData.compact(); 288 read = rawIn.read(buffer, 0, Math.min(in_inputData.remaining(), buffer.length)); 289 290 if(read==-1) 291 return -1; 292 293 if(read==0) 294 return 0; 295 296 in_inputData.put(buffer,0,read); 297 in_inputData.flip(); 298 } 299 300 in_outputData.compact(); 301 res = engine.unwrap(in_inputData, in_outputData); 302 in_outputData.flip(); 303 in_inputData.compact(); 304 305 } while(res.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW); 306 307 } 308 } catch (IOException e) { 309 if(log.isDebugEnabled()) 310 log.error(e); 311 throw e; 312 } 313 314 } 315 } 316 317 318 class SSLOutputStream extends OutputStream { 319 320 public void write(int b) throws IOException { 321 writeData(new byte[] { (byte)b }, 0, 1); 322 } 323 324 public void write(byte[] buf, int off, int len) throws IOException { 325 writeData(buf, off, len); 326 } 327 328 void writeData(byte[] buf, int off, int len) throws IOException { 329 330 ByteBuffer source = ByteBuffer.wrap(buf, off, len); 331 332 while(source.remaining() > 0) { 333 res = engine.wrap(source, out_outputData); 334 335 out_outputData.flip(); 336 337 int remaining = out_outputData.remaining(); 338 while(remaining > 0) { 339 out_outputData.get(buffer, 0, remaining); 340 rawOut.write(buffer, 0, remaining); 341 remaining = out_outputData.remaining(); 342 } 343 out_outputData.compact(); 344 } 345 } 346 } 347 348 public void close() throws SSLException { 349 350 try { 351 352 if(!engine.isOutboundDone()) 353 engine.closeOutbound(); 354 355 if(engine.isInboundDone()) 356 engine.closeInbound(); 357 358 } catch (Exception e) { 359 } finally { 360 Util.closeStream(rawIn); 361 Util.closeStream(rawOut); 362 } 363 364 } 365 } 366 | Popular Tags |