diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java index fdf7f7ee99e18ba4c4fe5439f1ca20f238a747a5..78144891cccd1b0b71818716213e92fe24806d13 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java @@ -249,6 +249,14 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa if (_receivedUnconfirmedIdentity != null) throw new DataFormatException("DUP RI in Sess Conf"); _receivedUnconfirmedIdentity = ri.getIdentity(); + if (ri.getPublished() < 0) { + // see SSU2Payload: RI format error, signature was verified there, so we can take action + _context.blocklist().add(_aliceIP); + Hash h = _receivedUnconfirmedIdentity.calculateHash(); + _context.banlist().banlistRouter(h, "Signed bad RI", null, + null, _context.clock().now() + 4*24*60*60*1000); + throw new RIException("RI DFE " + h.toBase64(), REASON_BANNED); + } // try to find the right address, because we need the MTU boolean isIPv6 = _aliceIP.length == 16; diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState2.java b/router/java/src/net/i2p/router/transport/udp/PeerState2.java index 033b4f4505de24d1f2d72aac1fe5e3dfdff5c35a..91916e8761be2c5cceff00d22dbd0e542324c0c7 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState2.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState2.java @@ -657,6 +657,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback public void gotRI(RouterInfo ri, boolean isHandshake, boolean flood) throws DataFormatException { if (_log.shouldDebug()) _log.debug("Got RI in data phase " + ri + "\non: " + this); + if (ri.getPublished() < 0) + throw new DataFormatException("RI DFE " + ri.getIdentity().calculateHash().toBase64()); try { Hash h = ri.getHash(); if (h.equals(_context.routerHash())) diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java index 797ec709de3c462d2647dce1ebd64a9044b56635..e0d319292ccc1b79c766e5a1f0bdf3e6c0085763 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java @@ -1913,6 +1913,11 @@ class PeerTestManager { public void gotOptions(byte[] options, boolean isHandshake) {} public void gotRI(RouterInfo ri, boolean isHandshake, boolean flood) { + if (ri.getPublished() < 0) { + if (_log.shouldWarn()) + _log.warn("RI DFE " + ri.getIdentity().calculateHash().toBase64()); + return; + } try { Hash h = ri.getHash(); if (h.equals(_context.routerHash())) diff --git a/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java b/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java index cfe0d8416df38638a7edc45058311ca9878684a2..6c37d9f924bd20ced51159fc938fd4c98f562810 100644 --- a/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java +++ b/router/java/src/net/i2p/router/transport/udp/SSU2Payload.java @@ -6,12 +6,17 @@ import java.util.Arrays; import java.util.List; import net.i2p.I2PAppContext; +import net.i2p.crypto.DSAEngine; +import net.i2p.crypto.SigType; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Hash; +import net.i2p.data.Signature; +import net.i2p.data.SigningPublicKey; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.i2np.I2NPMessageException; import net.i2p.data.i2np.I2NPMessageImpl; +import net.i2p.data.router.RouterIdentity; import net.i2p.data.router.RouterInfo; import net.i2p.util.Log; @@ -211,7 +216,36 @@ class SSU2Payload { if (bais.available() >= 3*1024) flood = false; RouterInfo alice = new RouterInfo(); - alice.readBytes(bais, true); + try { + alice.readBytes(bais, true); + } catch (DataFormatException dfe) { + // alternate verify of signature. + // if a badly formatted RI was correctly signed, we do a special callback + bais.reset(); + RouterIdentity ident = new RouterIdentity(); + ident.readBytes(bais); + SigningPublicKey pub = ident.getSigningPublicKey(); + SigType st = pub.getType(); + if (st == null) + throw dfe; + bais.reset(); + byte[] data = new byte[bais.available() - st.getSigLen()]; + bais.read(data); + Signature sig = new Signature(st); + sig.readBytes(bais); + if (DSAEngine.getInstance().verifySignature(sig, data, pub)) { + Log log = ctx.logManager().getLog(SSU2Payload.class); + if (log.shouldWarn()) + log.warn("Error reading RI", dfe); + // partially filled-in RI, -1 is signal to IES2.gotRI() + alice = new RouterInfo(); + alice.setIdentity(ident); + alice.setPublished(-1); + } else { + // bad sig, just throw dfe + throw dfe; + } + } cb.gotRI(alice, isHandshake, flood); } else { byte[] data = new byte[len - 2];