forked from I2P_Developers/i2p.i2p
I2PTunnel: Persist leaseset keys
I2CP: Use configured leaseset keys if available
This commit is contained in:
@@ -230,6 +230,26 @@ public class EditBean extends IndexBean {
|
|||||||
return SigType.isAvailable(code);
|
return SigType.isAvailable(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Random keys, hidden in forms
|
||||||
|
* @since 0.9.18
|
||||||
|
*/
|
||||||
|
public String getKey1(int tunnel) {
|
||||||
|
return getProperty(tunnel, "inbound.randomKey", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey2(int tunnel) {
|
||||||
|
return getProperty(tunnel, "outbound.randomKey", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey3(int tunnel) {
|
||||||
|
return getProperty(tunnel, "i2cp.leaseSetSigningPrivateKey", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey4(int tunnel) {
|
||||||
|
return getProperty(tunnel, "i2cp.leaseSetPrivateKey", "");
|
||||||
|
}
|
||||||
|
|
||||||
/** @since 0.8.9 */
|
/** @since 0.8.9 */
|
||||||
public boolean getDCC(int tunnel) {
|
public boolean getDCC(int tunnel) {
|
||||||
return getBooleanProperty(tunnel, I2PTunnelIRCClient.PROP_DCC);
|
return getBooleanProperty(tunnel, I2PTunnelIRCClient.PROP_DCC);
|
||||||
|
@@ -10,6 +10,7 @@ package net.i2p.i2ptunnel.web;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -25,12 +26,15 @@ import net.i2p.I2PAppContext;
|
|||||||
import net.i2p.app.ClientAppManager;
|
import net.i2p.app.ClientAppManager;
|
||||||
import net.i2p.app.Outproxy;
|
import net.i2p.app.Outproxy;
|
||||||
import net.i2p.client.I2PClient;
|
import net.i2p.client.I2PClient;
|
||||||
|
import net.i2p.crypto.KeyGenerator;
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.Base64;
|
import net.i2p.data.Base64;
|
||||||
import net.i2p.data.Certificate;
|
import net.i2p.data.Certificate;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.data.PrivateKeyFile;
|
import net.i2p.data.PrivateKeyFile;
|
||||||
import net.i2p.data.SessionKey;
|
import net.i2p.data.SessionKey;
|
||||||
|
import net.i2p.data.SimpleDataStructure;
|
||||||
import net.i2p.i2ptunnel.I2PTunnelClientBase;
|
import net.i2p.i2ptunnel.I2PTunnelClientBase;
|
||||||
import net.i2p.i2ptunnel.I2PTunnelConnectClient;
|
import net.i2p.i2ptunnel.I2PTunnelConnectClient;
|
||||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
||||||
@@ -1113,6 +1117,30 @@ public class IndexBean {
|
|||||||
// Otherwise this only works on a new tunnel...
|
// Otherwise this only works on a new tunnel...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Random keys, hidden in forms
|
||||||
|
* @since 0.9.18
|
||||||
|
*/
|
||||||
|
public void setKey1(String s) {
|
||||||
|
if (s != null)
|
||||||
|
_otherOptions.put("inbound.randomKey", s.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey2(String s) {
|
||||||
|
if (s != null)
|
||||||
|
_otherOptions.put("outbound.randomKey", s.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey3(String s) {
|
||||||
|
if (s != null)
|
||||||
|
_otherOptions.put("i2cp.leaseSetSigningPrivateKey", s.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey4(String s) {
|
||||||
|
if (s != null)
|
||||||
|
_otherOptions.put("i2cp.leaseSetPrivateKey", s.trim());
|
||||||
|
}
|
||||||
|
|
||||||
/** Modify or create a destination */
|
/** Modify or create a destination */
|
||||||
private String modifyDestination() {
|
private String modifyDestination() {
|
||||||
if (_privKeyFile == null || _privKeyFile.trim().length() <= 0)
|
if (_privKeyFile == null || _privKeyFile.trim().length() <= 0)
|
||||||
@@ -1332,11 +1360,10 @@ public class IndexBean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// As of 0.9.17, add a persistent random key if not present
|
|
||||||
if (!isClient(_type) || _booleanOptions.contains("persistentClientKey")) {
|
if (!isClient(_type) || _booleanOptions.contains("persistentClientKey")) {
|
||||||
|
// As of 0.9.17, add a persistent random key if not present
|
||||||
String p = OPT + "inbound.randomKey";
|
String p = OPT + "inbound.randomKey";
|
||||||
if (!config.containsKey(p)) {
|
if (!config.containsKey(p)) {
|
||||||
// as of 0.9.17, add a random key if not previously present
|
|
||||||
byte[] rk = new byte[32];
|
byte[] rk = new byte[32];
|
||||||
_context.random().nextBytes(rk);
|
_context.random().nextBytes(rk);
|
||||||
config.setProperty(p, Base64.encode(rk));
|
config.setProperty(p, Base64.encode(rk));
|
||||||
@@ -1344,6 +1371,22 @@ public class IndexBean {
|
|||||||
_context.random().nextBytes(rk);
|
_context.random().nextBytes(rk);
|
||||||
config.setProperty(p, Base64.encode(rk));
|
config.setProperty(p, Base64.encode(rk));
|
||||||
}
|
}
|
||||||
|
// As of 0.9.18, add persistent leaseset keys if not present
|
||||||
|
// but only if we know the sigtype
|
||||||
|
p = OPT + "i2cp.leaseSetSigningPrivateKey";
|
||||||
|
Destination dest = getDestination(_tunnel);
|
||||||
|
if (dest != null && !config.containsKey(p)) {
|
||||||
|
try {
|
||||||
|
SigType type = dest.getSigType();
|
||||||
|
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
|
||||||
|
config.setProperty(p, type.name() + ':' + keys[1].toBase64());
|
||||||
|
p = OPT + "i2cp.leaseSetPrivateKey";
|
||||||
|
keys = KeyGenerator.getInstance().generatePKIKeys();
|
||||||
|
config.setProperty(p, "ELGAMAL_2048:" + keys[1].toBase64());
|
||||||
|
} catch (GeneralSecurityException gse) {
|
||||||
|
// so much for that
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
@@ -1379,13 +1422,16 @@ public class IndexBean {
|
|||||||
I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
|
I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
|
||||||
I2PTunnelHTTPClientBase.PROP_AUTH,
|
I2PTunnelHTTPClientBase.PROP_AUTH,
|
||||||
I2PClient.PROP_SIGTYPE,
|
I2PClient.PROP_SIGTYPE,
|
||||||
I2PTunnelHTTPClient.PROP_SSL_OUTPROXIES
|
I2PTunnelHTTPClient.PROP_SSL_OUTPROXIES,
|
||||||
|
// following are mostly server but could also be persistent client
|
||||||
|
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey"
|
||||||
};
|
};
|
||||||
private static final String _otherServerOpts[] = {
|
private static final String _otherServerOpts[] = {
|
||||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
|
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
|
||||||
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
|
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
|
||||||
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
|
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
|
||||||
PROP_MAX_STREAMS, I2PClient.PROP_SIGTYPE
|
PROP_MAX_STREAMS, I2PClient.PROP_SIGTYPE,
|
||||||
|
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey"
|
||||||
};
|
};
|
||||||
private static final String _httpServerOpts[] = {
|
private static final String _httpServerOpts[] = {
|
||||||
I2PTunnelHTTPServer.OPT_POST_WINDOW,
|
I2PTunnelHTTPServer.OPT_POST_WINDOW,
|
||||||
|
@@ -58,6 +58,26 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
<input type="hidden" name="tunnel" value="<%=curTunnel%>" />
|
<input type="hidden" name="tunnel" value="<%=curTunnel%>" />
|
||||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||||
<input type="hidden" name="type" value="<%=tunnelType%>" />
|
<input type="hidden" name="type" value="<%=tunnelType%>" />
|
||||||
|
<%
|
||||||
|
// these are four keys that are generated automatically on first save,
|
||||||
|
// and we want to persist in i2ptunnel.config, but don't want to
|
||||||
|
// show clogging up the custom options form.
|
||||||
|
String key = editBean.getKey1(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key1" value="<%=key%>" />
|
||||||
|
<% }
|
||||||
|
key = editBean.getKey2(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key2" value="<%=key%>" />
|
||||||
|
<% }
|
||||||
|
key = editBean.getKey3(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key3" value="<%=key%>" />
|
||||||
|
<% }
|
||||||
|
key = editBean.getKey4(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key4" value="<%=key%>" />
|
||||||
|
<% } %>
|
||||||
<input type="submit" class="default" name="action" value="Save changes" />
|
<input type="submit" class="default" name="action" value="Save changes" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -58,6 +58,26 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
|||||||
<input type="hidden" name="tunnel" value="<%=curTunnel%>" />
|
<input type="hidden" name="tunnel" value="<%=curTunnel%>" />
|
||||||
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
<input type="hidden" name="nonce" value="<%=editBean.getNextNonce()%>" />
|
||||||
<input type="hidden" name="type" value="<%=tunnelType%>" />
|
<input type="hidden" name="type" value="<%=tunnelType%>" />
|
||||||
|
<%
|
||||||
|
// these are four keys that are generated automatically on first save,
|
||||||
|
// and we want to persist in i2ptunnel.config, but don't want to
|
||||||
|
// show clogging up the custom options form.
|
||||||
|
String key = editBean.getKey1(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key1" value="<%=key%>" />
|
||||||
|
<% }
|
||||||
|
key = editBean.getKey2(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key2" value="<%=key%>" />
|
||||||
|
<% }
|
||||||
|
key = editBean.getKey3(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key3" value="<%=key%>" />
|
||||||
|
<% }
|
||||||
|
key = editBean.getKey4(curTunnel);
|
||||||
|
if (key != null && key.length() > 0) { %>
|
||||||
|
<input type="hidden" name="key4" value="<%=key%>" />
|
||||||
|
<% } %>
|
||||||
<input type="submit" class="default" name="action" value="Save changes" />
|
<input type="submit" class="default" name="action" value="Save changes" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -74,22 +74,68 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
|||||||
* Finish creating and signing the new LeaseSet
|
* Finish creating and signing the new LeaseSet
|
||||||
* @since 0.9.7
|
* @since 0.9.7
|
||||||
*/
|
*/
|
||||||
protected void signLeaseSet(LeaseSet leaseSet, I2PSessionImpl session) {
|
protected synchronized void signLeaseSet(LeaseSet leaseSet, I2PSessionImpl session) {
|
||||||
|
Destination dest = session.getMyDestination();
|
||||||
// also, if this session is connected to multiple routers, include other leases here
|
// also, if this session is connected to multiple routers, include other leases here
|
||||||
leaseSet.setDestination(session.getMyDestination());
|
leaseSet.setDestination(dest);
|
||||||
|
|
||||||
// reuse the old keys for the client
|
// reuse the old keys for the client
|
||||||
LeaseInfo li = _existingLeaseSets.get(session.getMyDestination());
|
LeaseInfo li = _existingLeaseSets.get(dest);
|
||||||
if (li == null) {
|
if (li == null) {
|
||||||
li = new LeaseInfo(session.getMyDestination());
|
// [enctype:]b64 of private key
|
||||||
_existingLeaseSets.put(session.getMyDestination(), li);
|
String spk = session.getOptions().getProperty("i2cp.leaseSetPrivateKey");
|
||||||
|
// [sigtype:]b64 of private key
|
||||||
|
String sspk = session.getOptions().getProperty("i2cp.leaseSetSigningPrivateKey");
|
||||||
|
PrivateKey privKey = null;
|
||||||
|
SigningPrivateKey signingPrivKey = null;
|
||||||
|
boolean useOldKeys;
|
||||||
|
if (spk != null && sspk != null) {
|
||||||
|
useOldKeys = true;
|
||||||
|
int colon = sspk.indexOf(':');
|
||||||
|
SigType type = dest.getSigType();
|
||||||
|
if (colon > 0) {
|
||||||
|
String stype = sspk.substring(0, colon);
|
||||||
|
SigType t = SigType.parseSigType(stype);
|
||||||
|
if (t == type)
|
||||||
|
sspk = sspk.substring(colon + 1);
|
||||||
|
else
|
||||||
|
useOldKeys = false;
|
||||||
|
}
|
||||||
|
colon = spk.indexOf(':');
|
||||||
|
// just ignore for now, no other types supported
|
||||||
|
if (colon >= 0)
|
||||||
|
spk = spk.substring(colon + 1);
|
||||||
|
if (useOldKeys) {
|
||||||
|
try {
|
||||||
|
signingPrivKey = new SigningPrivateKey(type);
|
||||||
|
signingPrivKey.fromBase64(sspk);
|
||||||
|
} catch (DataFormatException iae) {
|
||||||
|
useOldKeys = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (useOldKeys) {
|
||||||
|
try {
|
||||||
|
privKey = new PrivateKey();
|
||||||
|
privKey.fromBase64(spk);
|
||||||
|
} catch (DataFormatException iae) {
|
||||||
|
useOldKeys = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
useOldKeys = false;
|
||||||
|
}
|
||||||
|
if (useOldKeys)
|
||||||
|
li = new LeaseInfo(privKey, signingPrivKey);
|
||||||
|
else
|
||||||
|
li = new LeaseInfo(dest);
|
||||||
|
_existingLeaseSets.put(dest, li);
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Creating new leaseInfo keys for "
|
_log.debug("Creating new leaseInfo keys for "
|
||||||
+ session.getMyDestination().calculateHash().toBase64());
|
+ dest + " using configured private keys? " + useOldKeys);
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Caching the old leaseInfo keys for "
|
_log.debug("Caching the old leaseInfo keys for "
|
||||||
+ session.getMyDestination().calculateHash().toBase64());
|
+ dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
leaseSet.setEncryptionKey(li.getPublicKey());
|
leaseSet.setEncryptionKey(li.getPublicKey());
|
||||||
@@ -133,7 +179,7 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
|||||||
private final SigningPrivateKey _signingPrivKey;
|
private final SigningPrivateKey _signingPrivKey;
|
||||||
|
|
||||||
public LeaseInfo(Destination dest) {
|
public LeaseInfo(Destination dest) {
|
||||||
Object encKeys[] = KeyGenerator.getInstance().generatePKIKeypair();
|
SimpleDataStructure encKeys[] = KeyGenerator.getInstance().generatePKIKeys();
|
||||||
// must be same type as the Destination's signing key
|
// must be same type as the Destination's signing key
|
||||||
SimpleDataStructure signKeys[];
|
SimpleDataStructure signKeys[];
|
||||||
try {
|
try {
|
||||||
@@ -147,6 +193,16 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
|||||||
_signingPrivKey = (SigningPrivateKey) signKeys[1];
|
_signingPrivKey = (SigningPrivateKey) signKeys[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.18
|
||||||
|
*/
|
||||||
|
public LeaseInfo(PrivateKey privKey, SigningPrivateKey signingPrivKey) {
|
||||||
|
_pubKey = KeyGenerator.getPublicKey(privKey);
|
||||||
|
_privKey = privKey;
|
||||||
|
_signingPubKey = KeyGenerator.getSigningPublicKey(signingPrivKey);
|
||||||
|
_signingPrivKey = signingPrivKey;
|
||||||
|
}
|
||||||
|
|
||||||
public PublicKey getPublicKey() {
|
public PublicKey getPublicKey() {
|
||||||
return _pubKey;
|
return _pubKey;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
|
2015-01-03 zzz
|
||||||
|
* I2CP: Use configured leaseset keys if available
|
||||||
|
* I2PTunnel: Persist leaseset keys
|
||||||
|
|
||||||
2014-12-15 zzz
|
2014-12-15 zzz
|
||||||
* Console: Prevent two-word translations from splitting across lines in summary bar
|
* Console: Prevent two-word translations from splitting across lines in summary bar
|
||||||
* EdDSA: Cleanups
|
* Crypto: EdDSA cleanups
|
||||||
* i2psnark: Unchoke new peer sooner
|
* i2psnark: Unchoke new peer sooner
|
||||||
* SSU: reduce log level of uncaught errors processing I2NP message
|
* SSU: reduce log level of uncaught errors processing I2NP message
|
||||||
* SU3:
|
* SU3:
|
||||||
|
@@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 3;
|
public final static long BUILD = 4;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
Reference in New Issue
Block a user