8268205: Enhance DTLS client handshake

Reviewed-by: jnimeh, ahgross, rhalade
This commit is contained in:
Xue-Lei Andrew Fan 2021-07-08 04:37:39 +00:00 committed by Henry Jen
parent 365a2d428c
commit c714707eac

View File

@ -567,6 +567,9 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
HashMap<Byte, List<HoleDescriptor>> holesMap; HashMap<Byte, List<HoleDescriptor>> holesMap;
// A map used to check duplicated handshake messages.
HashMap<Byte, Integer> messageSeqMap;
HandshakeFlight() { HandshakeFlight() {
this.handshakeType = HF_UNKNOWN; this.handshakeType = HF_UNKNOWN;
this.flightEpoch = 0; this.flightEpoch = 0;
@ -577,6 +580,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
this.maxRecordSeq = -1; this.maxRecordSeq = -1;
this.holesMap = new HashMap<>(5); this.holesMap = new HashMap<>(5);
this.messageSeqMap = new HashMap<>(5);
} }
boolean isRetransmitOf(HandshakeFlight hs) { boolean isRetransmitOf(HandshakeFlight hs) {
@ -598,6 +602,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
hf.maxRecordSeq = this.maxRecordSeq; hf.maxRecordSeq = this.maxRecordSeq;
hf.holesMap = new HashMap<>(this.holesMap); hf.holesMap = new HashMap<>(this.holesMap);
hf.messageSeqMap = new HashMap<>(this.messageSeqMap);
return hf; return hf;
} }
@ -640,7 +645,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
} }
// Queue up a handshake message. // Queue up a handshake message.
void queueUpHandshake(HandshakeFragment hsf) { void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException {
if (!isDesirable(hsf)) { if (!isDesirable(hsf)) {
// Not a dedired record, discard it. // Not a dedired record, discard it.
return; return;
@ -707,6 +712,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
holes.add(new HoleDescriptor(0, hsf.messageLength)); holes.add(new HoleDescriptor(0, hsf.messageLength));
} }
handshakeFlight.holesMap.put(hsf.handshakeType, holes); handshakeFlight.holesMap.put(hsf.handshakeType, holes);
handshakeFlight.messageSeqMap.put(hsf.handshakeType, hsf.messageSeq);
} else if (holes.isEmpty()) { } else if (holes.isEmpty()) {
// Have got the full handshake message. This record may be // Have got the full handshake message. This record may be
// a handshake message retransmission. Discard this record. // a handshake message retransmission. Discard this record.
@ -778,7 +784,8 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
} }
// Queue up a ChangeCipherSpec message // Queue up a ChangeCipherSpec message
void queueUpChangeCipherSpec(RecordFragment rf) { void queueUpChangeCipherSpec(RecordFragment rf)
throws SSLProtocolException {
if (!isDesirable(rf)) { if (!isDesirable(rf)) {
// Not a dedired record, discard it. // Not a dedired record, discard it.
return; return;
@ -807,7 +814,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
// Queue up a ciphertext message. // Queue up a ciphertext message.
// //
// Note: not yet be able to decrypt the message. // Note: not yet be able to decrypt the message.
void queueUpFragment(RecordFragment rf) { void queueUpFragment(RecordFragment rf) throws SSLProtocolException {
if (!isDesirable(rf)) { if (!isDesirable(rf)) {
// Not a dedired record, discard it. // Not a dedired record, discard it.
return; return;
@ -895,7 +902,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
// Is a desired record? // Is a desired record?
// //
// Check for retransmission and lost records. // Check for retransmission and lost records.
private boolean isDesirable(RecordFragment rf) { private boolean isDesirable(RecordFragment rf) throws SSLProtocolException {
// //
// Discard records old than the previous epoch. // Discard records old than the previous epoch.
// //
@ -970,6 +977,25 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
return false; return false;
} }
// Unexpected duplicated handshake messages.
if (rf.recordEpoch == handshakeEpoch &&
// For handshake messages only.
rf instanceof HandshakeFragment hsf &&
// Check on the received handshake messages.
handshakeFlight.holesMap.containsKey(hsf.handshakeType)) {
Integer cachedMsgSeq = handshakeFlight.messageSeqMap.get(
hsf.handshakeType);
if (cachedMsgSeq != null && cachedMsgSeq != hsf.messageSeq) {
// Handshake messages of the same type but with different
// message sequence numbers are not allowed.
throw new SSLProtocolException(
"Two message sequence numbers are used for the "
+ "same handshake message ("
+ SSLHandshake.nameOf(hsf.handshakeType)
+ ")");
}
}
return true; return true;
} }
@ -1086,6 +1112,9 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
// cleanup holes map // cleanup holes map
handshakeFlight.holesMap.clear(); handshakeFlight.holesMap.clear();
// cleanup handshake message sequence numbers map
handshakeFlight.messageSeqMap.clear();
// Ready to accept new input record. // Ready to accept new input record.
flightIsReady = false; flightIsReady = false;
needToCheckFlight = false; needToCheckFlight = false;