package net.jradius.tls; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * An implementation of the TLS 1.0 record layer. */ class RecordStream { private TlsProtocolHandler handler; private InputStream is; private OutputStream os; private CombinedHash hash; private TlsCipher readCipher = null; private TlsCipher writeCipher = null; RecordStream(TlsProtocolHandler handler, InputStream is, OutputStream os) { this.handler = handler; this.is = is; this.os = os; this.hash = new CombinedHash(); this.readCipher = new TlsNullCipher(); this.writeCipher = this.readCipher; } public RecordStream(TlsProtocolHandler handler) { this.handler = handler; this.hash = new CombinedHash(); this.readCipher = new TlsNullCipher(); this.writeCipher = this.readCipher; } void clientCipherSpecDecided(TlsCipher tlsCipher) { this.writeCipher = tlsCipher; } void serverClientSpecReceived() { this.readCipher = this.writeCipher; } public void setInputStream(ByteArrayInputStream stream) { this.is = stream; } public void setOutputStream(ByteArrayOutputStream stream) { this.os = stream; } public void readData() throws IOException { short type = TlsUtils.readUint8(is); TlsUtils.checkVersion(is, handler); int size = TlsUtils.readUint16(is); byte[] buf = decodeAndVerify(type, is, size); handler.processData(type, buf, 0, buf.length); } protected byte[] decodeAndVerify(short type, InputStream is, int len) throws IOException { byte[] buf = new byte[len]; TlsUtils.readFully(buf, is); return readCipher.decodeCiphertext(type, buf, 0, buf.length); } protected void writeMessage(short type, byte[] message, int offset, int len) throws IOException { if (type == 22) // TlsProtocolHandler.RL_HANDSHAKE { updateHandshakeData(message, offset, len); } byte[] ciphertext = writeCipher.encodePlaintext(type, message, offset, len); byte[] writeMessage = new byte[ciphertext.length + 5]; TlsUtils.writeUint8(type, writeMessage, 0); TlsUtils.writeUint8((short)3, writeMessage, 1); TlsUtils.writeUint8((short)1, writeMessage, 2); TlsUtils.writeUint16(ciphertext.length, writeMessage, 3); System.arraycopy(ciphertext, 0, writeMessage, 5, ciphertext.length); os.write(writeMessage); os.flush(); } public boolean hasMore() throws IOException { return (is.available() > 0); } void updateHandshakeData(byte[] message, int offset, int len) { hash.update(message, offset, len); } byte[] getCurrentHash() { return doFinal(new CombinedHash(hash)); } protected void close() throws IOException { IOException e = null; try { is.close(); } catch (IOException ex) { e = ex; } try { os.close(); } catch (IOException ex) { e = ex; } if (e != null) { throw e; } } protected void flush() throws IOException { os.flush(); } private static byte[] doFinal(CombinedHash ch) { byte[] bs = new byte[ch.getDigestSize()]; ch.doFinal(bs, 0); return bs; } }