diff options
Diffstat (limited to 'src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java')
-rw-r--r-- | src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java | 243 |
1 files changed, 167 insertions, 76 deletions
diff --git a/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java b/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java index b0c4bdc8..37ec889c 100644 --- a/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java +++ b/src/main/java/org/bouncycastle/crypto/tls/DTLSRecordLayer.java @@ -2,7 +2,9 @@ package org.bouncycastle.crypto.tls; import java.io.IOException;
-class DTLSRecordLayer implements DatagramTransport {
+class DTLSRecordLayer
+ implements DatagramTransport
+{
private static final int RECORD_HEADER_LENGTH = 13;
private static final int MAX_FRAGMENT_LENGTH = 1 << 14;
@@ -26,7 +28,8 @@ class DTLSRecordLayer implements DatagramTransport { private DTLSEpoch retransmitEpoch = null;
private long retransmitExpiry = 0;
- DTLSRecordLayer(DatagramTransport transport, TlsContext context, TlsPeer peer, short contentType) {
+ DTLSRecordLayer(DatagramTransport transport, TlsContext context, TlsPeer peer, short contentType)
+ {
this.transport = transport;
this.context = context;
this.peer = peer;
@@ -39,12 +42,15 @@ class DTLSRecordLayer implements DatagramTransport { this.writeEpoch = currentEpoch;
}
- ProtocolVersion getDiscoveredPeerVersion() {
+ ProtocolVersion getDiscoveredPeerVersion()
+ {
return discoveredPeerVersion;
}
- void initPendingEpoch(TlsCipher pendingCipher) {
- if (pendingEpoch != null) {
+ void initPendingEpoch(TlsCipher pendingCipher)
+ {
+ if (pendingEpoch != null)
+ {
throw new IllegalStateException();
}
@@ -58,13 +64,16 @@ class DTLSRecordLayer implements DatagramTransport { this.pendingEpoch = new DTLSEpoch(writeEpoch.getEpoch() + 1, pendingCipher);
}
- void handshakeSuccessful(DTLSHandshakeRetransmit retransmit) {
- if (readEpoch == currentEpoch || writeEpoch == currentEpoch) {
+ void handshakeSuccessful(DTLSHandshakeRetransmit retransmit)
+ {
+ if (readEpoch == currentEpoch || writeEpoch == currentEpoch)
+ {
// TODO
throw new IllegalStateException();
}
- if (retransmit != null) {
+ if (retransmit != null)
+ {
this.retransmit = retransmit;
this.retransmitEpoch = currentEpoch;
this.retransmitExpiry = System.currentTimeMillis() + RETRANSMIT_TIMEOUT;
@@ -75,57 +84,75 @@ class DTLSRecordLayer implements DatagramTransport { this.pendingEpoch = null;
}
- void resetWriteEpoch() {
- if (retransmitEpoch != null) {
+ void resetWriteEpoch()
+ {
+ if (retransmitEpoch != null)
+ {
this.writeEpoch = retransmitEpoch;
- } else {
+ }
+ else
+ {
this.writeEpoch = currentEpoch;
}
}
- public int getReceiveLimit() throws IOException {
+ public int getReceiveLimit()
+ throws IOException
+ {
return Math.min(MAX_FRAGMENT_LENGTH,
readEpoch.getCipher().getPlaintextLimit(transport.getReceiveLimit() - RECORD_HEADER_LENGTH));
}
- public int getSendLimit() throws IOException {
+ public int getSendLimit()
+ throws IOException
+ {
return Math.min(MAX_FRAGMENT_LENGTH,
writeEpoch.getCipher().getPlaintextLimit(transport.getSendLimit() - RECORD_HEADER_LENGTH));
}
- public int receive(byte[] buf, int off, int len, int waitMillis) throws IOException {
+ public int receive(byte[] buf, int off, int len, int waitMillis)
+ throws IOException
+ {
byte[] record = null;
- for (;;) {
+ for (; ; )
+ {
int receiveLimit = Math.min(len, getReceiveLimit()) + RECORD_HEADER_LENGTH;
- if (record == null || record.length < receiveLimit) {
+ if (record == null || record.length < receiveLimit)
+ {
record = new byte[receiveLimit];
}
- try {
- if (retransmit != null && System.currentTimeMillis() > retransmitExpiry) {
+ try
+ {
+ if (retransmit != null && System.currentTimeMillis() > retransmitExpiry)
+ {
retransmit = null;
retransmitEpoch = null;
}
int received = receiveRecord(record, 0, receiveLimit, waitMillis);
- if (received < 0) {
+ if (received < 0)
+ {
return received;
}
- if (received < RECORD_HEADER_LENGTH) {
+ if (received < RECORD_HEADER_LENGTH)
+ {
continue;
}
int length = TlsUtils.readUint16(record, 11);
- if (received != (length + RECORD_HEADER_LENGTH)) {
+ if (received != (length + RECORD_HEADER_LENGTH))
+ {
continue;
}
short type = TlsUtils.readUint8(record, 0);
// TODO Support user-specified custom protocols?
- switch (type) {
+ switch (type)
+ {
case ContentType.alert:
case ContentType.application_data:
case ContentType.change_cipher_spec:
@@ -139,23 +166,32 @@ class DTLSRecordLayer implements DatagramTransport { int epoch = TlsUtils.readUint16(record, 3);
DTLSEpoch recordEpoch = null;
- if (epoch == readEpoch.getEpoch()) {
+ if (epoch == readEpoch.getEpoch())
+ {
recordEpoch = readEpoch;
- } else if (type == ContentType.handshake && retransmitEpoch != null
- && epoch == retransmitEpoch.getEpoch()) {
+ }
+ else if (type == ContentType.handshake && retransmitEpoch != null
+ && epoch == retransmitEpoch.getEpoch())
+ {
recordEpoch = retransmitEpoch;
}
if (recordEpoch == null)
+ {
continue;
+ }
long seq = TlsUtils.readUint48(record, 5);
if (recordEpoch.getReplayWindow().shouldDiscard(seq))
+ {
continue;
+ }
ProtocolVersion version = TlsUtils.readVersion(record, 1);
if (discoveredPeerVersion != null && !discoveredPeerVersion.equals(version))
+ {
continue;
+ }
byte[] plaintext = recordEpoch.getCipher().decodeCiphertext(
getMacSequenceNumber(recordEpoch.getEpoch(), seq), type, record, RECORD_HEADER_LENGTH,
@@ -163,58 +199,74 @@ class DTLSRecordLayer implements DatagramTransport { recordEpoch.getReplayWindow().reportAuthenticated(seq);
- if (discoveredPeerVersion == null) {
+ if (discoveredPeerVersion == null)
+ {
discoveredPeerVersion = version;
}
- switch (type) {
- case ContentType.alert: {
+ switch (type)
+ {
+ case ContentType.alert:
+ {
- if (plaintext.length == 2) {
+ if (plaintext.length == 2)
+ {
short alertLevel = plaintext[0];
short alertDescription = plaintext[1];
peer.notifyAlertReceived(alertLevel, alertDescription);
- if (alertLevel == AlertLevel.fatal) {
+ if (alertLevel == AlertLevel.fatal)
+ {
fail(alertDescription);
throw new TlsFatalAlert(alertDescription);
}
// TODO Can close_notify be a fatal alert?
- if (alertDescription == AlertDescription.close_notify) {
+ if (alertDescription == AlertDescription.close_notify)
+ {
closeTransport();
}
- } else {
+ }
+ else
+ {
// TODO What exception?
}
continue;
}
- case ContentType.application_data: {
- if (inHandshake) {
+ case ContentType.application_data:
+ {
+ if (inHandshake)
+ {
// TODO Consider buffering application data for new epoch that arrives
// out-of-order with the Finished message
continue;
}
break;
}
- case ContentType.change_cipher_spec: {
+ case ContentType.change_cipher_spec:
+ {
// Implicitly receive change_cipher_spec and change to pending cipher state
- if (plaintext.length != 1 || plaintext[0] != 1) {
+ if (plaintext.length != 1 || plaintext[0] != 1)
+ {
continue;
}
- if (pendingEpoch != null) {
+ if (pendingEpoch != null)
+ {
readEpoch = pendingEpoch;
}
continue;
}
- case ContentType.handshake: {
- if (!inHandshake) {
- if (retransmit != null) {
+ case ContentType.handshake:
+ {
+ if (!inHandshake)
+ {
+ if (retransmit != null)
+ {
retransmit.receivedHandshakeRecord(epoch, plaintext, 0, plaintext.length);
}
@@ -228,40 +280,50 @@ class DTLSRecordLayer implements DatagramTransport { * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
* received our final flight.
*/
- if (!inHandshake && retransmit != null) {
+ if (!inHandshake && retransmit != null)
+ {
this.retransmit = null;
this.retransmitEpoch = null;
}
System.arraycopy(plaintext, 0, buf, off, plaintext.length);
return plaintext.length;
- } catch (IOException e) {
+ }
+ catch (IOException e)
+ {
// NOTE: Assume this is a timeout for the moment
throw e;
}
}
}
- public void send(byte[] buf, int off, int len) throws IOException {
+ public void send(byte[] buf, int off, int len)
+ throws IOException
+ {
short contentType = ContentType.application_data;
- if (this.inHandshake || this.writeEpoch == this.retransmitEpoch) {
+ if (this.inHandshake || this.writeEpoch == this.retransmitEpoch)
+ {
contentType = ContentType.handshake;
short handshakeType = TlsUtils.readUint8(buf, off);
- if (handshakeType == HandshakeType.finished) {
-
+ if (handshakeType == HandshakeType.finished)
+ {
+
DTLSEpoch nextEpoch = null;
- if (this.inHandshake) {
+ if (this.inHandshake)
+ {
nextEpoch = pendingEpoch;
}
- else if (this.writeEpoch == this.retransmitEpoch) {
+ else if (this.writeEpoch == this.retransmitEpoch)
+ {
nextEpoch = currentEpoch;
}
- if (nextEpoch == null) {
+ if (nextEpoch == null)
+ {
// TODO
throw new IllegalStateException();
}
@@ -269,7 +331,7 @@ class DTLSRecordLayer implements DatagramTransport { // Implicitly send change_cipher_spec and change to pending cipher state
// TODO Send change_cipher_spec and finished records in single datagram?
- byte[] data = new byte[] { 1 };
+ byte[] data = new byte[]{1};
sendRecord(ContentType.change_cipher_spec, data, 0, data.length);
writeEpoch = nextEpoch;
@@ -279,20 +341,29 @@ class DTLSRecordLayer implements DatagramTransport { sendRecord(contentType, buf, off, len);
}
- public void close() throws IOException {
- if (!closed) {
- if (inHandshake) {
+ public void close()
+ throws IOException
+ {
+ if (!closed)
+ {
+ if (inHandshake)
+ {
warn(AlertDescription.user_canceled, "User canceled handshake");
}
closeTransport();
}
}
- void fail(short alertDescription) {
- if (!closed) {
- try {
+ void fail(short alertDescription)
+ {
+ if (!closed)
+ {
+ try
+ {
raiseAlert(AlertLevel.fatal, alertDescription, null, null);
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
// Ignore
}
@@ -302,12 +373,16 @@ class DTLSRecordLayer implements DatagramTransport { }
}
- void warn(short alertDescription, String message) throws IOException {
+ void warn(short alertDescription, String message)
+ throws IOException
+ {
raiseAlert(AlertLevel.warning, alertDescription, message, null);
}
- private void closeTransport() {
- if (!closed) {
+ private void closeTransport()
+ {
+ if (!closed)
+ {
/*
* RFC 5246 7.2.1. Unless some other fatal alert has been transmitted, each party is
* required to send a close_notify alert before closing the write side of the
@@ -315,12 +390,16 @@ class DTLSRecordLayer implements DatagramTransport { * close down the connection immediately, discarding any pending writes.
*/
- try {
- if (!failed) {
+ try
+ {
+ if (!failed)
+ {
warn(AlertDescription.close_notify, null);
}
transport.close();
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
// Ignore
}
@@ -329,21 +408,26 @@ class DTLSRecordLayer implements DatagramTransport { }
private void raiseAlert(short alertLevel, short alertDescription, String message, Exception cause)
- throws IOException {
+ throws IOException
+ {
peer.notifyAlertRaised(alertLevel, alertDescription, message, cause);
byte[] error = new byte[2];
- error[0] = (byte) alertLevel;
- error[1] = (byte) alertDescription;
+ error[0] = (byte)alertLevel;
+ error[1] = (byte)alertDescription;
sendRecord(ContentType.alert, error, 0, 2);
}
- private int receiveRecord(byte[] buf, int off, int len, int waitMillis) throws IOException {
- if (recordQueue.size() > 0) {
+ private int receiveRecord(byte[] buf, int off, int len, int waitMillis)
+ throws IOException
+ {
+ if (recordQueue.size() > 0)
+ {
int length = 0;
- if (recordQueue.size() >= RECORD_HEADER_LENGTH) {
+ if (recordQueue.size() >= RECORD_HEADER_LENGTH)
+ {
byte[] lengthBytes = new byte[2];
recordQueue.read(lengthBytes, 0, 2, 11);
length = TlsUtils.readUint16(lengthBytes, 0);
@@ -356,10 +440,12 @@ class DTLSRecordLayer implements DatagramTransport { }
int received = transport.receive(buf, off, len, waitMillis);
- if (received >= RECORD_HEADER_LENGTH) {
+ if (received >= RECORD_HEADER_LENGTH)
+ {
int fragmentLength = TlsUtils.readUint16(buf, off + 11);
int recordLength = RECORD_HEADER_LENGTH + fragmentLength;
- if (received > recordLength) {
+ if (received > recordLength)
+ {
recordQueue.addData(buf, off + recordLength, received - recordLength);
received = recordLength;
}
@@ -368,13 +454,16 @@ class DTLSRecordLayer implements DatagramTransport { return received;
}
- private void sendRecord(short contentType, byte[] buf, int off, int len) throws IOException {
+ private void sendRecord(short contentType, byte[] buf, int off, int len)
+ throws IOException
+ {
/*
* RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
* or ChangeCipherSpec content types.
*/
- if (len < 1 && contentType != ContentType.application_data) {
+ if (len < 1 && contentType != ContentType.application_data)
+ {
throw new TlsFatalAlert(AlertDescription.internal_error);
}
@@ -384,7 +473,8 @@ class DTLSRecordLayer implements DatagramTransport { byte[] ciphertext = writeEpoch.getCipher().encodePlaintext(
getMacSequenceNumber(recordEpoch, recordSequenceNumber), contentType, buf, off, len);
- if (ciphertext.length > MAX_FRAGMENT_LENGTH) {
+ if (ciphertext.length > MAX_FRAGMENT_LENGTH)
+ {
throw new TlsFatalAlert(AlertDescription.internal_error);
}
@@ -400,7 +490,8 @@ class DTLSRecordLayer implements DatagramTransport { transport.send(record, 0, record.length);
}
- private static long getMacSequenceNumber(int epoch, long sequence_number) {
- return ((long) epoch << 48) | sequence_number;
+ private static long getMacSequenceNumber(int epoch, long sequence_number)
+ {
+ return ((long)epoch << 48) | sequence_number;
}
}
|