Skip to content

Commit 989cdcc

Browse files
committed
Merge branch 'main' of gitlab.cryptoworkshop.com:root/bc-java
2 parents ec2f3f0 + 976c3a0 commit 989cdcc

1 file changed

Lines changed: 41 additions & 72 deletions

File tree

tls/src/main/java/org/bouncycastle/tls/DTLSReassembler.java

Lines changed: 41 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@
55
class DTLSReassembler
66
{
77
/*
8-
* Bounds the number of gaps tracked for one message. Each interior fragment splits a gap in two,
9-
* so an unbounded list lets single-byte fragments at alternating offsets take a 32KiB message to
10-
* 16K gaps, at a cost quadratic in the message length - seconds of CPU per message_seq in the
11-
* flight, spent before anything about the peer has been verified. A cooperating peer fragments
12-
* to the path MTU, so its gap count tracks its fragment count: a 1MiB message in 516-byte
13-
* fragments arriving in fully random order peaks at 536 gaps, hence one gap per 512 bytes with a
14-
* floor for small messages. At the cap a fragment that would split a gap is ignored for that gap
15-
* - and not recorded as received, so a byte already held is still never overwritten - leaving the
16-
* peer's normal retransmission of the flight to complete the message once the gaps close.
8+
* Bounds the number of gaps tracked for one message.
9+
* <p>
10+
* Limits the amount of fragmentation a malicious peer can cause. While at the limit a fragment that would
11+
* split a range is ignored; retransmission is then relied on to complete the message.
1712
*/
18-
private static final int MIN_MAX_MISSING_RANGES = 1024;
13+
private static final int MIN_MISSING_RANGES_LIMIT = 64;
1914

2015
/*
2116
* No 'final' modifiers so that it works in earlier JDKs
@@ -30,7 +25,7 @@ class DTLSReassembler
3025
{
3126
this.msg_type = msg_type;
3227
this.body = new byte[length];
33-
this.maxMissingRanges = Math.max(MIN_MAX_MISSING_RANGES, length / 512);
28+
this.maxMissingRanges = Math.max(MIN_MISSING_RANGES_LIMIT, length / 1024);
3429
this.missing.addElement(new Range(0, length));
3530
}
3631

@@ -54,80 +49,74 @@ void contributeFragment(short msg_type, int length, byte[] buf, int off, int fra
5449
return;
5550
}
5651

52+
// NOTE: Empty messages still require an empty fragment to complete it
5753
if (fragment_length == 0)
5854
{
59-
// NOTE: Empty messages still require an empty fragment to complete it
60-
if (fragment_offset == 0 && !missing.isEmpty())
55+
if (fragment_offset == 0 && !missing.isEmpty() && ((Range)missing.firstElement()).end == 0)
6156
{
62-
Range firstRange = (Range)missing.firstElement();
63-
if (firstRange.getEnd() == 0)
64-
{
65-
missing.removeElementAt(0);
66-
}
57+
missing.removeElementAt(0);
6758
}
6859
return;
6960
}
7061

71-
for (int i = firstCandidate(fragment_offset); i < missing.size(); ++i)
62+
for (int i = findStartIndex(fragment_offset); i < missing.size(); ++i)
7263
{
7364
Range range = (Range)missing.elementAt(i);
74-
if (range.getStart() >= fragment_end)
65+
if (range.start >= fragment_end)
7566
{
7667
break;
7768
}
78-
if (range.getEnd() > fragment_offset)
69+
if (range.end <= fragment_offset)
7970
{
71+
continue;
72+
}
8073

81-
int copyStart = Math.max(range.getStart(), fragment_offset);
82-
int copyEnd = Math.min(range.getEnd(), fragment_end);
83-
int copyLength = copyEnd - copyStart;
74+
int copyStart = Math.max(range.start, fragment_offset);
75+
int copyEnd = Math.min(range.end, fragment_end);
76+
int copyLength = copyEnd - copyStart;
8477

85-
if (copyStart != range.getStart() && copyEnd != range.getEnd()
86-
&& missing.size() >= maxMissingRanges)
78+
if (copyStart == range.start)
79+
{
80+
if (copyEnd == range.end)
8781
{
88-
// splitting this range would pass the cap, so ignore the fragment for it
89-
continue;
82+
// TODO[tls] It should be possible to handle all removals together at the end (linearly)
83+
missing.removeElementAt(i--);
9084
}
91-
92-
System.arraycopy(buf, off + copyStart - fragment_offset, body, copyStart,
93-
copyLength);
94-
95-
if (copyStart == range.getStart())
85+
else
9686
{
97-
if (copyEnd == range.getEnd())
98-
{
99-
missing.removeElementAt(i--);
100-
}
101-
else
102-
{
103-
range.setStart(copyEnd);
104-
}
87+
range.start = copyEnd;
10588
}
106-
else
89+
}
90+
else
91+
{
92+
if (copyEnd != range.end)
10793
{
108-
if (copyEnd != range.getEnd())
94+
// Splitting this range would exceed the limit, so ignore the fragment
95+
if (missing.size() >= maxMissingRanges)
10996
{
110-
missing.insertElementAt(new Range(copyEnd, range.getEnd()), ++i);
97+
continue;
11198
}
112-
range.setEnd(copyStart);
99+
100+
missing.insertElementAt(new Range(copyEnd, range.end), ++i);
113101
}
102+
range.end = copyStart;
114103
}
104+
105+
System.arraycopy(buf, off + copyStart - fragment_offset, body, copyStart, copyLength);
115106
}
116107
}
117108

118109
/**
119-
* Index of the first range that can overlap a fragment starting at fragment_offset. The ranges
120-
* are sorted and disjoint, so every earlier one ends at or below fragment_offset and could only
121-
* be skipped over; searching for the start rather than rescanning from zero is what keeps the
122-
* cost of a fragment independent of how many gaps precede it.
110+
* Find the index of the first range that might overlap a fragment starting at fragment_offset. The ranges are
111+
* sorted and disjoint, so every earlier one ends at or below fragment_offset and could only be skipped over.
123112
*/
124-
private int firstCandidate(int fragment_offset)
113+
private int findStartIndex(int fragment_offset)
125114
{
126115
int lo = 0, hi = missing.size();
127116
while (lo < hi)
128117
{
129118
int mid = (lo + hi) >>> 1;
130-
if (((Range)missing.elementAt(mid)).getEnd() > fragment_offset)
119+
if (((Range)missing.elementAt(mid)).end > fragment_offset)
131120
{
132121
hi = mid;
133122
}
@@ -147,32 +136,12 @@ void reset()
147136

148137
private static class Range
149138
{
150-
private int start, end;
139+
int start, end;
151140

152141
Range(int start, int end)
153142
{
154143
this.start = start;
155144
this.end = end;
156145
}
157-
158-
int getStart()
159-
{
160-
return start;
161-
}
162-
163-
void setStart(int start)
164-
{
165-
this.start = start;
166-
}
167-
168-
int getEnd()
169-
{
170-
return end;
171-
}
172-
173-
void setEnd(int end)
174-
{
175-
this.end = end;
176-
}
177146
}
178147
}

0 commit comments

Comments
 (0)