From d054c6bc04eabaecc1ef5c814347ddb1eef35af2 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Wed, 5 Dec 2018 13:50:07 +0000 Subject: [PATCH] I2CP: Set offline keys in generated LS2 (router side to follow) Propagate error from disconnect message to session listener Refactor RLSMH options --- .../net/i2p/client/impl/I2PSessionImpl.java | 22 ++++++++++-- .../impl/RequestLeaseSetMessageHandler.java | 35 +++++++++++++++---- .../client/impl/SetDateMessageHandler.java | 8 ++++- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/core/java/src/net/i2p/client/impl/I2PSessionImpl.java b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java index 9e0cadfddd..e7ca36871b 100644 --- a/core/java/src/net/i2p/client/impl/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java @@ -148,6 +148,10 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 /** monitor for waiting until a lease set has been granted */ protected final Object _leaseSetWait = new Object(); + /** set in propogateError(), sync with _stateLock */ + private String _errorMessage; + private Throwable _errorCause; + /** * @since 0.9.8 */ @@ -694,6 +698,8 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 try { // protect w/ closeSocket() synchronized(_stateLock) { + _errorMessage = null; + _errorCause = null; // If we are in the router JVM, connect using the internal queue if (_context.isRouterContext()) { // _socket and _writer remain null @@ -780,8 +786,17 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 _leaseSetWait.wait(1000); } // if we got a disconnect message while waiting - if (isClosed()) - throw new IOException("Disconnected from router while waiting for tunnels"); + synchronized (_stateLock) { + if (isClosed()) { + String msg = "Disconnected from router while waiting for tunnels"; + if (_errorMessage != null) + msg += ": " + _errorMessage; + IOException ioe = new IOException(msg); + if (_errorCause != null) + ioe.initCause(_errorCause); + throw ioe; + } + } } if (_log.shouldLog(Log.INFO)) { long connected = _context.clock().now(); @@ -1258,6 +1273,9 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 if (_log.shouldLog(level)) _log.log(level, getPrefix() + msgpfx + msg, error); if (_sessionListener != null) _sessionListener.errorOccurred(this, msg, error); + // Save for throwing out of connect() + _errorMessage = msg; + _errorCause = error; } /** diff --git a/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java b/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java index 82a7fb46df..3d8da22b9c 100644 --- a/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java +++ b/core/java/src/net/i2p/client/impl/RequestLeaseSetMessageHandler.java @@ -49,6 +49,15 @@ import net.i2p.util.Log; class RequestLeaseSetMessageHandler extends HandlerImpl { private final Map<Destination, LeaseInfo> _existingLeaseSets; + // LS 1 + private static final String PROP_LS_ENCRYPT = "i2cp.encryptLeaseSet"; + private static final String PROP_LS_KEY = "i2cp.leaseSetKey"; + private static final String PROP_LS_PK = "i2cp.leaseSetPrivateKey"; + private static final String PROP_LS_SPK = "i2cp.leaseSetSigningPrivateKey"; + // LS 2 + private static final String PROP_LS_TYPE = "i2cp.leaseSetType"; + private static final String PROP_LS_ENCTYPE = "i2cp.leaseSetEncType"; + public RequestLeaseSetMessageHandler(I2PAppContext context) { this(context, RequestLeaseSetMessage.MESSAGE_TYPE); } @@ -70,13 +79,15 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { protected static boolean requiresLS2(I2PSessionImpl session) { if (!session.supportsLS2()) return false; - String s = session.getOptions().getProperty("crypto.encType"); + if (session.isOffline()) + return true; + String s = session.getOptions().getProperty(PROP_LS_ENCTYPE); if (s != null) { EncType type = EncType.parseEncType(s); if (type != null && type != EncType.ELGAMAL_2048 && type.isAvailable()) return true; } - s = session.getOptions().getProperty("i2cp.leaseSetType"); + s = session.getOptions().getProperty(PROP_LS_TYPE); if (s != null) { try { int type = Integer.parseInt(s); @@ -117,9 +128,9 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { LeaseInfo li = _existingLeaseSets.get(dest); if (li == null) { // [enctype:]b64 of private key - String spk = session.getOptions().getProperty("i2cp.leaseSetPrivateKey"); + String spk = session.getOptions().getProperty(PROP_LS_PK); // [sigtype:]b64 of private key - String sspk = session.getOptions().getProperty("i2cp.leaseSetSigningPrivateKey"); + String sspk = session.getOptions().getProperty(PROP_LS_SPK); PrivateKey privKey = null; SigningPrivateKey signingPrivKey = null; if (spk != null && sspk != null) { @@ -178,7 +189,7 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { } } else { EncType type = EncType.ELGAMAL_2048; - String senc = session.getOptions().getProperty("crypto.encType"); + String senc = session.getOptions().getProperty(PROP_LS_ENCTYPE); if (senc != null) { EncType newtype = EncType.parseEncType(senc); if (newtype != null) { @@ -215,8 +226,8 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { opts = ((SubSession) session).getPrimaryOptions(); else opts = session.getOptions(); - boolean encrypt = Boolean.parseBoolean(opts.getProperty("i2cp.encryptLeaseSet")); - String sk = opts.getProperty("i2cp.leaseSetKey"); + boolean encrypt = Boolean.parseBoolean(opts.getProperty(PROP_LS_ENCRYPT)); + String sk = opts.getProperty(PROP_LS_KEY); Hash h = dest.calculateHash(); if (encrypt && sk != null) { SessionKey key = new SessionKey(); @@ -231,6 +242,16 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { } else { _context.keyRing().remove(h); } + // offline keys + if (session.isOffline()) { + LeaseSet2 ls2 = (LeaseSet2) leaseSet; + boolean ok = ls2.setOfflineSignature(session.getOfflineExpiration(), session.getTransientSigningPublicKey(), + session.getOfflineSignature()); + if (!ok) { + session.propogateError("Bad offline signature", new Exception()); + // TODO just let the router handle it for now + } + } try { leaseSet.sign(session.getPrivateKey()); // Workaround for unparsable serialized signing private key for revocation diff --git a/core/java/src/net/i2p/client/impl/SetDateMessageHandler.java b/core/java/src/net/i2p/client/impl/SetDateMessageHandler.java index 723bb7e2fe..c15e0f3a96 100644 --- a/core/java/src/net/i2p/client/impl/SetDateMessageHandler.java +++ b/core/java/src/net/i2p/client/impl/SetDateMessageHandler.java @@ -34,7 +34,13 @@ class SetDateMessageHandler extends HandlerImpl { // we did was get the time from ourselves. if (!_context.isRouterContext()) Clock.getInstance().setNow(msg.getDate().getTime()); - // TODO - save router's version string for future reference + // This saves the various support capabilities based on + // the router's version string for future reference session.dateUpdated(msg.getVersion()); + if (session.isOffline() && !session.supportsLS2()) { + // TODO check other options also? see RLSMH.requiresLS2() + session.propogateError("Router does not support offline keys", new Exception()); + session.destroySession(false); + } } } -- GitLab