forked from I2P_Developers/i2p.i2p
I2CP: Add preliminary support for LS2 (proposal 123)
This commit is contained in:
@@ -17,6 +17,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.SendMessageOptions;
|
||||
import net.i2p.data.DatabaseEntry;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.LeaseSet;
|
||||
@@ -28,6 +29,7 @@ import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.i2cp.AbuseReason;
|
||||
import net.i2p.data.i2cp.AbuseSeverity;
|
||||
import net.i2p.data.i2cp.CreateLeaseSetMessage;
|
||||
import net.i2p.data.i2cp.CreateLeaseSet2Message;
|
||||
import net.i2p.data.i2cp.CreateSessionMessage;
|
||||
import net.i2p.data.i2cp.DestroySessionMessage;
|
||||
import net.i2p.data.i2cp.MessageId;
|
||||
@@ -328,13 +330,20 @@ class I2CPMessageProducer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new signed leaseSet in response to a request to do so and send it
|
||||
* to the router
|
||||
*
|
||||
* In response to a RequestLeaseSet Message from the router, send a
|
||||
* CreateLeaseset Message back to the router.
|
||||
* This method is misnamed, it does not create the LeaseSet,
|
||||
* the caller does that.
|
||||
*
|
||||
*/
|
||||
public void createLeaseSet(I2PSessionImpl session, LeaseSet leaseSet, SigningPrivateKey signingPriv,
|
||||
PrivateKey priv) throws I2PSessionException {
|
||||
CreateLeaseSetMessage msg = new CreateLeaseSetMessage();
|
||||
CreateLeaseSetMessage msg;
|
||||
int type = leaseSet.getType();
|
||||
if (type == DatabaseEntry.KEY_TYPE_LEASESET)
|
||||
msg = new CreateLeaseSetMessage();
|
||||
else
|
||||
msg = new CreateLeaseSet2Message();
|
||||
msg.setLeaseSet(leaseSet);
|
||||
msg.setPrivateKey(priv);
|
||||
msg.setSigningPrivateKey(signingPriv);
|
||||
|
||||
@@ -171,6 +171,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
private final boolean _fastReceive;
|
||||
private volatile boolean _routerSupportsFastReceive;
|
||||
private volatile boolean _routerSupportsHostLookup;
|
||||
private volatile boolean _routerSupportsLS2;
|
||||
|
||||
protected static final int CACHE_MAX_SIZE = SystemVersion.isAndroid() ? 32 : 128;
|
||||
/**
|
||||
@@ -197,19 +198,25 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
private static final long MAX_SEND_WAIT = 10*1000;
|
||||
|
||||
private static final String MIN_FAST_VERSION = "0.9.4";
|
||||
////// TESTING, change to 38 before release
|
||||
private static final String MIN_LS2_VERSION = "0.9.37";
|
||||
|
||||
/** @param routerVersion as rcvd in the SetDateMessage, may be null for very old routers */
|
||||
void dateUpdated(String routerVersion) {
|
||||
_routerSupportsFastReceive = _context.isRouterContext() ||
|
||||
boolean isrc = _context.isRouterContext();
|
||||
_routerSupportsFastReceive = isrc ||
|
||||
(routerVersion != null && routerVersion.length() > 0 &&
|
||||
VersionComparator.comp(routerVersion, MIN_FAST_VERSION) >= 0);
|
||||
_routerSupportsHostLookup = _context.isRouterContext() ||
|
||||
_routerSupportsHostLookup = isrc ||
|
||||
TEST_LOOKUP ||
|
||||
(routerVersion != null && routerVersion.length() > 0 &&
|
||||
VersionComparator.comp(routerVersion, MIN_HOST_LOOKUP_VERSION) >= 0);
|
||||
_routerSupportsSubsessions = _context.isRouterContext() ||
|
||||
_routerSupportsSubsessions = isrc ||
|
||||
(routerVersion != null && routerVersion.length() > 0 &&
|
||||
VersionComparator.comp(routerVersion, MIN_SUBSESSION_VERSION) >= 0);
|
||||
_routerSupportsLS2 = isrc ||
|
||||
(routerVersion != null && routerVersion.length() > 0 &&
|
||||
VersionComparator.comp(routerVersion, MIN_LS2_VERSION) >= 0);
|
||||
synchronized (_stateLock) {
|
||||
if (_state == State.OPENING) {
|
||||
changeState(State.GOTDATE);
|
||||
@@ -281,9 +288,11 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
_privateKey = null;
|
||||
_signingPrivateKey = null;
|
||||
}
|
||||
_routerSupportsFastReceive = _context.isRouterContext();
|
||||
_routerSupportsHostLookup = _context.isRouterContext();
|
||||
_routerSupportsSubsessions = _context.isRouterContext();
|
||||
boolean isrc = _context.isRouterContext();
|
||||
_routerSupportsFastReceive = isrc;
|
||||
_routerSupportsHostLookup = isrc;
|
||||
_routerSupportsSubsessions = isrc;
|
||||
_routerSupportsLS2 = isrc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,6 +518,13 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
return _fastReceive && _routerSupportsFastReceive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.38
|
||||
*/
|
||||
public boolean supportsLS2() {
|
||||
return _routerSupportsLS2;
|
||||
}
|
||||
|
||||
void setLeaseSet(LeaseSet ls) {
|
||||
_leaseSet = ls;
|
||||
if (ls != null) {
|
||||
|
||||
@@ -17,14 +17,19 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.crypto.EncType;
|
||||
import net.i2p.crypto.KeyGenerator;
|
||||
import net.i2p.crypto.KeyPair;
|
||||
import net.i2p.crypto.SigType;
|
||||
import net.i2p.data.DatabaseEntry;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.Lease;
|
||||
import net.i2p.data.Lease2;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.LeaseSet2;
|
||||
import net.i2p.data.PrivateKey;
|
||||
import net.i2p.data.PublicKey;
|
||||
import net.i2p.data.SessionKey;
|
||||
@@ -58,13 +63,38 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
_existingLeaseSets = new ConcurrentHashMap<Destination, LeaseInfo>(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we send a LeaseSet or a LeaseSet2?
|
||||
* @since 0.9.38
|
||||
*/
|
||||
protected static boolean requiresLS2(I2PSessionImpl session) {
|
||||
if (!session.supportsLS2())
|
||||
return false;
|
||||
String s = session.getOptions().getProperty("crypto.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");
|
||||
if (s != null) {
|
||||
try {
|
||||
int type = Integer.parseInt(s);
|
||||
if (type != DatabaseEntry.KEY_TYPE_LEASESET)
|
||||
return true;
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
RequestLeaseSetMessage msg = (RequestLeaseSetMessage) message;
|
||||
LeaseSet leaseSet = new LeaseSet();
|
||||
boolean isLS2 = requiresLS2(session);
|
||||
LeaseSet leaseSet = isLS2 ? new LeaseSet2() : new LeaseSet();
|
||||
for (int i = 0; i < msg.getEndpoints(); i++) {
|
||||
Lease lease = new Lease();
|
||||
Lease lease = isLS2 ? new Lease2() : new Lease();
|
||||
lease.setGateway(msg.getRouter(i));
|
||||
lease.setTunnelId(msg.getTunnelId(i));
|
||||
lease.setEndDate(msg.getEndDate());
|
||||
@@ -147,7 +177,26 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
li = new LeaseInfo(privKey, dest);
|
||||
}
|
||||
} else {
|
||||
li = new LeaseInfo(dest);
|
||||
EncType type = EncType.ELGAMAL_2048;
|
||||
String senc = session.getOptions().getProperty("crypto.encType");
|
||||
if (senc != null) {
|
||||
EncType newtype = EncType.parseEncType(senc);
|
||||
if (newtype != null) {
|
||||
if (newtype.isAvailable()) {
|
||||
type = newtype;
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Using crypto type: " + type);
|
||||
} else {
|
||||
_log.error("Unsupported crypto.encType: " + newtype);
|
||||
}
|
||||
} else {
|
||||
_log.error("Bad crypto.encType: " + senc);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Using default crypto type");
|
||||
}
|
||||
li = new LeaseInfo(dest, type);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating new leaseInfo keys for " + dest + " without configured private keys");
|
||||
}
|
||||
@@ -187,14 +236,18 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
// Workaround for unparsable serialized signing private key for revocation
|
||||
// Send him a dummy DSA_SHA1 private key since it's unused anyway
|
||||
// See CreateLeaseSetMessage.doReadMessage()
|
||||
// For LS1 only
|
||||
SigningPrivateKey spk = li.getSigningPrivateKey();
|
||||
if (!_context.isRouterContext() && spk.getType() != SigType.DSA_SHA1) {
|
||||
if (!_context.isRouterContext() && spk.getType() != SigType.DSA_SHA1 &&
|
||||
!(leaseSet instanceof LeaseSet2)) {
|
||||
byte[] dummy = new byte[SigningPrivateKey.KEYSIZE_BYTES];
|
||||
_context.random().nextBytes(dummy);
|
||||
spk = new SigningPrivateKey(dummy);
|
||||
}
|
||||
session.getProducer().createLeaseSet(session, leaseSet, spk, li.getPrivateKey());
|
||||
session.setLeaseSet(leaseSet);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Created and signed LeaseSet: " + leaseSet);
|
||||
} catch (DataFormatException dfe) {
|
||||
session.propogateError("Error signing the leaseSet", dfe);
|
||||
} catch (I2PSessionException ise) {
|
||||
@@ -220,8 +273,8 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
/**
|
||||
* New keys
|
||||
*/
|
||||
public LeaseInfo(Destination dest) {
|
||||
SimpleDataStructure encKeys[] = KeyGenerator.getInstance().generatePKIKeys();
|
||||
public LeaseInfo(Destination dest, EncType type) {
|
||||
KeyPair encKeys = KeyGenerator.getInstance().generatePKIKeys(type);
|
||||
// must be same type as the Destination's signing key
|
||||
SimpleDataStructure signKeys[];
|
||||
try {
|
||||
@@ -229,8 +282,8 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new IllegalStateException(gse);
|
||||
}
|
||||
_pubKey = (PublicKey) encKeys[0];
|
||||
_privKey = (PrivateKey) encKeys[1];
|
||||
_pubKey = encKeys.getPublic();
|
||||
_privKey = encKeys.getPrivate();
|
||||
_signingPubKey = (SigningPublicKey) signKeys[0];
|
||||
_signingPrivKey = (SigningPrivateKey) signKeys[1];
|
||||
}
|
||||
|
||||
@@ -10,7 +10,10 @@ package net.i2p.client.impl;
|
||||
*/
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Lease;
|
||||
import net.i2p.data.Lease2;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.LeaseSet2;
|
||||
import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.RequestVariableLeaseSetMessage;
|
||||
import net.i2p.util.Log;
|
||||
@@ -32,9 +35,21 @@ class RequestVariableLeaseSetMessageHandler extends RequestLeaseSetMessageHandle
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
RequestVariableLeaseSetMessage msg = (RequestVariableLeaseSetMessage) message;
|
||||
LeaseSet leaseSet = new LeaseSet();
|
||||
boolean isLS2 = requiresLS2(session);
|
||||
LeaseSet leaseSet = isLS2 ? new LeaseSet2() : new LeaseSet();
|
||||
for (int i = 0; i < msg.getEndpoints(); i++) {
|
||||
leaseSet.addLease(msg.getEndpoint(i));
|
||||
Lease lease;
|
||||
if (isLS2) {
|
||||
// convert Lease to Lease2
|
||||
Lease old = msg.getEndpoint(i);
|
||||
lease = new Lease2();
|
||||
lease.setGateway(old.getGateway());
|
||||
lease.setTunnelId(old.getTunnelId());
|
||||
lease.setEndDate(old.getEndDate());
|
||||
} else {
|
||||
lease = msg.getEndpoint(i);
|
||||
}
|
||||
leaseSet.addLease(lease);
|
||||
}
|
||||
signLeaseSet(leaseSet, session);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user