From bb19fcdac353aa4d2fa01b6f57dcf9f03183a545 Mon Sep 17 00:00:00 2001 From: zzz <zzz@i2pmail.org> Date: Tue, 22 Jun 2021 09:06:40 -0400 Subject: [PATCH] Tunnels: Changes for new build messages (Prop. 157) - Remove ITBM, change record length from 236 to 218 bytes - Fix check of blank record in BuildReplyHandler - Fix offset constants for short record in BuildRequestRecord - Fix BuildMessageTestStandalone test 6 (short inbound) - ITBM class removal TODO --- .../net/i2p/data/i2np/BuildRequestRecord.java | 17 +++--- .../net/i2p/data/i2np/I2NPMessageImpl.java | 3 - .../data/i2np/ShortTunnelBuildMessage.java | 2 +- .../router/tunnel/OutboundGatewayMessage.java | 1 - .../i2p/router/tunnel/TunnelDispatcher.java | 3 +- .../i2p/router/tunnel/pool/BuildHandler.java | 57 +++---------------- .../tunnel/pool/BuildMessageGenerator.java | 6 +- .../router/tunnel/pool/BuildReplyHandler.java | 3 +- .../router/tunnel/pool/BuildRequestor.java | 10 +--- .../pool/BuildMessageTestStandalone.java | 19 +------ 10 files changed, 29 insertions(+), 92 deletions(-) diff --git a/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java b/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java index d70d92e3a4..595b140b6a 100644 --- a/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java +++ b/router/java/src/net/i2p/data/i2np/BuildRequestRecord.java @@ -94,7 +94,7 @@ import net.i2p.router.RouterContext; * * ECIES short record format, ref: proposal 157: * - * Holds the unencrypted 172-byte tunnel request record, + * Holds the unencrypted 154-byte tunnel request record, * with a constructor for ECIES decryption and a method for ECIES encryption. * Iterative AES encryption/decryption is done elsewhere. * @@ -111,15 +111,15 @@ import net.i2p.router.RouterContext; * bytes 52-55: next message ID * bytes 56-x: tunnel build options (Mapping) * bytes x-x: other data as implied by flags or options - * bytes x-171: random padding + * bytes x-153: random padding * </pre> * * Encrypted: * <pre> * bytes 0-15: Hop's truncated identity hash * bytes 16-47: Sender's ephemeral X25519 public key - * bytes 48-219: ChaCha20 encrypted BuildRequestRecord - * bytes 220-235: Poly1305 MAC + * bytes 48-201: ChaCha20 encrypted BuildRequestRecord + * bytes 202-217: Poly1305 MAC * </pre> * */ @@ -189,10 +189,11 @@ public class BuildRequestRecord { private static final int OFF_FLAG_EC_SHORT = OFF_SEND_IDENT_EC + Hash.HASH_LENGTH; private static final int OFF_LAYER_ENC_TYPE = OFF_FLAG_EC_SHORT + 3; private static final int OFF_REQ_TIME_EC_SHORT = OFF_LAYER_ENC_TYPE + 1; - private static final int OFF_EXPIRATION_SHORT = OFF_REQ_TIME_EC + 4; - private static final int OFF_SEND_MSG_ID_EC_SHORT = OFF_EXPIRATION + 4; + private static final int OFF_EXPIRATION_SHORT = OFF_REQ_TIME_EC_SHORT + 4; + private static final int OFF_SEND_MSG_ID_EC_SHORT = OFF_EXPIRATION_SHORT + 4; private static final int OFF_OPTIONS_SHORT = OFF_SEND_MSG_ID_EC_SHORT + 4; - private static final int LENGTH_EC_SHORT = 172; + // 16 byte trunc. hash, 32 byte eph. key, 16 byte MAC + private static final int LENGTH_EC_SHORT = ShortTunnelBuildMessage.SHORT_RECORD_SIZE - (16 + 32 + 16); private static final int MAX_OPTIONS_LENGTH_SHORT = LENGTH_EC_SHORT - OFF_OPTIONS_SHORT; // includes options length private static final boolean TEST = false; @@ -644,7 +645,7 @@ public class BuildRequestRecord { * @param nextMsgId message ID to use when sending on to the next hop (or for the reply) * @param isInGateway are we the gateway of an inbound tunnel? * @param isOutEndpoint are we the endpoint of an outbound tunnel? - * @param options 116 bytes max when serialized + * @param options 98 bytes max when serialized * @since 0.9.51 * @throws IllegalArgumentException if options too long */ diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 9c8a636a33..46a8dde39b 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -439,9 +439,6 @@ public abstract class I2NPMessageImpl implements I2NPMessage { case VariableTunnelBuildReplyMessage.MESSAGE_TYPE: return new VariableTunnelBuildReplyMessage(context); // since 0.9.51 - case InboundTunnelBuildMessage.MESSAGE_TYPE: - return new InboundTunnelBuildMessage(context); - // since 0.9.51 case OutboundTunnelBuildReplyMessage.MESSAGE_TYPE: return new OutboundTunnelBuildReplyMessage(context); // since 0.9.51 diff --git a/router/java/src/net/i2p/data/i2np/ShortTunnelBuildMessage.java b/router/java/src/net/i2p/data/i2np/ShortTunnelBuildMessage.java index 2fc6e943cc..4740e1c84c 100644 --- a/router/java/src/net/i2p/data/i2np/ShortTunnelBuildMessage.java +++ b/router/java/src/net/i2p/data/i2np/ShortTunnelBuildMessage.java @@ -10,7 +10,7 @@ import net.i2p.I2PAppContext; */ public class ShortTunnelBuildMessage extends TunnelBuildMessage { public static final int MESSAGE_TYPE = 25; - public static final int SHORT_RECORD_SIZE = 236; + public static final int SHORT_RECORD_SIZE = 218; /** zero record count, will be set with readMessage() */ public ShortTunnelBuildMessage(I2PAppContext context) { diff --git a/router/java/src/net/i2p/router/tunnel/OutboundGatewayMessage.java b/router/java/src/net/i2p/router/tunnel/OutboundGatewayMessage.java index 48d0ccd775..eb8b27db8f 100644 --- a/router/java/src/net/i2p/router/tunnel/OutboundGatewayMessage.java +++ b/router/java/src/net/i2p/router/tunnel/OutboundGatewayMessage.java @@ -79,7 +79,6 @@ class OutboundGatewayMessage extends PendingGatewayMessage implements CDPQEntry // these shouldn't go into a OBGW case DatabaseSearchReplyMessage.MESSAGE_TYPE: case DataMessage.MESSAGE_TYPE: - case InboundTunnelBuildMessage.MESSAGE_TYPE: case OutboundTunnelBuildReplyMessage.MESSAGE_TYPE: case TunnelBuildReplyMessage.MESSAGE_TYPE: case TunnelDataMessage.MESSAGE_TYPE: diff --git a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java index f7ffc18c78..96877b2ee0 100644 --- a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java +++ b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java @@ -11,7 +11,6 @@ import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.TunnelId; import net.i2p.data.i2np.I2NPMessage; -import net.i2p.data.i2np.InboundTunnelBuildMessage; import net.i2p.data.i2np.OutboundTunnelBuildReplyMessage; import net.i2p.data.i2np.ShortTunnelBuildMessage; import net.i2p.data.i2np.TunnelBuildMessage; @@ -785,7 +784,7 @@ public class TunnelDispatcher implements Service { } else if (loc == Location.IBGW) { // we don't need to check for VTBM/TBM as that happens at tunnel creation if (type == VariableTunnelBuildReplyMessage.MESSAGE_TYPE || type == TunnelBuildReplyMessage.MESSAGE_TYPE || - type == OutboundTunnelBuildReplyMessage.MESSAGE_TYPE || type == InboundTunnelBuildMessage.MESSAGE_TYPE) + type == OutboundTunnelBuildReplyMessage.MESSAGE_TYPE) factor = 1 / (1.5f * 1.5f * 1.5f); else factor = 1 / 1.5f; diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java index 87bf37c3ce..67665342b2 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java @@ -19,7 +19,6 @@ import net.i2p.data.i2np.BuildRequestRecord; import net.i2p.data.i2np.BuildResponseRecord; import net.i2p.data.i2np.EncryptedBuildRecord; import net.i2p.data.i2np.I2NPMessage; -import net.i2p.data.i2np.InboundTunnelBuildMessage; import net.i2p.data.i2np.OutboundTunnelBuildReplyMessage; import net.i2p.data.i2np.ShortTunnelBuildMessage; import net.i2p.data.i2np.ShortTunnelBuildReplyMessage; @@ -173,7 +172,6 @@ class BuildHandler implements Runnable { ctx.inNetMessagePool().registerHandlerJobBuilder(TunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb); ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildMessage.MESSAGE_TYPE, tbmhjb); ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb); - ctx.inNetMessagePool().registerHandlerJobBuilder(InboundTunnelBuildMessage.MESSAGE_TYPE, tbmhjb); ctx.inNetMessagePool().registerHandlerJobBuilder(ShortTunnelBuildMessage.MESSAGE_TYPE, tbmhjb); ctx.inNetMessagePool().registerHandlerJobBuilder(OutboundTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb); } @@ -736,21 +734,6 @@ class BuildHandler implements Runnable { _log.warn("Dropping build request, we are the previous hop: " + req); return; } - if (state.msg.getType() == InboundTunnelBuildMessage.MESSAGE_TYPE) { - // can only be at IBGW - _context.statManager().addRateData("tunnel.rejectHostile", 1); - if (_log.shouldWarn()) - _log.warn("Dropping ITBM, we are not IBGW: " + req); - return; - } - } else { - if (state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) { - // cannot be at IBGW - _context.statManager().addRateData("tunnel.rejectHostile", 1); - if (_log.shouldWarn()) - _log.warn("Dropping STBM, we are IBGW: " + req); - return; - } } if ((!isOutEnd) && (!isInGW)) { // Previous and next hop the same? Don't help somebody be evil. Drop it without a reply. @@ -997,33 +980,13 @@ class BuildHandler implements Runnable { } int records = state.msg.getRecordCount(); int ourSlot = -1; - ShortTunnelBuildMessage stbm = null; - if (state.msg.getType() == InboundTunnelBuildMessage.MESSAGE_TYPE) { - if (!HANDLE_SHORT) { - if (_log.shouldWarn()) - _log.warn("Unsupported ITBM"); - return; - } - // IBGW only (enforced above) - // Create a ShortTunnelBuildMessage and populate it for sending - InboundTunnelBuildMessage itbm = (InboundTunnelBuildMessage) state.msg; - ourSlot = itbm.getPlaintextSlot(); - stbm = new ShortTunnelBuildMessage(_context, records); - for (int j = 0; j < records; j++) { - if (j == ourSlot) - stbm.setRecord(j, reply); - else - stbm.setRecord(j, itbm.getRecord(j)); - } - } else { - for (int j = 0; j < records; j++) { - if (state.msg.getRecord(j) == null) { - ourSlot = j; - if (!(isOutEnd && state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE)) - state.msg.setRecord(j, reply); - // else reply will be sent in plaintext - break; - } + for (int j = 0; j < records; j++) { + if (state.msg.getRecord(j) == null) { + ourSlot = j; + if (!(isOutEnd && state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE)) + state.msg.setRecord(j, reply); + // else reply will be sent in plaintext + break; } } @@ -1035,11 +998,7 @@ class BuildHandler implements Runnable { // now actually send the response long expires = now + NEXT_HOP_SEND_TIMEOUT; if (!isOutEnd) { - TunnelBuildMessage nextMessage; - if (stbm != null) - nextMessage = stbm; - else - nextMessage = state.msg; + TunnelBuildMessage nextMessage = state.msg; nextMessage.setUniqueId(req.readReplyMessageId()); nextMessage.setMessageExpiration(expires); OutNetMessage msg = new OutNetMessage(_context, nextMessage, expires, PRIORITY, nextPeerInfo); diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java b/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java index 4e7aa3e059..1ab9117db9 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java @@ -12,7 +12,6 @@ import net.i2p.data.SessionKey; import net.i2p.data.i2np.BuildRequestRecord; import net.i2p.data.i2np.EncryptedBuildRecord; import net.i2p.data.i2np.I2NPMessage; -import net.i2p.data.i2np.InboundTunnelBuildMessage; import net.i2p.data.i2np.ShortEncryptedBuildRecord; import net.i2p.data.i2np.ShortTunnelBuildMessage; import net.i2p.data.i2np.TunnelBuildMessage; @@ -41,7 +40,7 @@ abstract class BuildMessageGenerator { TunnelCreatorConfig cfg, Hash replyRouter, long replyTunnel, RouterContext ctx, PublicKey peerKey) { int mtype = msg.getType(); - boolean isShort = mtype == InboundTunnelBuildMessage.MESSAGE_TYPE || mtype == ShortTunnelBuildMessage.MESSAGE_TYPE; + boolean isShort = mtype == ShortTunnelBuildMessage.MESSAGE_TYPE; EncryptedBuildRecord erec; if (peerKey != null) { boolean isEC = peerKey.getType() == EncType.ECIES_X25519; @@ -56,6 +55,7 @@ abstract class BuildMessageGenerator { Hash peer = cfg.getPeer(hop); if (isEC) { erec = req.encryptECIESRecord(ctx, peerKey, peer); + // TODO if isShort, set derived keys in coonfig cfg.setChaChaReplyKeys(hop, req.getChaChaReplyKey(), req.getChaChaReplyAD()); } else { erec = req.encryptRecord(ctx, peerKey, peer); @@ -163,7 +163,7 @@ abstract class BuildMessageGenerator { public static void layeredEncrypt(I2PAppContext ctx, TunnelBuildMessage msg, TunnelCreatorConfig cfg, List<Integer> order) { int mtype = msg.getType(); - boolean isShort = mtype == InboundTunnelBuildMessage.MESSAGE_TYPE || mtype == ShortTunnelBuildMessage.MESSAGE_TYPE; + boolean isShort = mtype == ShortTunnelBuildMessage.MESSAGE_TYPE; int size = isShort ? ShortTunnelBuildMessage.SHORT_RECORD_SIZE : TunnelBuildMessage.RECORD_SIZE; byte[] chachaIV = isShort ? new byte[12] : null; // encrypt the records so that the right elements will be visible at the right time diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildReplyHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildReplyHandler.java index 92726222eb..28f1ba2b6b 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildReplyHandler.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildReplyHandler.java @@ -62,7 +62,8 @@ class BuildReplyHandler { log.debug(reply.getUniqueId() + ": skipping record " + i + "/" + hop + " for: " + cfg); if (cfg.isInbound() && hop + 1 == cfg.getLength()) { // IBEP byte[] h1 = new byte[Hash.HASH_LENGTH]; - ctx.sha().calculateHash(reply.getRecord(i).getData(), 0, TunnelBuildReplyMessage.RECORD_SIZE, h1, 0); + byte[] data = reply.getRecord(i).getData(); + ctx.sha().calculateHash(data, 0, data.length, h1, 0); // get stored hash put here by BuildMessageGenerator Hash h2 = cfg.getBlankHash(); if (h2 != null && DataHelper.eq(h1, h2.getData())) { diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java index bba144f18c..360bb5e5fa 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java @@ -11,7 +11,6 @@ import net.i2p.data.PublicKey; import net.i2p.data.router.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.data.i2np.I2NPMessage; -import net.i2p.data.i2np.InboundTunnelBuildMessage; import net.i2p.data.i2np.ShortTunnelBuildMessage; import net.i2p.data.i2np.TunnelBuildMessage; import net.i2p.data.i2np.VariableTunnelBuildMessage; @@ -211,8 +210,8 @@ abstract class BuildRequestor { //long beforeDispatch = System.currentTimeMillis(); if (cfg.isInbound()) { Hash ibgw = cfg.getPeer(0); - if (msg.getType() == InboundTunnelBuildMessage.MESSAGE_TYPE) { - // ITBM is garlic encrypted to the IBGW, to hide it from the OBEP + if (msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) { + // STBM is garlic encrypted to the IBGW, to hide it from the OBEP RouterInfo peer = ctx.netDb().lookupRouterInfoLocally(ibgw); if (peer != null) { I2NPMessage enc = MessageWrapper.wrap(ctx, msg, peer); @@ -339,10 +338,7 @@ abstract class BuildRequestor { len = TunnelBuildMessage.MAX_RECORD_COUNT; order = new ArrayList<Integer>(ORDER); } - if (cfg.isInbound()) - msg = new InboundTunnelBuildMessage(ctx, len); - else - msg = new ShortTunnelBuildMessage(ctx, len); + msg = new ShortTunnelBuildMessage(ctx, len); } else if (useVariable) { if (cfg.getLength() <= SHORT_RECORDS) { msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS); diff --git a/router/java/test/junit/net/i2p/router/tunnel/pool/BuildMessageTestStandalone.java b/router/java/test/junit/net/i2p/router/tunnel/pool/BuildMessageTestStandalone.java index e45897881d..0e60883fdd 100644 --- a/router/java/test/junit/net/i2p/router/tunnel/pool/BuildMessageTestStandalone.java +++ b/router/java/test/junit/net/i2p/router/tunnel/pool/BuildMessageTestStandalone.java @@ -24,7 +24,6 @@ import net.i2p.data.i2np.EncryptedBuildRecord; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.i2np.I2NPMessageException; import net.i2p.data.i2np.I2NPMessageHandler; -import net.i2p.data.i2np.InboundTunnelBuildMessage; import net.i2p.data.i2np.OutboundTunnelBuildReplyMessage; import net.i2p.data.i2np.ShortTunnelBuildMessage; import net.i2p.data.i2np.ShortTunnelBuildReplyMessage; @@ -84,20 +83,8 @@ public class BuildMessageTestStandalone extends TestCase { // populate and encrypt the message TunnelBuildMessage msg; - if (testType == 3) { + if (testType == 3 || testType == 6) { msg = new ShortTunnelBuildMessage(ctx, TunnelBuildMessage.MAX_RECORD_COUNT); - } else if (testType == 6) { - InboundTunnelBuildMessage itbm = new InboundTunnelBuildMessage(ctx, TunnelBuildMessage.MAX_RECORD_COUNT); - // set plaintext record for ibgw - for (int i = 0; i < order.size(); i++) { - int hop = order.get(i).intValue(); - if (hop == 0) { - // TODO - itbm.setPlaintextRecord(i, new byte[100]); - break; - } - } - msg = itbm; } else { msg = new TunnelBuildMessage(ctx); } @@ -109,9 +96,7 @@ public class BuildMessageTestStandalone extends TestCase { PublicKey key = null; if (hop < end) key = _pubKeys[hop]; - // don't do this for ibgw in itbm - if (testType != 6 || hop != 0) - BuildMessageGenerator.createRecord(i, hop, msg, cfg, _replyRouter, _replyTunnel, ctx, key); + BuildMessageGenerator.createRecord(i, hop, msg, cfg, _replyRouter, _replyTunnel, ctx, key); } BuildMessageGenerator.layeredEncrypt(ctx, msg, cfg, order); -- GitLab