From 8bba4a0365703e06c2e8c1a8664594eaa264e122 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Fri, 12 Jul 2019 12:37:17 +0200 Subject: [PATCH] Update address only for newest tls12_cid records. Fix updates with already deprecated addresses. Signed-off-by: Achim Kraus --- .../californium/scandium/DTLSConnector.java | 6 ++- .../scandium/dtls/DTLSSession.java | 38 +++++++++++-------- .../scandium/dtls/DTLSSessionTest.java | 38 +++++++++++++++++++ 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/scandium-core/src/main/java/org/eclipse/californium/scandium/DTLSConnector.java b/scandium-core/src/main/java/org/eclipse/californium/scandium/DTLSConnector.java index b029197d1f..2d4baa0e07 100644 --- a/scandium-core/src/main/java/org/eclipse/californium/scandium/DTLSConnector.java +++ b/scandium-core/src/main/java/org/eclipse/californium/scandium/DTLSConnector.java @@ -1239,13 +1239,15 @@ private void processApplicationDataRecord(final Record record, final Connection record.setSession(session); ApplicationMessage message = (ApplicationMessage) record.getFragment(); // the fragment could be de-crypted, mark it - session.markRecordAsRead(record.getEpoch(), record.getSequenceNumber()); + boolean updateAddress = session.markRecordAsRead(record.getEpoch(), record.getSequenceNumber()); if (ongoingHandshake != null) { // the handshake has been completed successfully ongoingHandshake.handshakeCompleted(); } connection.refreshAutoResumptionTime(); - connectionStore.update(connection, record.getPeerAddress()); + if (updateAddress) { + connectionStore.update(connection, record.getPeerAddress()); + } final RawDataChannel channel = messageHandler; // finally, forward de-crypted message to application layer diff --git a/scandium-core/src/main/java/org/eclipse/californium/scandium/dtls/DTLSSession.java b/scandium-core/src/main/java/org/eclipse/californium/scandium/dtls/DTLSSession.java index 64cb9c60c1..b5671456df 100644 --- a/scandium-core/src/main/java/org/eclipse/californium/scandium/dtls/DTLSSession.java +++ b/scandium-core/src/main/java/org/eclipse/californium/scandium/dtls/DTLSSession.java @@ -177,7 +177,7 @@ public final class DTLSSession { */ private boolean parameterAvailable = false; - private volatile long receiveWindowUpperBoundary = RECEIVE_WINDOW_SIZE - 1; + private volatile long receiveWindowUpperCurrent = -1; private volatile long receiveWindowLowerBoundary = 0; private volatile long receivedRecordsVector = 0; private long creationTime; @@ -940,7 +940,7 @@ public boolean isRecordProcessable(long epoch, long sequenceNo, boolean useWindo * @return true if the record has already been received */ boolean isDuplicate(long sequenceNo) { - if (sequenceNo > receiveWindowUpperBoundary) { + if (sequenceNo > receiveWindowUpperCurrent) { return false; } else { @@ -959,31 +959,39 @@ boolean isDuplicate(long sequenceNo) { } /** - * Marks a record as having been received so that it can be detected - * as a duplicate if it is received again, e.g. if a client re-transmits - * the record because it runs into a timeout. + * Marks a record as having been received so that it can be detected as a + * duplicate if it is received again, e.g. if a client re-transmits the + * record because it runs into a timeout. * * The record is marked as received only if it belongs to this session's * current read epoch as indicated by {@link #getReadEpoch()}. * * @param epoch the record's epoch * @param sequenceNo the record's sequence number + * @return {@code true}, if the sequenceNo is higher than the current upper + * boundary. {@code false}, if not. */ - public void markRecordAsRead(long epoch, long sequenceNo) { - + public boolean markRecordAsRead(long epoch, long sequenceNo) { if (epoch == getReadEpoch()) { - if (sequenceNo > receiveWindowUpperBoundary) { - long incr = sequenceNo - receiveWindowUpperBoundary; - receiveWindowUpperBoundary = sequenceNo; - // slide receive window to the right - receivedRecordsVector = receivedRecordsVector >>> incr; - receiveWindowLowerBoundary = Math.max(0, receiveWindowUpperBoundary - RECEIVE_WINDOW_SIZE + 1); + boolean newest = sequenceNo > receiveWindowUpperCurrent; + if (newest) { + receiveWindowUpperCurrent = sequenceNo; + long lowerBoundary = Math.max(0, sequenceNo - RECEIVE_WINDOW_SIZE + 1); + long incr = lowerBoundary - receiveWindowLowerBoundary; + if (incr > 0) { + // slide receive window to the right + receivedRecordsVector = receivedRecordsVector >>> incr; + receiveWindowLowerBoundary = lowerBoundary; + } } long bitMask = 1L << (sequenceNo - receiveWindowLowerBoundary); // mark sequence number as "received" in receive window receivedRecordsVector |= bitMask; LOGGER.debug("Updated receive window with sequence number [{}]: new upper boundary [{}], new bit vector [{}]", - sequenceNo, receiveWindowUpperBoundary, Long.toBinaryString(receivedRecordsVector)); + sequenceNo, receiveWindowUpperCurrent, Long.toBinaryString(receivedRecordsVector)); + return newest; + } else { + return epoch > getReadEpoch(); } } @@ -995,7 +1003,7 @@ public void markRecordAsRead(long epoch, long sequenceNo) { */ private void resetReceiveWindow() { receivedRecordsVector = 0; - receiveWindowUpperBoundary = RECEIVE_WINDOW_SIZE - 1; + receiveWindowUpperCurrent = -1; receiveWindowLowerBoundary = 0; } diff --git a/scandium-core/src/test/java/org/eclipse/californium/scandium/dtls/DTLSSessionTest.java b/scandium-core/src/test/java/org/eclipse/californium/scandium/dtls/DTLSSessionTest.java index 00f2c6386e..0a641b08ad 100644 --- a/scandium-core/src/test/java/org/eclipse/californium/scandium/dtls/DTLSSessionTest.java +++ b/scandium-core/src/test/java/org/eclipse/californium/scandium/dtls/DTLSSessionTest.java @@ -167,6 +167,44 @@ public void testEpochSwitchResetsReceiveWindow() { assertTrue(session.isRecordProcessable(session.getReadEpoch(), 2, false)); } + @Test + public void testHigherSequenceNumberIsNewer() { + + int epoch = session.getReadEpoch(); + session.markRecordAsRead(epoch, 0); + assertTrue(session.markRecordAsRead(epoch, 2)); + } + + @Test + public void testLowerSequenceNumberIsNotNewer() { + + int epoch = session.getReadEpoch(); + session.markRecordAsRead(epoch, 2); + assertFalse(session.markRecordAsRead(epoch, 0)); + } + + @Test + public void testSameSequenceNumberIsNotNewer() { + + int epoch = session.getReadEpoch(); + session.markRecordAsRead(epoch, 2); + assertFalse(session.markRecordAsRead(epoch, 2)); + } + + @Test + public void testHigherEpochIsNewer() { + int epoch = session.getReadEpoch(); + session.markRecordAsRead(epoch, 2); + assertTrue(session.markRecordAsRead(epoch + 1, 0)); + } + + @Test + public void testLowerEpochIsNotNewer() { + int epoch = session.getReadEpoch(); + session.markRecordAsRead(epoch, 0); + assertFalse(session.markRecordAsRead(epoch - 1, 2)); + } + @Test public void testConstructorEnforcesMaxSequenceNo() { session = new DTLSSession(PEER_ADDRESS, DtlsTestTools.MAX_SEQUENCE_NO); // should succeed