forked from I2P_Developers/i2p.i2p
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:
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 +
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user