SSU2: Send retry with termination block on clock skew

This commit is contained in:
zzz
2022-07-15 15:03:22 -04:00
parent c2ffcb8512
commit 097fa34e91
3 changed files with 26 additions and 8 deletions

View File

@@ -1246,7 +1246,7 @@ class EstablishmentManager {
case IB_STATE_REQUEST_BAD_TOKEN_RECEIVED:
if (_log.shouldDebug())
_log.debug("Send retry to: " + state);
pkt = _builder2.buildRetryPacket(state2);
pkt = _builder2.buildRetryPacket(state2, 0);
break;
default:

View File

@@ -166,7 +166,9 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
throw new GeneralSecurityException("No DateTime block in Session/Token Request");
_skew = _establishBegin - _timeReceived;
if (_skew > MAX_SKEW || _skew < 0 - MAX_SKEW) {
// TODO send retry with termination
// send retry with termination
UDPPacket retry = _transport.getBuilder2().buildRetryPacket(this, SSU2Util.REASON_SKEW);
_transport.send(retry);
throw new GeneralSecurityException("Skew exceeded in Session/Token Request: " + _skew);
}
packetReceived();
@@ -519,8 +521,12 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
throw new GeneralSecurityException("No DateTime block in Session Request");
// _nextSend is now(), from packetReceived()
_skew = _nextSend - _timeReceived;
if (_skew > MAX_SKEW || _skew < 0 - MAX_SKEW)
if (_skew > MAX_SKEW || _skew < 0 - MAX_SKEW) {
// send another retry with termination
UDPPacket retry = _transport.getBuilder2().buildRetryPacket(this, SSU2Util.REASON_SKEW);
_transport.send(retry);
throw new GeneralSecurityException("Skew exceeded in Session Request: " + _skew);
}
_sendHeaderEncryptKey2 = SSU2Util.hkdf(_context, _handshakeState.getChainingKey(), "SessCreateHeader");
_currentState = InboundState.IB_STATE_REQUEST_RECEIVED;
_rtt = (int) (_nextSend - _lastSend);
@@ -531,6 +537,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
* If the message is fragmented, store the data for reassembly and return,
* unless this was the last one.
*
* Exceptions thrown from here are fatal.
*
* @return the new PeerState2 if are done, may also be retrieved from getPeerState(),
* or null if more fragments to go
*/

View File

@@ -433,12 +433,14 @@ class PacketBuilder2 {
* Build a new Retry packet for the given peer, encrypting it
* as necessary.
*
* @param terminationCode 0 normally, nonzero to send termination block
* @return ready to send packet, or null if there was a problem
*/
public UDPPacket buildRetryPacket(InboundEstablishState2 state) {
public UDPPacket buildRetryPacket(InboundEstablishState2 state, int terminationCode) {
long n = _context.random().signedNextInt() & 0xFFFFFFFFL;
long token = terminationCode == 0 ? state.getToken() : 0;
UDPPacket packet = buildLongPacketHeader(state.getSendConnID(), n, RETRY_FLAG_BYTE,
state.getRcvConnID(), state.getToken());
state.getRcvConnID(), token);
DatagramPacket pkt = packet.getPacket();
byte sentIP[] = state.getSentIP();
@@ -446,7 +448,7 @@ class PacketBuilder2 {
int port = state.getSentPort();
encryptRetry(packet, state.getSendHeaderEncryptKey1(), n, state.getSendHeaderEncryptKey1(),
state.getSendHeaderEncryptKey2(),
sentIP, port);
sentIP, port, terminationCode);
pkt.setSocketAddress(state.getSentAddress());
packet.setMessageType(TYPE_CREAT);
packet.setPriority(PRIORITY_HIGH);
@@ -945,10 +947,18 @@ class PacketBuilder2 {
/**
* @param packet containing only 32 byte header
* @param terminationCode 0 normally, nonzero to send termination block
*/
private void encryptRetry(UDPPacket packet, byte[] chachaKey, long n,
byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port) {
encryptPeerTest(packet, chachaKey, n, hdrKey1, hdrKey2, ip, port, null);
byte[] hdrKey1, byte[] hdrKey2, byte[] ip, int port,
int terminationCode) {
Block block;
if (terminationCode != 0) {
block = new SSU2Payload.TerminationBlock(terminationCode, 0);
} else {
block = null;
}
encryptPeerTest(packet, chachaKey, n, hdrKey1, hdrKey2, ip, port, block);
}
/**