1 19 20 package com.maverick.ssl; 21 22 import java.io.ByteArrayOutputStream ; 23 import java.io.DataInputStream ; 24 import java.io.DataOutputStream ; 25 import java.io.EOFException ; 26 import java.io.IOException ; 27 import java.io.InputStream ; 28 import java.io.InterruptedIOException ; 29 import java.io.OutputStream ; 30 import java.text.MessageFormat ; 31 32 import com.maverick.crypto.asn1.x509.X509Certificate; 33 34 38 public class SSLTransportImpl implements SSLTransport { 39 40 public static final int VERSION_MAJOR = 3; 41 public static final int VERSION_MINOR = 0; 42 43 static final int WARNING_ALERT = 1; 44 static final int FATAL_ALERT = 2; 45 46 final static int CHANGE_CIPHER_SPEC_MSG = 20; 47 final static int ALERT_PROTOCOL = 21; 48 final static int APPLICATION_DATA = 23; 49 50 SSLInputStream sslIn = new SSLInputStream(); 51 SSLOutputStream sslOut = new SSLOutputStream(); 52 53 SSLHandshakeProtocol handshake = null; 54 SSLContext context; 55 56 public String debug = "Standard transport"; 58 DataInputStream rawIn; 59 DataOutputStream rawOut; 60 61 long incomingSequence = 0; 62 long outgoingSequence = 0; 63 64 SSLCipherSuite writeCipherSuite = null; 65 SSLCipherSuite readCipherSuite = null; 66 67 org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(SSLSocket.class); 69 70 72 public SSLTransportImpl() { 73 } 74 75 public SSLContext getContext() { 76 return context; 77 } 78 79 82 public X509Certificate getCertificate(){ 83 return handshake.getCertificate(); 84 } 85 86 89 public void initialize(InputStream in, OutputStream out) throws IOException , SSLException { 90 initialize(in, out, null); 91 } 92 93 public void initialize(InputStream in, OutputStream out, SSLContext context) throws IOException , SSLException { 94 95 this.rawIn = new DataInputStream (in); 96 this.rawOut = new DataOutputStream (out); 97 writeCipherSuite = readCipherSuite = new SSL_NULL_WITH_NULL_NULL(); 98 99 log.debug(Messages.getString("SSLTransport.initialising")); 103 if (context == null) 104 context = new SSLContext(); 105 106 handshake = new SSLHandshakeProtocol(this, context); 107 108 handshake.startHandshake(); 110 111 while (!handshake.isComplete()) { 113 processMessages(); 114 115 log.debug(Messages.getString("SSLTransport.initCompleteStartingAppProtocol")); } 119 } 120 121 void processMessages() throws SSLException, EOFException { 122 123 int type = 0; 124 byte[] fragment = null; 125 try { 126 type = rawIn.read(); 127 int major = rawIn.read(); 128 int minor = rawIn.read(); 129 130 int length = rawIn.readShort(); 131 132 fragment = new byte[length]; 133 134 rawIn.readFully(fragment); 135 136 readCipherSuite.decrypt(fragment, 0, fragment.length); 137 138 if (readCipherSuite.getMACLength() > 0) { 139 if (!readCipherSuite.verifyMAC(fragment, 140 0, 141 fragment.length - readCipherSuite.getMACLength(), 142 type, 143 incomingSequence, 144 fragment, 145 fragment.length - readCipherSuite.getMACLength(), 146 readCipherSuite.getMACLength())) { 147 throw new SSLException(SSLException.PROTOCOL_VIOLATION, Messages.getString("SSLTransport.invalidMAC")); } 149 150 } 151 } catch (EOFException ex) { 152 throw ex; 153 } catch (InterruptedIOException ex) { 154 throw new SSLException(SSLException.READ_TIMEOUT); 155 } catch (IOException ex) { 156 throw new SSLException(SSLException.UNEXPECTED_TERMINATION, ex.getMessage() == null ? ex.getClass().getName() 157 : ex.getMessage()); 158 } 159 160 incomingSequence++; 161 162 log.debug(MessageFormat.format(Messages.getString("SSLTransport.processingFragmentOfType"), new Object [] { new Integer (type) })); 166 switch (type) { 167 case SSLHandshakeProtocol.HANDSHAKE_PROTOCOL_MSG: 168 handshake.processMessage(fragment, 0, fragment.length - readCipherSuite.getMACLength()); 169 break; 170 case CHANGE_CIPHER_SPEC_MSG: 171 172 174 log.debug(Messages.getString("SSLTransport.changingInputCipherSpec")); 177 readCipherSuite = handshake.getPendingCipherSuite(); 178 incomingSequence = 0; 179 break; 180 case ALERT_PROTOCOL: 181 switch (fragment[0]) { 182 case FATAL_ALERT: 183 throw new SSLException(((int) (fragment[1] & 0xFF))); 184 case WARNING_ALERT: 185 switch (fragment[1]) { 186 case SSLException.CLOSE_NOTIFY: 187 188 log.debug(Messages.getString("SSLTransport.remoteSideClosing")); 192 sendMessage(ALERT_PROTOCOL, new byte[] { (byte) WARNING_ALERT, (byte) SSLException.CLOSE_NOTIFY }); 193 throw new EOFException (); 196 197 default: 198 199 log.warn(SSLException.getDescription(fragment[1])); 201 203 break; 204 } 205 206 break; 207 default: 208 209 log.debug(MessageFormat.format(Messages.getString("SSLTransport.unexpectedAlert"), new Object [] { new Integer (fragment[0]), new Integer (fragment[1]) })); 213 break; 214 } 215 case APPLICATION_DATA: 216 sslIn.write(fragment, 0, fragment.length - readCipherSuite.getMACLength()); 217 break; 218 default: 219 throw new SSLException(SSLException.PROTOCOL_VIOLATION, 220 Messages.getString("SSLTransport.unexpecedSSLProtocolType") + type); 222 } 223 224 } 225 226 229 public void close() throws SSLException { 230 sendMessage(ALERT_PROTOCOL, new byte[] { WARNING_ALERT, SSLException.CLOSE_NOTIFY }); 231 } 232 233 void sendMessage(int type, byte[] fragment) throws SSLException { 234 sendMessage(type, fragment, 0, fragment.length); 235 } 236 237 void sendMessage(int type, byte[] fragment, int off, int len) throws SSLException { 238 239 byte[] encrypted; 242 if (writeCipherSuite.getMACLength() > 0) { 244 byte[] mac = writeCipherSuite.generateMAC(fragment, off, len, type, outgoingSequence); 245 encrypted = new byte[len + mac.length]; 247 System.arraycopy(fragment, off, encrypted, 0, len); 248 System.arraycopy(mac, 0, encrypted, len, mac.length); 249 250 writeCipherSuite.encrypt(encrypted, 0, encrypted.length); 252 } else { 253 if (off > 0 || fragment.length != len) { 254 encrypted = new byte[len]; 255 System.arraycopy(fragment, off, encrypted, 0, len); 256 } else { 257 encrypted = fragment; 258 } 259 } 260 261 ByteArrayOutputStream record = new ByteArrayOutputStream (); 263 264 try { 265 record.write(type); 266 record.write(SSLTransportImpl.VERSION_MAJOR); 267 record.write(SSLTransportImpl.VERSION_MINOR); 268 record.write((encrypted.length >> 8) & 0xFF); 269 record.write(encrypted.length); 270 record.write(encrypted); 271 } catch (IOException ex) { 272 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 273 } 274 275 try { 276 rawOut.write(record.toByteArray()); 278 } catch (IOException ex) { 279 throw new SSLException(SSLException.UNEXPECTED_TERMINATION, ex.getMessage() == null ? ex.getClass().getName() 280 : ex.getMessage()); 281 } 282 283 outgoingSequence++; 285 } 286 287 void sendCipherChangeSpec(SSLCipherSuite pendingCipherSuite) throws SSLException { 288 289 log.debug(Messages.getString("SSLTransport.changingOutputCipherSpec")); 293 sendMessage(CHANGE_CIPHER_SPEC_MSG, new byte[] { 1 }); 294 writeCipherSuite = pendingCipherSuite; 295 outgoingSequence = 0; 296 } 297 298 301 public InputStream getInputStream() throws IOException { 302 return sslIn; 303 } 304 305 308 public OutputStream getOutputStream() throws IOException { 309 return sslOut; 310 } 311 312 class SSLOutputStream extends OutputStream { 313 public synchronized void write(int b) throws IOException { 314 log.debug(Messages.getString("SSLTransport.sending1Byte")); try { 318 sendMessage(APPLICATION_DATA, new byte[] { (byte) b }); 319 } catch (SSLException ex) { 320 throw new SSLIOException(ex); 321 } 322 } 323 324 public synchronized void write(byte[] b, int off, int len) throws IOException { 325 log.debug(MessageFormat.format(Messages.getString("SSLTransport.bytesToSend"), new Object [] { new Integer (len) })); 329 try { 330 int pos = 0; 331 while (pos < len) { 332 log.debug(MessageFormat.format(Messages.getString("SSLTransport.sendingBlock"), new Object [] { new Integer ((len - pos) < 16384 ? len - pos : 16384) })); sendMessage(APPLICATION_DATA, b, off + pos, ((len - pos) < 16384 ? len - pos : 16384)); 336 pos += (len < 16384 ? len : 16384); 337 } 338 } catch (SSLException ex) { 339 throw new SSLIOException(ex); 340 } 341 } 342 } 343 344 class SSLInputStream extends InputStream { 345 346 byte[] buffer; 347 int unread = 0; 348 int position = 0; 349 int base = 0; 350 boolean isEOF = false; 351 352 SSLInputStream() { 353 buffer = new byte[16384]; 354 } 355 356 public int available() { 357 return unread; 358 } 359 360 public int read() throws IOException { 361 byte[] b = new byte[1]; 362 int ret = read(b, 0, 1); 363 if (ret > 0) { 364 return b[0] & 0xFF; 365 } else { 366 return -1; 367 } 368 } 369 370 long transfered = 0; 371 372 public int read(byte[] buf, int offset, int len) throws IOException { 373 374 try { 375 376 while (unread <= 0 && !isEOF) { 377 processMessages(); 378 } 379 380 int count = unread < len ? unread : len; 381 int index = base; 382 base = (base + count) % buffer.length; 383 if (buffer.length - index > count) { 384 System.arraycopy(buffer, index, buf, offset, count); 385 } else { 386 int remaining = buffer.length - index; 387 System.arraycopy(buffer, index, buf, offset, remaining); 388 System.arraycopy(buffer, 0, buf, offset + remaining, count - remaining); 389 } 390 391 unread -= count; 392 393 return count; 394 } catch (EOFException ex) { 395 return -1; 396 } catch (SSLException ex) { 397 throw new SSLIOException(ex); 398 } 399 400 } 401 402 void write(byte[] buf, int offset, int len) { 403 404 for (int i = offset; i < offset + len; i++) { 405 int index = (base + unread) % buffer.length; 407 buffer[index] = buf[i]; 408 unread++; 409 } 410 411 } 412 } 413 414 } 415 | Popular Tags |