SSU2: Relay WIP part 14

Fixes after testnet testing:
Fix NPE in OES2 constructor
Fix relay request signature
Fix relay response signature verification bugs
Fix unhandled state OB_STATE_INTRODUCED
Refactor state handling to switch
Remove dup copy in SSU2Util.sign()
Log tweaks
This commit is contained in:
zzz
2022-06-12 12:54:52 -04:00
parent 2ec0894c35
commit 3ef06f88c9
7 changed files with 58 additions and 34 deletions

View File

@@ -1201,21 +1201,28 @@ class EstablishmentManager {
} else {
InboundEstablishState2 state2 = (InboundEstablishState2) state;
InboundEstablishState.InboundState istate = state2.getState();
if (istate == IB_STATE_CREATED_SENT) {
switch (istate) {
case IB_STATE_CREATED_SENT:
if (_log.shouldInfo())
_log.info("Retransmit created to: " + state);
// if already sent, get from the state to retx
pkt = state2.getRetransmitSessionCreatedPacket();
} else if (istate == IB_STATE_REQUEST_RECEIVED) {
break;
case IB_STATE_REQUEST_RECEIVED:
if (_log.shouldDebug())
_log.debug("Send created to: " + state);
pkt = _builder2.buildSessionCreatedPacket(state2);
} else if (istate == IB_STATE_TOKEN_REQUEST_RECEIVED ||
istate == IB_STATE_REQUEST_BAD_TOKEN_RECEIVED) {
break;
case IB_STATE_TOKEN_REQUEST_RECEIVED:
case IB_STATE_REQUEST_BAD_TOKEN_RECEIVED:
if (_log.shouldDebug())
_log.debug("Send retry to: " + state);
pkt = _builder2.buildRetryPacket(state2);
} else {
break;
default:
if (_log.shouldWarn())
_log.warn("Unhandled state " + istate + " on " + state);
return;
@@ -1252,23 +1259,34 @@ class EstablishmentManager {
} else {
OutboundEstablishState2 state2 = (OutboundEstablishState2) state;
OutboundEstablishState.OutboundState ostate = state2.getState();
if (ostate == OB_STATE_REQUEST_SENT ||
ostate == OB_STATE_REQUEST_SENT_NEW_TOKEN) {
switch (ostate) {
case OB_STATE_REQUEST_SENT:
case OB_STATE_REQUEST_SENT_NEW_TOKEN:
if (_log.shouldInfo())
_log.info("Retransmit Session Request to: " + state);
// if already sent, get from the state to retx
packet = state2.getRetransmitSessionRequestPacket();
} else if (ostate == OB_STATE_NEEDS_TOKEN ||
ostate == OB_STATE_TOKEN_REQUEST_SENT) {
break;
case OB_STATE_NEEDS_TOKEN:
case OB_STATE_TOKEN_REQUEST_SENT:
if (_log.shouldDebug())
_log.debug("Send Token Request to: " + state);
packet = _builder2.buildTokenRequestPacket(state2);
} else if (ostate == OB_STATE_UNKNOWN ||
ostate == OB_STATE_RETRY_RECEIVED) {
break;
case OB_STATE_UNKNOWN:
case OB_STATE_RETRY_RECEIVED:
if (_log.shouldDebug())
_log.debug("Send Session Request to: " + state);
packet = _builder2.buildSessionRequestPacket(state2);
} else {
break;
case OB_STATE_INTRODUCED:
handlePendingIntro(state);
return;
default:
if (_log.shouldWarn())
_log.warn("Unhandled state " + ostate + " on " + state);
return;
@@ -1446,7 +1464,7 @@ class EstablishmentManager {
if (ourIP == null)
return;
int ourPort = _transport.getRequestedPort();
byte[] data = SSU2Util.createRelayRequestData(_context, bob.getRemotePeer(), charlie.getRemoteHostId().getPeerHash(),
byte[] data = SSU2Util.createRelayRequestData(_context, bob.getRemotePeer(), charlie.getRemoteIdentity().getHash(),
charlie.getIntroNonce(), tag, ourIP, ourPort,
_context.keyManager().getSigningPrivateKey());
if (data == null) {
@@ -1563,11 +1581,11 @@ class EstablishmentManager {
if (signerRI != null) {
// validate signed data
SigningPublicKey spk = signerRI.getIdentity().getSigningPublicKey();
if (SSU2Util.validateSig(_context, SSU2Util.RELAY_REQUEST_PROLOGUE,
if (SSU2Util.validateSig(_context, SSU2Util.RELAY_RESPONSE_PROLOGUE,
bobHash, null, data, spk)) {
} else {
if (_log.shouldWarn())
_log.warn("Signature failed relay response\n" + signerRI);
_log.warn("Signature failed relay response " + code + " as alice from:\n" + signerRI);
}
} else {
if (_log.shouldWarn())
@@ -2151,7 +2169,7 @@ class EstablishmentManager {
_outboundStates.remove(outboundState.getRemoteHostId(), outboundState);
if (outboundState.getState() != OB_STATE_CONFIRMED_COMPLETELY) {
if (_log.shouldDebug())
_log.debug("Expired: " + outboundState + " Lifetime: " + outboundState.getLifetime());
_log.debug("Expired: " + outboundState);
OutNetMessage msg;
while ((msg = outboundState.getNextQueuedMessage()) != null) {
_transport.failed(msg, "Expired during failed establish");
@@ -2177,6 +2195,8 @@ class EstablishmentManager {
* @since 0.9.2
*/
private void processExpired(InboundEstablishState inboundState) {
if (_log.shouldWarn())
_log.warn("Expired: " + inboundState);
_inboundStates.remove(inboundState.getRemoteHostId());
OutNetMessage msg;
while ((msg = inboundState.getNextQueuedMessage()) != null) {

View File

@@ -484,8 +484,11 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
if (sid != _sendConnID)
throw new GeneralSecurityException("Conn ID mismatch: 1: " + _sendConnID + " 2: " + sid);
long token = DataHelper.fromLong8(data, off + 24);
if (token != _token)
throw new GeneralSecurityException("Token mismatch: 1: " + _token + " 2: " + token);
if (token != _token) {
// most likely a retransmitted session request with the old invalid token
// TODO should we retransmit retry in this case?
throw new GeneralSecurityException("Token mismatch: expected: " + _token + " got: " + token);
}
_handshakeState.start();
_handshakeState.mixHash(data, off, 32);
//if (_log.shouldDebug())
@@ -788,7 +791,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
buf.append(" lifetime: ").append(DataHelper.formatDuration(getLifetime()));
buf.append(" Rcv ID: ").append(_rcvConnID);
buf.append(" Send ID: ").append(_sendConnID);
buf.append(" RelayTag: ").append(_sentRelayTag);
if (_sentRelayTag > 0)
buf.append(" RelayTag: ").append(_sentRelayTag);
buf.append(' ').append(_currentState);
return buf.toString();
}

View File

@@ -825,7 +825,7 @@ class IntroductionManager {
// TODO add timer to remove from _nonceToAlice
} else {
if (_log.shouldWarn())
_log.warn("Signature failed relay intro\n" + aliceRI);
_log.warn("Signature failed relay request\n" + aliceRI);
rcode = SSU2Util.RELAY_REJECT_BOB_SIGFAIL;
}
} else {
@@ -867,7 +867,7 @@ class IntroductionManager {
return;
}
if (_log.shouldInfo())
_log.info("Send relay response rejection " + rcode + " to " + alice);
_log.info("Send relay response rejection as bob " + rcode + " to alice " + alice);
packet = _builder2.buildRelayResponse(data, alice);
}
_transport.send(packet);
@@ -975,7 +975,7 @@ class IntroductionManager {
}
UDPPacket packet = _builder2.buildRelayResponse(data, bob);
if (_log.shouldDebug())
_log.debug("Send relay response " + " nonce " + nonce + " to " + bob);
_log.debug("Send relay response " + rcode + " as charlie " + " nonce " + nonce + " to bob " + bob);
_transport.send(packet);
if (rcode == SSU2Util.RELAY_ACCEPT) {
// send hole punch with the same data we sent to Bob
@@ -1030,11 +1030,11 @@ class IntroductionManager {
else
signedData = data;
SigningPublicKey spk = charlie.getIdentity().getSigningPublicKey();
if (SSU2Util.validateSig(_context, SSU2Util.RELAY_REQUEST_PROLOGUE,
_context.routerHash(), null, data, spk)) {
if (SSU2Util.validateSig(_context, SSU2Util.RELAY_RESPONSE_PROLOGUE,
_context.routerHash(), null, signedData, spk)) {
} else {
if (_log.shouldWarn())
_log.warn("Signature failed relay response\n" + charlie);
_log.warn("Signature failed relay response as bob from charlie:\n" + charlie);
}
} else {
if (_log.shouldWarn())
@@ -1047,12 +1047,12 @@ class IntroductionManager {
System.arraycopy(data, 0, idata, 2, data.length);
UDPPacket packet = _builder2.buildRelayResponse(idata, alice);
if (_log.shouldDebug())
_log.debug("Send relay response " + " nonce " + nonce + " to " + alice);
_log.debug("Got relay response " + status + " as bob, forward " + " nonce " + nonce + " to " + alice);
_transport.send(packet);
} else {
// We are Alice, give to EstablishmentManager to check sig and process
if (_log.shouldDebug())
_log.debug("Got relay response " + " nonce " + nonce + " from " + peer);
_log.debug("Got relay response " + status + " as alice " + " nonce " + nonce + " from " + peer);
_transport.getEstablisher().receiveRelayResponse(peer, nonce, status, data);
}
}

View File

@@ -771,7 +771,7 @@ class OutboundEstablishState {
/** @since 0.8.9 */
@Override
public String toString() {
return "OES " + _remoteHostId +
return "OES " + _remotePeer.getHash().toBase64().substring(0, 6) + ' ' + _remoteHostId +
" lifetime: " + DataHelper.formatDuration(getLifetime()) +
' ' + _currentState;
}

View File

@@ -94,7 +94,7 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
if (ra.getTransportStyle().equals(UDPTransport.STYLE2)) {
mtu = PeerState2.DEFAULT_MTU;
} else {
if (_bobIP.length == 16)
if (_bobIP != null && _bobIP.length == 16)
mtu = PeerState2.DEFAULT_SSU_IPV6_MTU;
else
mtu = PeerState2.DEFAULT_SSU_IPV4_MTU;
@@ -104,7 +104,7 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
if (ra.getTransportStyle().equals(UDPTransport.STYLE2)) {
mtu = Math.min(Math.max(mtu, PeerState2.MIN_MTU), PeerState2.MAX_MTU);
} else {
if (_bobIP.length == 16)
if (_bobIP != null && _bobIP.length == 16)
mtu = Math.min(Math.max(mtu, PeerState2.MIN_SSU_IPV6_MTU), PeerState2.MAX_SSU_IPV6_MTU);
else
mtu = Math.min(Math.max(mtu, PeerState2.MIN_SSU_IPV4_MTU), PeerState2.MAX_SSU_IPV4_MTU);
@@ -559,7 +559,7 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
@Override
public String toString() {
return "OES2 " + _remoteHostId +
return "OES2 " + _remotePeer.getHash().toBase64().substring(0, 6) + ' ' + _remoteHostId +
" lifetime: " + DataHelper.formatDuration(getLifetime()) +
" Rcv ID: " + _rcvConnID +
" Send ID: " + _sendConnID +

View File

@@ -577,8 +577,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
// IllegalArgumentException, buggy ack block, let the other blocks get processed
if (_log.shouldWarn())
_log.warn("Bad ACK block\n" + SSU2Bitfield.toString(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0)) +
"\nAck through " + ackThru + " acks " + acks + (ranges != null ? "\n" + HexDump.dump(ranges) : "") +
"\nfrom " + this, e);
"\nAck through " + ackThru + " acnt " + acks + (ranges != null ? "Ranges:\n" + HexDump.dump(ranges) : "") +
"from " + this, e);
}
}

View File

@@ -304,7 +304,6 @@ final class SSU2Util {
byte[] buf = new byte[len];
System.arraycopy(prologue, 0, buf, 0, prologue.length);
System.arraycopy(h.getData(), 0, buf, prologue.length, Hash.HASH_LENGTH);
System.arraycopy(h.getData(), 0, buf, prologue.length, Hash.HASH_LENGTH);
int off = prologue.length + Hash.HASH_LENGTH;
if (h2 != null) {
System.arraycopy(h2.getData(), 0, buf, off, Hash.HASH_LENGTH);
@@ -320,6 +319,7 @@ final class SSU2Util {
* and then the provided data which ends with a signature of the specified type.
*
* @param h2 may be null
* @param data not including relay response token
*/
public static boolean validateSig(I2PAppContext ctx, byte[] prologue, Hash h, Hash h2, byte[] data, SigningPublicKey spk) {
SigType type = spk.getType();