forked from I2P_Developers/i2p.i2p
* I2CP: Move SSL client socket code to util,
move cert location to certificates/i2cp. * I2PTunnel: Support SSL for connection to local server for Standard, HTTP, and IRC server tunnels. Put server cert in certificates/i2ptunnel if necessary.
This commit is contained in:
@ -148,7 +148,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
setEntry(headers, "Accept-encoding", "");
|
||||
|
||||
socket.setReadTimeout(readTimeout);
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
Socket s = getSocket(remoteHost, remotePort);
|
||||
long afterSocket = getTunnel().getContext().clock().now();
|
||||
// instead of i2ptunnelrunner, use something that reads the HTTP
|
||||
// request from the socket, modifies the headers, sends the request to the
|
||||
|
@ -137,7 +137,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
buf.append("\r\n");
|
||||
modifiedRegistration = buf.toString();
|
||||
}
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
Socket s = getSocket(remoteHost, remotePort);
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
|
@ -14,6 +14,7 @@ import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -33,6 +34,7 @@ import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.I2PSSLSocketFactory;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
@ -43,11 +45,13 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
|
||||
private final Object lock = new Object();
|
||||
protected final Object slock = new Object();
|
||||
protected final Object sslLock = new Object();
|
||||
|
||||
protected final InetAddress remoteHost;
|
||||
protected final int remotePort;
|
||||
private final boolean _usePool;
|
||||
protected final Logging l;
|
||||
private I2PSSLSocketFactory _sslFactory;
|
||||
|
||||
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000;
|
||||
/** default timeout to 5 minutes - override if desired */
|
||||
@ -56,6 +60,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
/** do we use threads? default true (ignored for standard servers, always false) */
|
||||
private static final String PROP_USE_POOL = "i2ptunnel.usePool";
|
||||
private static final boolean DEFAULT_USE_POOL = true;
|
||||
public static final String PROP_USE_SSL = "useSSL";
|
||||
/** apparently unused */
|
||||
protected static volatile long __serverId = 0;
|
||||
/** max number of threads - this many slowlorisses will DOS this server, but too high could OOM the JVM */
|
||||
@ -462,17 +467,17 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Incoming connection to '" + toString() + "' port " + socket.getLocalPort() +
|
||||
" from: " + socket.getPeerDestination().calculateHash() + " port " + socket.getPort());
|
||||
long afterAccept = I2PAppContext.getGlobalContext().clock().now();
|
||||
long afterAccept = getTunnel().getContext().clock().now();
|
||||
long afterSocket = -1;
|
||||
//local is fast, so synchronously. Does not need that many
|
||||
//threads.
|
||||
try {
|
||||
socket.setReadTimeout(readTimeout);
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
afterSocket = I2PAppContext.getGlobalContext().clock().now();
|
||||
Socket s = getSocket(remoteHost, remotePort);
|
||||
afterSocket = getTunnel().getContext().clock().now();
|
||||
new I2PTunnelRunner(s, socket, slock, null, null);
|
||||
|
||||
long afterHandle = I2PAppContext.getGlobalContext().clock().now();
|
||||
long afterHandle = getTunnel().getContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
|
||||
@ -487,5 +492,31 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a regular or SSL socket depending on config
|
||||
*
|
||||
* @since 0.9.9
|
||||
*/
|
||||
protected Socket getSocket(InetAddress remoteHost, int remotePort) throws IOException {
|
||||
String opt = getTunnel().getClientOptions().getProperty(PROP_USE_SSL);
|
||||
if (Boolean.parseBoolean(opt)) {
|
||||
synchronized(sslLock) {
|
||||
if (_sslFactory == null) {
|
||||
try {
|
||||
_sslFactory = new I2PSSLSocketFactory(getTunnel().getContext(),
|
||||
true, "certificates/i2ptunnel");
|
||||
} catch (GeneralSecurityException gse) {
|
||||
IOException ioe = new IOException("SSL Fail");
|
||||
ioe.initCause(gse);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _sslFactory.createSocket(remoteHost, remotePort);
|
||||
} else {
|
||||
return new Socket(remoteHost, remotePort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -407,7 +407,7 @@ public class TunnelController implements Logging {
|
||||
/**
|
||||
* These are the ones stored with a prefix of "option."
|
||||
*
|
||||
* @return keys with the "option." prefix stripped
|
||||
* @return keys with the "option." prefix stripped, non-null
|
||||
* @since 0.9.1 Much better than getClientOptions()
|
||||
*/
|
||||
public Properties getClientOptionProps() {
|
||||
|
@ -31,6 +31,7 @@ import net.i2p.i2ptunnel.I2PTunnelConnectClient;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
|
||||
import net.i2p.i2ptunnel.I2PTunnelIRCClient;
|
||||
import net.i2p.i2ptunnel.I2PTunnelServer;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
import net.i2p.util.Addresses;
|
||||
@ -770,6 +771,21 @@ public class IndexBean {
|
||||
_booleanOptions.add(I2PTunnelIRCClient.PROP_DCC);
|
||||
}
|
||||
|
||||
/** @since 0.9.9 */
|
||||
public void setUseSSL(String moo) {
|
||||
_booleanOptions.add(I2PTunnelServer.PROP_USE_SSL);
|
||||
}
|
||||
|
||||
/** @since 0.9.9 */
|
||||
public boolean isSSLEnabled(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
Properties opts = tun.getClientOptionProps();
|
||||
return Boolean.parseBoolean(opts.getProperty(I2PTunnelServer.PROP_USE_SSL));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
|
||||
protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
|
||||
|
||||
@ -1149,7 +1165,8 @@ public class IndexBean {
|
||||
I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH
|
||||
};
|
||||
private static final String _booleanServerOpts[] = {
|
||||
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST
|
||||
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST,
|
||||
I2PTunnelServer.PROP_USE_SSL
|
||||
};
|
||||
private static final String _otherClientOpts[] = {
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
|
||||
|
@ -121,6 +121,14 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
|
||||
</label>
|
||||
<input type="text" size="6" maxlength="5" id="targetPort" name="targetPort" title="Target Port Number" value="<%=editBean.getTargetPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<% if (!"streamrserver".equals(tunnelType)) { %>
|
||||
<div id="portField" class="rowItem">
|
||||
<label>
|
||||
<%=intl._("Use SSL?")%>
|
||||
</label>
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="useSSL" title="Use SSL to connect to target" <%=(editBean.isSSLEnabled(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
</div>
|
||||
<% } /* !streamrserver */ %>
|
||||
|
||||
<% if ("httpbidirserver".equals(tunnelType)) { %>
|
||||
<div class="subdivider">
|
||||
|
@ -114,12 +114,19 @@
|
||||
<span class="text">
|
||||
<%
|
||||
if (indexBean.isServerTargetLinkValid(curServer)) {
|
||||
%>
|
||||
<a href="http://<%=indexBean.getServerTarget(curServer)%>/" title="Test HTTP server, bypassing I2P" target="_top"><%=indexBean.getServerTarget(curServer)%></a>
|
||||
if (indexBean.isSSLEnabled(curServer)) { %>
|
||||
<a href="https://<%=indexBean.getServerTarget(curServer)%>/" title="Test HTTPS server, bypassing I2P" target="_top"><%=indexBean.getServerTarget(curServer)%> SSL</a>
|
||||
<% } else { %>
|
||||
<a href="http://<%=indexBean.getServerTarget(curServer)%>/" title="Test HTTP server, bypassing I2P" target="_top"><%=indexBean.getServerTarget(curServer)%></a>
|
||||
<%
|
||||
}
|
||||
} else {
|
||||
%><%=indexBean.getServerTarget(curServer)%>
|
||||
<%
|
||||
if (indexBean.isSSLEnabled(curServer)) { %>
|
||||
SSL
|
||||
<%
|
||||
}
|
||||
}
|
||||
%></span>
|
||||
</div>
|
||||
|
@ -1,119 +0,0 @@
|
||||
package net.i2p.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.security.KeyStore;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.KeyStoreUtil;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Loads trusted ASCII certs from ~/.i2p/certificates/ and $CWD/certificates/.
|
||||
* Keeps a single static SSLContext for the whole JVM.
|
||||
*
|
||||
* @author zzz
|
||||
* @since 0.8.3
|
||||
*/
|
||||
class I2CPSSLSocketFactory {
|
||||
|
||||
private static final Object _initLock = new Object();
|
||||
private static SSLSocketFactory _factory;
|
||||
|
||||
private static final String CERT_DIR = "certificates";
|
||||
|
||||
/**
|
||||
* Initializes the static SSL Context if required, then returns a socket
|
||||
* to the host.
|
||||
*
|
||||
* @param ctx just for logging
|
||||
* @throws IOException on init error or usual socket errors
|
||||
*/
|
||||
public static Socket createSocket(I2PAppContext ctx, String host, int port) throws IOException {
|
||||
synchronized(_initLock) {
|
||||
if (_factory == null) {
|
||||
initSSLContext(ctx);
|
||||
if (_factory == null)
|
||||
throw new IOException("Unable to create SSL Context for I2CP Client");
|
||||
info(ctx, "I2CP Client-side SSL Context initialized");
|
||||
}
|
||||
}
|
||||
return _factory.createSocket(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads certs from
|
||||
* the ~/.i2p/certificates/ and $CWD/certificates/ directories.
|
||||
*/
|
||||
private static void initSSLContext(I2PAppContext context) {
|
||||
KeyStore ks;
|
||||
try {
|
||||
ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
ks.load(null, "".toCharArray());
|
||||
} catch (GeneralSecurityException gse) {
|
||||
error(context, "Key Store init error", gse);
|
||||
return;
|
||||
} catch (IOException ioe) {
|
||||
error(context, "Key Store init error", ioe);
|
||||
return;
|
||||
}
|
||||
|
||||
File dir = new File(context.getConfigDir(), CERT_DIR);
|
||||
int adds = KeyStoreUtil.addCerts(dir, ks);
|
||||
int totalAdds = adds;
|
||||
if (adds > 0)
|
||||
info(context, "Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||
|
||||
File dir2 = new File(System.getProperty("user.dir"), CERT_DIR);
|
||||
if (!dir.getAbsolutePath().equals(dir2.getAbsolutePath())) {
|
||||
adds = KeyStoreUtil.addCerts(dir2, ks);
|
||||
totalAdds += adds;
|
||||
if (adds > 0)
|
||||
info(context, "Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||
}
|
||||
if (totalAdds > 0) {
|
||||
info(context, "Loaded total of " + totalAdds + " new trusted certificates");
|
||||
} else {
|
||||
error(context, "No trusted certificates loaded (looked in " +
|
||||
dir.getAbsolutePath() + (dir.getAbsolutePath().equals(dir2.getAbsolutePath()) ? "" : (" and " + dir2.getAbsolutePath())) +
|
||||
", I2CP SSL client connections will fail. " +
|
||||
"Copy the file certificates/i2cp.local.crt from the router to the directory.", null);
|
||||
// don't continue, since we didn't load the system keystore, we have nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SSLContext sslc = SSLContext.getInstance("TLS");
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(ks);
|
||||
sslc.init(null, tmf.getTrustManagers(), context.random());
|
||||
_factory = sslc.getSocketFactory();
|
||||
} catch (GeneralSecurityException gse) {
|
||||
error(context, "SSL context init error", gse);
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 0.9.8 */
|
||||
private static void info(I2PAppContext ctx, String msg) {
|
||||
log(ctx, Log.INFO, msg, null);
|
||||
}
|
||||
|
||||
/** @since 0.9.8 */
|
||||
private static void error(I2PAppContext ctx, String msg, Throwable t) {
|
||||
log(ctx, Log.ERROR, msg, t);
|
||||
}
|
||||
|
||||
/** @since 0.9.8 */
|
||||
private static void log(I2PAppContext ctx, int level, String msg, Throwable t) {
|
||||
Log l = ctx.logManager().getLog(I2CPSSLSocketFactory.class);
|
||||
l.log(level, msg, t);
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -43,6 +44,7 @@ import net.i2p.internal.I2CPMessageQueue;
|
||||
import net.i2p.internal.InternalClientManager;
|
||||
import net.i2p.internal.QueuedI2CPMessageReader;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.I2PSSLSocketFactory;
|
||||
import net.i2p.util.LHMCache;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
@ -438,10 +440,18 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
_queue = mgr.connect();
|
||||
_reader = new QueuedI2CPMessageReader(_queue, this);
|
||||
} else {
|
||||
if (Boolean.parseBoolean(_options.getProperty(PROP_ENABLE_SSL)))
|
||||
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
|
||||
else
|
||||
if (Boolean.parseBoolean(_options.getProperty(PROP_ENABLE_SSL))) {
|
||||
try {
|
||||
I2PSSLSocketFactory fact = new I2PSSLSocketFactory(_context, false, "certificates/i2cp");
|
||||
_socket = fact.createSocket(_hostname, _portNum);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
IOException ioe = new IOException("SSL Fail");
|
||||
ioe.initCause(gse);
|
||||
throw ioe;
|
||||
}
|
||||
} else {
|
||||
_socket = new Socket(_hostname, _portNum);
|
||||
}
|
||||
// _socket.setSoTimeout(1000000); // Uhmmm we could really-really use a real timeout, and handle it.
|
||||
OutputStream out = _socket.getOutputStream();
|
||||
out.write(I2PClient.PROTOCOL_BYTE);
|
||||
|
@ -11,6 +11,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
@ -19,6 +20,7 @@ import net.i2p.data.i2cp.DestReplyMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessageReader;
|
||||
import net.i2p.internal.InternalClientManager;
|
||||
import net.i2p.internal.QueuedI2CPMessageReader;
|
||||
import net.i2p.util.I2PSSLSocketFactory;
|
||||
|
||||
/**
|
||||
* Create a new session for doing naming and bandwidth queries only. Do not create a Destination.
|
||||
@ -67,10 +69,18 @@ class I2PSimpleSession extends I2PSessionImpl2 {
|
||||
_queue = mgr.connect();
|
||||
_reader = new QueuedI2CPMessageReader(_queue, this);
|
||||
} else {
|
||||
if (Boolean.parseBoolean(getOptions().getProperty(PROP_ENABLE_SSL)))
|
||||
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
|
||||
else
|
||||
if (Boolean.parseBoolean(getOptions().getProperty(PROP_ENABLE_SSL))) {
|
||||
try {
|
||||
I2PSSLSocketFactory fact = new I2PSSLSocketFactory(_context, false, "certificates/i2cp");
|
||||
_socket = fact.createSocket(_hostname, _portNum);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
IOException ioe = new IOException("SSL Fail");
|
||||
ioe.initCause(gse);
|
||||
throw ioe;
|
||||
}
|
||||
} else {
|
||||
_socket = new Socket(_hostname, _portNum);
|
||||
}
|
||||
OutputStream out = _socket.getOutputStream();
|
||||
out.write(I2PClient.PROTOCOL_BYTE);
|
||||
out.flush();
|
||||
|
109
core/java/src/net/i2p/util/I2PSSLSocketFactory.java
Normal file
109
core/java/src/net/i2p/util/I2PSSLSocketFactory.java
Normal file
@ -0,0 +1,109 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.KeyStore;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.KeyStoreUtil;
|
||||
|
||||
/**
|
||||
* Loads trusted ASCII certs from ~/.i2p/certificates/ and $I2P/certificates/.
|
||||
*
|
||||
* @author zzz
|
||||
* @since 0.9.9 moved from ../client, original since 0.8.3
|
||||
*/
|
||||
public class I2PSSLSocketFactory {
|
||||
|
||||
private final SSLSocketFactory _factory;
|
||||
|
||||
/**
|
||||
* @param relativeCertPath e.g. "certificates/i2cp"
|
||||
* @since 0.9.9 was static
|
||||
*/
|
||||
public I2PSSLSocketFactory(I2PAppContext context, boolean loadSystemCerts, String relativeCertPath)
|
||||
throws GeneralSecurityException {
|
||||
_factory = initSSLContext(context, loadSystemCerts, relativeCertPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a socket to the host.
|
||||
*/
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
return _factory.createSocket(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a socket to the host.
|
||||
* @since 0.9.9
|
||||
*/
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
return _factory.createSocket(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads certs from
|
||||
* the ~/.i2p/certificates/ and $I2P/certificates/ directories.
|
||||
*/
|
||||
private SSLSocketFactory initSSLContext(I2PAppContext context, boolean loadSystemCerts, String relativeCertPath)
|
||||
throws GeneralSecurityException {
|
||||
Log log = context.logManager().getLog(I2PSSLSocketFactory.class);
|
||||
KeyStore ks;
|
||||
if (loadSystemCerts) {
|
||||
ks = KeyStoreUtil.loadSystemKeyStore();
|
||||
if (ks == null)
|
||||
throw new GeneralSecurityException("Key Store init error");
|
||||
} else {
|
||||
try {
|
||||
ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
ks.load(null, "".toCharArray());
|
||||
} catch (IOException ioe) {
|
||||
throw new GeneralSecurityException("Key Store init error", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
File dir = new File(context.getConfigDir(), relativeCertPath);
|
||||
int adds = KeyStoreUtil.addCerts(dir, ks);
|
||||
int totalAdds = adds;
|
||||
if (adds > 0) {
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||
}
|
||||
|
||||
File dir2 = new File(context.getBaseDir(), relativeCertPath);
|
||||
if (!dir.getAbsolutePath().equals(dir2.getAbsolutePath())) {
|
||||
adds = KeyStoreUtil.addCerts(dir2, ks);
|
||||
totalAdds += adds;
|
||||
if (adds > 0) {
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
if (totalAdds > 0 || loadSystemCerts) {
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("Loaded total of " + totalAdds + " new trusted certificates");
|
||||
} else {
|
||||
String msg = "No trusted certificates loaded (looked in " +
|
||||
dir.getAbsolutePath() + (dir.getAbsolutePath().equals(dir2.getAbsolutePath()) ? "" : (" and " + dir2.getAbsolutePath())) +
|
||||
", SSL connections will fail. " +
|
||||
"Copy the cert in " + relativeCertPath + " from the router to the directory.";
|
||||
// don't continue, since we didn't load the system keystore, we have nothing.
|
||||
throw new GeneralSecurityException(msg);
|
||||
}
|
||||
|
||||
SSLContext sslc = SSLContext.getInstance("TLS");
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(ks);
|
||||
sslc.init(null, tmf.getTrustManagers(), context.random());
|
||||
return sslc.getSocketFactory();
|
||||
}
|
||||
}
|
@ -118,8 +118,8 @@ class SSLClientListenerRunner extends ClientListenerRunner {
|
||||
* so the clients can get to it.
|
||||
*/
|
||||
private void exportCert(File ks) {
|
||||
File sdir = new SecureDirectory(_context.getConfigDir(), "certificates");
|
||||
if (sdir.exists() || sdir.mkdir()) {
|
||||
File sdir = new SecureDirectory(_context.getConfigDir(), "certificates/i2cp");
|
||||
if (sdir.exists() || sdir.mkdirs()) {
|
||||
String ksPass = _context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
|
||||
File out = new File(sdir, ASCII_KEYFILE);
|
||||
boolean success = KeyStoreUtil.exportCert(ks, ksPass, KEY_ALIAS, out);
|
||||
|
Reference in New Issue
Block a user