forked from I2P_Developers/i2p.i2p
i2ptunnel: Add alt names in standard and irc client tunnel certs
This commit is contained in:
@@ -14,8 +14,10 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -700,8 +702,29 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
Properties opts = getTunnel().getClientOptions();
|
||||
boolean useSSL = Boolean.parseBoolean(opts.getProperty(PROP_USE_SSL));
|
||||
if (useSSL) {
|
||||
// was already done in web/IndexBean.java when saving the config
|
||||
boolean wasCreated = SSLClientUtil.verifyKeyStore(opts);
|
||||
// was already done in GeneralHelper.updateTunnelConfig() when saving the config
|
||||
// we should never be generating the cert here.
|
||||
// add the local interface and all targets to the cert
|
||||
Set<String> altNames = new HashSet<String>(4);
|
||||
String intfc = getTunnel().listenHost;
|
||||
if (intfc != null && !intfc.equals("0.0.0.0") && !intfc.equals("::") &&
|
||||
!intfc.equals("0:0:0:0:0:0:0:0"))
|
||||
altNames.add(intfc);
|
||||
// We can't easily get to the targetDestination property,
|
||||
// or the _addrs List in I2PTunnelClient, or the target argument in I2PTunnel from here,
|
||||
// but it shouldn't matter, we should never be generating the cert here.
|
||||
//String targets = ...
|
||||
//if (targets != null) {
|
||||
// StringTokenizer tok = new StringTokenizer(targets, ", ");
|
||||
// while (tok.hasMoreTokens()) {
|
||||
// String h = tok.nextToken();
|
||||
// int colon = h.indexOf(':');
|
||||
// if (colon >= 0)
|
||||
// h = h.substring(0, colon);
|
||||
// altNames.add(h);
|
||||
// }
|
||||
//}
|
||||
boolean wasCreated = SSLClientUtil.verifyKeyStore(opts, "", altNames);
|
||||
if (wasCreated) {
|
||||
// From here, we can't save the config.
|
||||
// We shouldn't get here, as SSL isn't the default, so it would
|
||||
|
||||
@@ -6,7 +6,9 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
@@ -56,6 +58,22 @@ public class SSLClientUtil {
|
||||
* @throws IOException on creation fail
|
||||
*/
|
||||
public static boolean verifyKeyStore(Properties opts, String optPfx) throws IOException {
|
||||
return verifyKeyStore(opts, optPfx, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new selfsigned cert and keystore and pubkey cert if they don't exist.
|
||||
* May take a while.
|
||||
*
|
||||
* @param opts in/out, updated if rv is true
|
||||
* @param optPfx add this prefix when getting/setting options
|
||||
* @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
|
||||
* cname, localhost, 127.0.0.1, and ::1 will be automatically added.
|
||||
* @return false if it already exists; if true, caller must save opts
|
||||
* @throws IOException on creation fail
|
||||
* @since 0.9.34 added altNames param
|
||||
*/
|
||||
public static boolean verifyKeyStore(Properties opts, String optPfx, Set<String> altNames) throws IOException {
|
||||
String name = opts.getProperty(optPfx + PROP_KEY_ALIAS);
|
||||
if (name == null) {
|
||||
name = KeyStoreUtil.randomString();
|
||||
@@ -79,7 +97,7 @@ public class SSLClientUtil {
|
||||
if (!sdir.mkdirs())
|
||||
throw new IOException("Unable to create keystore " + ks);
|
||||
}
|
||||
boolean rv = createKeyStore(ks, name, opts, optPfx);
|
||||
boolean rv = createKeyStore(ks, name, opts, optPfx, altNames);
|
||||
if (!rv)
|
||||
throw new IOException("Unable to create keystore " + ks);
|
||||
|
||||
@@ -92,20 +110,22 @@ public class SSLClientUtil {
|
||||
|
||||
|
||||
/**
|
||||
* Call out to keytool to create a new keystore with a keypair in it.
|
||||
* Create a new keystore with a keypair in it.
|
||||
*
|
||||
* @param name used in CNAME
|
||||
* @param opts in/out, updated if rv is true, must contain PROP_KEY_ALIAS
|
||||
* @param optPfx add this prefix when getting/setting options
|
||||
* @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
|
||||
* cname, localhost, 127.0.0.1, and ::1 will be automatically added.
|
||||
* @return success, if true, opts will have password properties added to be saved
|
||||
*/
|
||||
private static boolean createKeyStore(File ks, String name, Properties opts, String optPfx) {
|
||||
private static boolean createKeyStore(File ks, String name, Properties opts, String optPfx, Set<String> altNames) {
|
||||
// make a random 48 character password (30 * 8 / 5)
|
||||
String keyPassword = KeyStoreUtil.randomString();
|
||||
String cname = "localhost";
|
||||
|
||||
String keyName = opts.getProperty(optPfx + PROP_KEY_ALIAS);
|
||||
boolean success = KeyStoreUtil.createKeys(ks, keyName, cname, "I2PTUNNEL", keyPassword);
|
||||
boolean success = KeyStoreUtil.createKeys(ks, keyName, cname, altNames, "I2PTUNNEL", keyPassword);
|
||||
if (success) {
|
||||
success = ks.exists();
|
||||
if (success) {
|
||||
@@ -115,7 +135,8 @@ public class SSLClientUtil {
|
||||
}
|
||||
if (success) {
|
||||
logAlways("Created self-signed certificate for " + cname + " in keystore: " + ks.getAbsolutePath() + "\n" +
|
||||
"The certificate was generated randomly, and is not associated with your " +
|
||||
"The certificate was generated randomly.\n" +
|
||||
"Unless you have changed the default settings, the certificate is not associated with your " +
|
||||
"IP address, host name, router identity, or destination keys.");
|
||||
} else {
|
||||
error("Failed to create I2PTunnel SSL keystore.\n" +
|
||||
|
||||
@@ -3,9 +3,11 @@ package net.i2p.i2ptunnel.ui;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
@@ -14,6 +16,7 @@ import net.i2p.client.I2PClient;
|
||||
import net.i2p.crypto.SigType;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.PrivateKeyFile;
|
||||
import net.i2p.i2ptunnel.I2PTunnelClientBase;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
||||
@@ -25,6 +28,7 @@ import net.i2p.i2ptunnel.SSLClientUtil;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
import net.i2p.i2ptunnel.web.Messages;
|
||||
import net.i2p.util.ConvertToHash;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureFile;
|
||||
@@ -94,8 +98,30 @@ public class GeneralHelper {
|
||||
// Down in I2PTunnelClientBase it's very hard to save the config.
|
||||
//
|
||||
if (Boolean.parseBoolean(props.getProperty(OPT + I2PTunnelClientBase.PROP_USE_SSL))) {
|
||||
// add the local interface and all targets to the cert
|
||||
String intfc = props.getProperty(TunnelController.PROP_INTFC);
|
||||
Set<String> altNames = new HashSet<String>(4);
|
||||
if (intfc != null && !intfc.equals("0.0.0.0") && !intfc.equals("::") &&
|
||||
!intfc.equals("0:0:0:0:0:0:0:0"))
|
||||
altNames.add(intfc);
|
||||
String tgts = props.getProperty(TunnelController.PROP_DEST);
|
||||
if (tgts != null) {
|
||||
altNames.add(intfc);
|
||||
String[] hosts = DataHelper.split(tgts, "[ ,]");
|
||||
for (String h : hosts) {
|
||||
int colon = h.indexOf(':');
|
||||
if (colon >= 0)
|
||||
h = h.substring(0, colon);
|
||||
altNames.add(h);
|
||||
if (!h.endsWith(".b32.i2p")) {
|
||||
Hash hash = ConvertToHash.getHash(h);
|
||||
if (hash != null)
|
||||
altNames.add(hash.toBase32());
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
boolean created = SSLClientUtil.verifyKeyStore(props, OPT);
|
||||
boolean created = SSLClientUtil.verifyKeyStore(props, OPT, altNames);
|
||||
if (created) {
|
||||
// config now contains new keystore props
|
||||
String name = props.getProperty(TunnelController.PROP_NAME, "");
|
||||
|
||||
Reference in New Issue
Block a user