i2ptunnel:

ECDSA default for all new server tunnels
ECDSA default for streamr client tunnels
Fix display of server destination on edit page when not running (privkey file path wasn't absolute)
Fix display of persistent client key b32 on edit page when not running
Fix display of server sig type on edit page when we have a privkey file
Add KeysAndCert.getSigType()
Javadocs
This commit is contained in:
zzz
2014-11-02 15:23:13 +00:00
parent 2284c963af
commit 6ca0c54ba7
5 changed files with 168 additions and 49 deletions

View File

@ -84,9 +84,20 @@ public class TunnelController implements Logging {
public static final String TYPE_SOCKS_IRC = "socksirctunnel"; public static final String TYPE_SOCKS_IRC = "socksirctunnel";
public static final String TYPE_STD_CLIENT = "client"; public static final String TYPE_STD_CLIENT = "client";
public static final String TYPE_STD_SERVER = "server"; public static final String TYPE_STD_SERVER = "server";
/** Client in the UI and I2P side but a server on the localhost side */
public static final String TYPE_STREAMR_CLIENT = "streamrclient"; public static final String TYPE_STREAMR_CLIENT = "streamrclient";
/** Server in the UI and I2P side but a client on the localhost side */
public static final String TYPE_STREAMR_SERVER = "streamrserver"; public static final String TYPE_STREAMR_SERVER = "streamrserver";
/**
* This is guaranteed to be available.
* @since 0.9.17
*/
public static final SigType PREFERRED_SIGTYPE = SigType.ECDSA_SHA256_P256.isAvailable() ?
SigType.ECDSA_SHA256_P256 :
SigType.DSA_SHA1;
/** /**
* Create a new controller for a tunnel out of the specific config options. * Create a new controller for a tunnel out of the specific config options.
* The config may contain a large number of options - only ones that begin in * The config may contain a large number of options - only ones that begin in
@ -125,15 +136,12 @@ public class TunnelController implements Logging {
*/ */
private boolean createPrivateKey() { private boolean createPrivateKey() {
I2PClient client = I2PClientFactory.createClient(); I2PClient client = I2PClientFactory.createClient();
String filename = getPrivKeyFile(); File keyFile = getPrivateKeyFile();
if ( (filename == null) || (filename.trim().length() <= 0) ) { if (keyFile == null) {
log("No filename specified for the private key"); log("No filename specified for the private key");
return false; return false;
} }
File keyFile = new File(getPrivKeyFile());
if (!keyFile.isAbsolute())
keyFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), getPrivKeyFile());
if (keyFile.exists()) { if (keyFile.exists()) {
//log("Not overwriting existing private keys in " + keyFile.getAbsolutePath()); //log("Not overwriting existing private keys in " + keyFile.getAbsolutePath());
return true; return true;
@ -145,11 +153,11 @@ public class TunnelController implements Logging {
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
fos = new SecureFileOutputStream(keyFile); fos = new SecureFileOutputStream(keyFile);
SigType stype = I2PClient.DEFAULT_SIGTYPE; SigType stype = PREFERRED_SIGTYPE;
String st = _config.getProperty(OPT_SIG_TYPE); String st = _config.getProperty(OPT_SIG_TYPE);
if (st != null) { if (st != null) {
SigType type = SigType.parseSigType(st); SigType type = SigType.parseSigType(st);
if (type != null) if (type != null && type.isAvailable())
stype = type; stype = type;
else else
log("Unsupported sig type " + st + ", reverting to " + stype); log("Unsupported sig type " + st + ", reverting to " + stype);
@ -586,11 +594,12 @@ public class TunnelController implements Logging {
_config.setProperty(OPT_LOW_TAGS, "14"); _config.setProperty(OPT_LOW_TAGS, "14");
} }
// same default logic as in EditBean.getSigType() // same default logic as in EditBean.getSigType()
if ((type.equals(TYPE_IRC_CLIENT) || type.equals(TYPE_STD_CLIENT) || type.equals(TYPE_SOCKS_IRC)) if (!isClient(type) ||
&& !Boolean.valueOf(getSharedClient())) { ((type.equals(TYPE_IRC_CLIENT) || type.equals(TYPE_STD_CLIENT) ||
if (!_config.containsKey(OPT_SIG_TYPE) && type.equals(TYPE_SOCKS_IRC) || type.equals(TYPE_STREAMR_CLIENT))
SigType.ECDSA_SHA256_P256.isAvailable()) && !Boolean.valueOf(getSharedClient()))) {
_config.setProperty(OPT_SIG_TYPE, "ECDSA_SHA256_P256"); if (!_config.containsKey(OPT_SIG_TYPE))
_config.setProperty(OPT_SIG_TYPE, PREFERRED_SIGTYPE.name());
} }
} }
@ -640,6 +649,34 @@ public class TunnelController implements Logging {
public String getI2CPHost() { return _config.getProperty(PROP_I2CP_HOST); } public String getI2CPHost() { return _config.getProperty(PROP_I2CP_HOST); }
public String getI2CPPort() { return _config.getProperty(PROP_I2CP_PORT); } public String getI2CPPort() { return _config.getProperty(PROP_I2CP_PORT); }
/**
* Is it a client or server in the UI and I2P side?
* Note that a streamr client is a UI and I2P client but a server on the localhost side.
* Note that a streamr server is a UI and I2P server but a client on the localhost side.
*
* @since 0.9.17
*/
public boolean isClient() {
return isClient(getType());
}
/**
* Is it a client or server in the UI and I2P side?
* Note that a streamr client is a UI and I2P client but a server on the localhost side.
* Note that a streamr server is a UI and I2P server but a client on the localhost side.
*
* @since 0.9.17 moved from IndexBean
*/
public static boolean isClient(String type) {
return TYPE_STD_CLIENT.equals(type) ||
TYPE_HTTP_CLIENT.equals(type) ||
TYPE_SOCKS.equals(type) ||
TYPE_SOCKS_IRC.equals(type) ||
TYPE_CONNECT.equals(type) ||
TYPE_STREAMR_CLIENT.equals(type) ||
TYPE_IRC_CLIENT.equals(type);
}
/** /**
* These are the ones with a prefix of "option." * These are the ones with a prefix of "option."
* *
@ -664,7 +701,12 @@ public class TunnelController implements Logging {
public String getTargetHost() { return _config.getProperty(PROP_TARGET_HOST); } public String getTargetHost() { return _config.getProperty(PROP_TARGET_HOST); }
public String getTargetPort() { return _config.getProperty(PROP_TARGET_PORT); } public String getTargetPort() { return _config.getProperty(PROP_TARGET_PORT); }
public String getSpoofedHost() { return _config.getProperty(PROP_SPOOFED_HOST); } public String getSpoofedHost() { return _config.getProperty(PROP_SPOOFED_HOST); }
/**
* Probably not absolute. May be null. getPrivateKeyFile() recommended.
*/
public String getPrivKeyFile() { return _config.getProperty(PROP_FILE); } public String getPrivKeyFile() { return _config.getProperty(PROP_FILE); }
public String getListenPort() { return _config.getProperty(PROP_LISTEN_PORT); } public String getListenPort() { return _config.getProperty(PROP_LISTEN_PORT); }
public String getTargetDestination() { return _config.getProperty(PROP_DEST); } public String getTargetDestination() { return _config.getProperty(PROP_DEST); }
public String getProxyList() { return _config.getProperty(PROP_PROXIES); } public String getProxyList() { return _config.getProperty(PROP_PROXIES); }
@ -674,30 +716,59 @@ public class TunnelController implements Logging {
public boolean getStartOnLoad() { return Boolean.parseBoolean(_config.getProperty(PROP_START, "true")); } public boolean getStartOnLoad() { return Boolean.parseBoolean(_config.getProperty(PROP_START, "true")); }
public boolean getPersistentClientKey() { return Boolean.parseBoolean(_config.getProperty(OPT_PERSISTENT)); } public boolean getPersistentClientKey() { return Boolean.parseBoolean(_config.getProperty(OPT_PERSISTENT)); }
/**
* Does not necessarily exist.
* @return absolute path or null if unset
* @since 0.9.17
*/
public File getPrivateKeyFile() {
String f = getPrivKeyFile();
if (f == null)
return null;
f = f.trim();
if (f.length() == 0)
return null;
File rv = new File(f);
if (!rv.isAbsolute())
rv = new File(I2PAppContext.getGlobalContext().getConfigDir(), f);
return rv;
}
/**
* Returns null if not running.
* @return Base64 or null
*/
public String getMyDestination() { public String getMyDestination() {
if (_tunnel != null) { Destination dest = getDestination();
List<I2PSession> sessions = _tunnel.getSessions(); if (dest != null)
for (int i = 0; i < sessions.size(); i++) { return dest.toBase64();
I2PSession session = sessions.get(i);
Destination dest = session.getMyDestination();
if (dest != null)
return dest.toBase64();
}
}
return null; return null;
} }
/** /**
* Returns null if not running.
* @return "{52 chars}.b32.i2p" or null * @return "{52 chars}.b32.i2p" or null
*/ */
public String getMyDestHashBase32() { public String getMyDestHashBase32() {
Destination dest = getDestination();
if (dest != null)
return dest.toBase32();
return null;
}
/**
* Returns null if not running.
* @return Destination or null
* @since 0.9.17
*/
public Destination getDestination() {
if (_tunnel != null) { if (_tunnel != null) {
List<I2PSession> sessions = _tunnel.getSessions(); List<I2PSession> sessions = _tunnel.getSessions();
for (int i = 0; i < sessions.size(); i++) { for (int i = 0; i < sessions.size(); i++) {
I2PSession session = sessions.get(i); I2PSession session = sessions.get(i);
Destination dest = session.getMyDestination(); Destination dest = session.getMyDestination();
if (dest != null) if (dest != null)
return dest.toBase32(); return dest;
} }
} }
return null; return null;

View File

@ -41,6 +41,11 @@ import net.i2p.util.Addresses;
public class EditBean extends IndexBean { public class EditBean extends IndexBean {
public EditBean() { super(); } public EditBean() { super(); }
/**
* Is it a client or server in the UI and I2P side?
* Note that a streamr client is a UI and I2P client but a server on the localhost side.
* Note that a streamr server is a UI and I2P server but a client on the localhost side.
*/
public static boolean staticIsClient(int tunnel) { public static boolean staticIsClient(int tunnel) {
TunnelControllerGroup group = TunnelControllerGroup.getInstance(); TunnelControllerGroup group = TunnelControllerGroup.getInstance();
if (group == null) if (group == null)
@ -190,6 +195,12 @@ public class EditBean extends IndexBean {
String ttype; String ttype;
boolean isShared; boolean isShared;
if (tunnel >= 0) { if (tunnel >= 0) {
Destination d = getDestination(tunnel);
if (d != null) {
type = d.getSigType();
if (type != null)
return type.getCode();
}
String stype = getProperty(tunnel, I2PClient.PROP_SIGTYPE, null); String stype = getProperty(tunnel, I2PClient.PROP_SIGTYPE, null);
type = stype != null ? SigType.parseSigType(stype) : null; type = stype != null ? SigType.parseSigType(stype) : null;
ttype = getTunnelType(tunnel); ttype = getTunnelType(tunnel);
@ -201,12 +212,13 @@ public class EditBean extends IndexBean {
} }
if (type == null) { if (type == null) {
// same default logic as in TunnelController.setConfig() // same default logic as in TunnelController.setConfig()
if ((TunnelController.TYPE_IRC_CLIENT.equals(ttype) || if ((!TunnelController.isClient(ttype) ||
TunnelController.TYPE_SOCKS_IRC.equals(ttype) || ((TunnelController.TYPE_IRC_CLIENT.equals(ttype) ||
TunnelController.TYPE_STD_CLIENT.equals(ttype)) && TunnelController.TYPE_SOCKS_IRC.equals(ttype) ||
!isShared && TunnelController.TYPE_STREAMR_CLIENT.equals(ttype) ||
SigType.ECDSA_SHA256_P256.isAvailable()) TunnelController.TYPE_STD_CLIENT.equals(ttype)) &&
type = SigType.ECDSA_SHA256_P256; !isShared)))
type = TunnelController.PREFERRED_SIGTYPE;
else else
type = SigType.DSA_SHA1; type = SigType.DSA_SHA1;
} }

View File

@ -467,20 +467,24 @@ public class IndexBean {
return _group.getControllers().size(); return _group.getControllers().size();
} }
/**
* Is it a client or server in the UI and I2P side?
* Note that a streamr client is a UI and I2P client but a server on the localhost side.
* Note that a streamr server is a UI and I2P server but a client on the localhost side.
*/
public boolean isClient(int tunnelNum) { public boolean isClient(int tunnelNum) {
TunnelController cur = getController(tunnelNum); TunnelController cur = getController(tunnelNum);
if (cur == null) return false; if (cur == null) return false;
return isClient(cur.getType()); return cur.isClient();
} }
/**
* Is it a client or server in the UI and I2P side?
* Note that a streamr client is a UI and I2P client but a server on the localhost side.
* Note that a streamr server is a UI and I2P server but a client on the localhost side.
*/
public static boolean isClient(String type) { public static boolean isClient(String type) {
return ( (TunnelController.TYPE_STD_CLIENT.equals(type)) || return TunnelController.isClient(type);
(TunnelController.TYPE_HTTP_CLIENT.equals(type)) ||
(TunnelController.TYPE_SOCKS.equals(type)) ||
(TunnelController.TYPE_SOCKS_IRC.equals(type)) ||
(TunnelController.TYPE_CONNECT.equals(type)) ||
(TunnelController.TYPE_STREAMR_CLIENT.equals(type)) ||
(TunnelController.TYPE_IRC_CLIENT.equals(type)));
} }
public String getTunnelName(int tunnel) { public String getTunnelName(int tunnel) {
@ -657,36 +661,50 @@ public class IndexBean {
return ""; return "";
} }
public String getDestinationBase64(int tunnel) { /**
* Works even if tunnel is not running.
* @return Destination or null
* @since 0.9.17
*/
protected Destination getDestination(int tunnel) {
TunnelController tun = getController(tunnel); TunnelController tun = getController(tunnel);
if (tun != null) { if (tun != null) {
String rv = tun.getMyDestination(); Destination rv = tun.getDestination();
if (rv != null) if (rv != null)
return rv; return rv;
// if not running, do this the hard way // if not running, do this the hard way
String keyFile = tun.getPrivKeyFile(); File keyFile = tun.getPrivateKeyFile();
if (keyFile != null && keyFile.trim().length() > 0) { if (keyFile != null) {
PrivateKeyFile pkf = new PrivateKeyFile(keyFile); PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
try { try {
Destination d = pkf.getDestination(); rv = pkf.getDestination();
if (d != null) if (rv != null)
return d.toBase64(); return rv;
} catch (Exception e) {} } catch (Exception e) {}
} }
} }
return null;
}
/**
* Works even if tunnel is not running.
* @return Base64 or ""
*/
public String getDestinationBase64(int tunnel) {
Destination d = getDestination(tunnel);
if (d != null)
return d.toBase64();
return ""; return "";
} }
/** /**
* Works even if tunnel is not running.
* @return "{52 chars}.b32.i2p" or "" * @return "{52 chars}.b32.i2p" or ""
*/ */
public String getDestHashBase32(int tunnel) { public String getDestHashBase32(int tunnel) {
TunnelController tun = getController(tunnel); Destination d = getDestination(tunnel);
if (tun != null) { if (d != null)
String rv = tun.getMyDestHashBase32(); return d.toBase32();
if (rv != null)
return rv;
}
return ""; return "";
} }

View File

@ -16,6 +16,7 @@ import java.io.OutputStream;
import java.util.Arrays; import java.util.Arrays;
import net.i2p.crypto.SHA256Generator; import net.i2p.crypto.SHA256Generator;
import net.i2p.crypto.SigType;
/** /**
* KeysAndCert has a public key, a signing key, and a certificate. * KeysAndCert has a public key, a signing key, and a certificate.
@ -51,6 +52,22 @@ public class KeysAndCert extends DataStructureImpl {
_certificate = cert; _certificate = cert;
} }
/**
* @return null if not set or unknown
* @since 0.9.17
*/
public SigType getSigType() {
if (_certificate == null)
return null;
if (_certificate.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
try {
KeyCertificate kcert = _certificate.toKeyCertificate();
return kcert.getSigType();
} catch (DataFormatException dfe) {}
}
return SigType.DSA_SHA1;
}
public PublicKey getPublicKey() { public PublicKey getPublicKey() {
return _publicKey; return _publicKey;
} }

View File

@ -91,6 +91,7 @@ tunnel.3.i2cpHost=127.0.0.1
tunnel.3.i2cpPort=7654 tunnel.3.i2cpPort=7654
tunnel.3.option.inbound.nickname=eepsite tunnel.3.option.inbound.nickname=eepsite
tunnel.3.option.outbound.nickname=eepsite tunnel.3.option.outbound.nickname=eepsite
tunnel.3.option.i2cp.destination.sigType=ECDSA_SHA256_P256
tunnel.3.option.inbound.length=3 tunnel.3.option.inbound.length=3
tunnel.3.option.inbound.lengthVariance=0 tunnel.3.option.inbound.lengthVariance=0
tunnel.3.option.outbound.length=3 tunnel.3.option.outbound.length=3