summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2009-01-06 15:27:35 -0800
committerMark Spruiell <mes@zeroc.com>2009-01-06 15:27:35 -0800
commit799ae412e223c9fd232df54c23e7abcdba4f9968 (patch)
tree35be16ebb9110c60a7e763166e2d02c635ea21a1
parentanother fix for bug 3628 (diff)
downloadice-799ae412e223c9fd232df54c23e7abcdba4f9968.tar.bz2
ice-799ae412e223c9fd232df54c23e7abcdba4f9968.tar.xz
ice-799ae412e223c9fd232df54c23e7abcdba4f9968.zip
- Another fix for bug 3628
- Porting IceSSL changes from Android branch
-rw-r--r--CHANGES10
-rw-r--r--java/src/IceSSL/ConnectionInfo.java4
-rw-r--r--java/src/IceSSL/Instance.java219
-rw-r--r--java/src/IceSSL/Plugin.java24
-rw-r--r--java/src/IceSSL/PluginI.java18
5 files changed, 216 insertions, 59 deletions
diff --git a/CHANGES b/CHANGES
index 78f08291135..3d4c45eb3c0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -59,6 +59,16 @@ C++ Changes
incorrectly be sent compressed or not compressed.
+Java Changes
+============
+
+- Added methods to the IceSSL plug-in to allow keystores, truststores,
+ and RNG seeds to be specified using input streams.
+
+- Fixed the IceSSL.ConnectionInfo type so that the "incoming" and
+ "adapterName" members are public.
+
+
C# Changes
==========
diff --git a/java/src/IceSSL/ConnectionInfo.java b/java/src/IceSSL/ConnectionInfo.java
index 53433eb4e3d..5e10a24bec8 100644
--- a/java/src/IceSSL/ConnectionInfo.java
+++ b/java/src/IceSSL/ConnectionInfo.java
@@ -42,11 +42,11 @@ public class ConnectionInfo
// If the connection is incoming this bool is true, false
// otherwise.
//
- boolean incoming;
+ public boolean incoming;
//
// The name of the object adapter that hosts this endpoint, if
// any.
//
- String adapterName;
+ public String adapterName;
}
diff --git a/java/src/IceSSL/Instance.java b/java/src/IceSSL/Instance.java
index 9c950bae453..afddf43071a 100644
--- a/java/src/IceSSL/Instance.java
+++ b/java/src/IceSSL/Instance.java
@@ -9,6 +9,12 @@
package IceSSL;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import Ice.Logger;
+
class Instance
{
Instance(Ice.Communicator communicator)
@@ -19,7 +25,7 @@ class Instance
_securityTraceCategory = "Security";
_trustManager = new TrustManager(communicator);
- //
+ //
// Register the endpoint factory. We have to do this now, rather than
// in initialize, because the communicator may need to interpret
// proxies before the plug-in is fully initialized.
@@ -31,7 +37,7 @@ class Instance
initialize()
{
if(_initialized)
- {
+ {
return;
}
@@ -89,12 +95,12 @@ class Instance
//
_verifyDepthMax = properties.getPropertyAsIntWithDefault(prefix + "VerifyDepthMax", 2);
- //
+ //
// Check for a certificate verifier.
- //
+ //
final String certVerifierClass = properties.getProperty(prefix + "CertVerifier");
if(certVerifierClass.length() > 0)
- {
+ {
if(_verifier != null)
{
Ice.PluginInitializationException e = new Ice.PluginInitializationException();
@@ -200,8 +206,6 @@ class Instance
final String seedFiles = properties.getProperty(prefix + "Random");
if(seedFiles.length() > 0)
{
- byte[] seed = null;
- int start = 0;
final String[] arr = seedFiles.split(java.io.File.pathSeparator);
for(int i = 0; i < arr.length; ++i)
{
@@ -213,34 +217,54 @@ class Instance
throw e;
}
java.io.File f = new java.io.File(seedFile.value);
- int num = (int)f.length();
- if(seed == null)
+ try
{
- seed = new byte[num];
+ _seeds.add(new java.io.FileInputStream(f));
}
- else
+ catch(java.io.IOException ex)
{
- byte[] tmp = new byte[seed.length + num];
- System.arraycopy(seed, 0, tmp, 0, seed.length);
- start = seed.length;
- seed = tmp;
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: error while reading random seed file:\n" + arr[i];
+ e.initCause(ex);
+ throw e;
}
+ }
+ }
+
+ if(!_seeds.isEmpty())
+ {
+ byte[] seed = null;
+ int start = 0;
+ for(java.util.Iterator<InputStream> p = _seeds.iterator(); p.hasNext();)
+ {
+ InputStream in = p.next();
try
{
- java.io.FileInputStream in = new java.io.FileInputStream(f);
+ int num = in.available();
+ if(seed == null)
+ {
+ seed = new byte[num];
+ }
+ else
+ {
+ byte[] tmp = new byte[seed.length + num];
+ System.arraycopy(seed, 0, tmp, 0, seed.length);
+ start = seed.length;
+ seed = tmp;
+ }
in.read(seed, start, num);
- in.close();
}
catch(java.io.IOException ex)
{
Ice.PluginInitializationException e = new Ice.PluginInitializationException();
- e.reason = "IceSSL: error while reading random seed file:\n" + arr[i];
+ e.reason = "IceSSL: error while reading random seed";
e.initCause(ex);
throw e;
}
}
rand.setSeed(seed);
}
+ _seeds.clear();
//
// We call nextInt() in order to force the object to perform any time-consuming
@@ -264,7 +288,8 @@ class Instance
String keystorePassword = properties.getProperty(prefix + "KeystorePassword");
//
- // The default keystore type value is "JKS", but it can also be "PKCS12".
+ // The default keystore type is usually "JKS", but the legal values are determined
+ // by the JVM implementation. Other possibilities include "PKCS12" and "BKS".
//
final String defaultType = java.security.KeyStore.getDefaultType();
final String keystoreType = properties.getPropertyWithDefault(prefix + "KeystoreType", defaultType);
@@ -285,7 +310,8 @@ class Instance
String truststorePassword = properties.getProperty(prefix + "TruststorePassword");
//
- // The truststore type defaults to "JKS", but it can also be "PKCS12".
+ // The default truststore type is usually "JKS", but the legal values are determined
+ // by the JVM implementation. Other possibilities include "PKCS12" and "BKS".
//
final String truststoreType =
properties.getPropertyWithDefault(prefix + "TruststoreType",
@@ -295,15 +321,16 @@ class Instance
// Collect the key managers.
//
javax.net.ssl.KeyManager[] keyManagers = null;
- if(keystorePath.value.length() > 0)
+ java.security.KeyStore keys = null;
+ if(_keystoreStream != null || keystorePath.value.length() > 0)
{
- if(!checkPath(keystorePath, false))
+ if(_keystoreStream == null && !checkPath(keystorePath, false))
{
Ice.PluginInitializationException e = new Ice.PluginInitializationException();
e.reason = "IceSSL: keystore file not found:\n" + keystorePath.value;
throw e;
}
- java.security.KeyStore keys = java.security.KeyStore.getInstance(keystoreType);
+ keys = java.security.KeyStore.getInstance(keystoreType);
try
{
char[] passwordChars = null;
@@ -315,9 +342,21 @@ class Instance
{
passwordChars = _passwordCallback.getKeystorePassword();
}
+ else if(keystoreType.equals("BKS"))
+ {
+ // Bouncy Castle does not permit null passwords.
+ passwordChars = new char[0];
+ }
- java.io.BufferedInputStream bis =
- new java.io.BufferedInputStream(new java.io.FileInputStream(keystorePath.value));
+ java.io.InputStream bis;
+ if(_keystoreStream != null)
+ {
+ bis = _keystoreStream;
+ }
+ else
+ {
+ bis = new java.io.BufferedInputStream(new java.io.FileInputStream(keystorePath.value));
+ }
keys.load(bis, passwordChars);
if(passwordChars != null)
@@ -337,7 +376,7 @@ class Instance
String algorithm = javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm();
javax.net.ssl.KeyManagerFactory kmf = javax.net.ssl.KeyManagerFactory.getInstance(algorithm);
char[] passwordChars = new char[0]; // This password cannot be null.
- if(password.length() > 0)
+ if(password.length() > 0)
{
passwordChars = password.toCharArray();
}
@@ -377,43 +416,71 @@ class Instance
// Collect the trust managers.
//
javax.net.ssl.TrustManager[] trustManagers = null;
- if(truststorePath.value.length() > 0)
+ if(_truststoreStream != null || truststorePath.value.length() > 0)
{
- if(!checkPath(truststorePath, false))
+ if(_truststoreStream == null && !checkPath(truststorePath, false))
{
Ice.PluginInitializationException e = new Ice.PluginInitializationException();
e.reason = "IceSSL: truststore file not found:\n" + truststorePath.value;
throw e;
}
- java.security.KeyStore ts = java.security.KeyStore.getInstance(truststoreType);
- try
+
+ //
+ // If the trust store and the key store are the same input
+ // stream or file, don't create another key store.
+ //
+ java.security.KeyStore ts;
+ if((_truststoreStream != null && _truststoreStream == _keystoreStream) ||
+ (truststorePath.value.length() > 0 && truststorePath.value.equals(keystorePath.value)))
{
- char[] passwordChars = null;
- if(truststorePassword.length() > 0)
- {
- passwordChars = truststorePassword.toCharArray();
- }
- else if(_passwordCallback != null)
+ assert keys != null;
+ ts = keys;
+ }
+ else
+ {
+ ts = java.security.KeyStore.getInstance(truststoreType);
+ try
{
- passwordChars = _passwordCallback.getTruststorePassword();
- }
+ char[] passwordChars = null;
+ if(truststorePassword.length() > 0)
+ {
+ passwordChars = truststorePassword.toCharArray();
+ }
+ else if(_passwordCallback != null)
+ {
+ passwordChars = _passwordCallback.getTruststorePassword();
+ }
+ else if(truststoreType.equals("BKS"))
+ {
+ // Bouncy Castle does not permit null passwords.
+ passwordChars = new char[0];
+ }
- java.io.BufferedInputStream bis =
- new java.io.BufferedInputStream(new java.io.FileInputStream(truststorePath.value));
- ts.load(bis, passwordChars);
+ java.io.InputStream bis;
+ if(_truststoreStream != null)
+ {
+ bis = _truststoreStream;
+ }
+ else
+ {
+ bis = new java.io.BufferedInputStream(
+ new java.io.FileInputStream(truststorePath.value));
+ }
+ ts.load(bis, passwordChars);
- if(passwordChars != null)
+ if(passwordChars != null)
+ {
+ java.util.Arrays.fill(passwordChars, '\0');
+ }
+ truststorePassword = null;
+ }
+ catch(java.io.IOException ex)
{
- java.util.Arrays.fill(passwordChars, '\0');
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unable to load truststore:\n" + truststorePath.value;
+ e.initCause(ex);
+ throw e;
}
- truststorePassword = null;
- }
- catch(java.io.IOException ex)
- {
- Ice.PluginInitializationException e = new Ice.PluginInitializationException();
- e.reason = "IceSSL: unable to load truststore:\n" + truststorePath.value;
- e.initCause(ex);
- throw e;
}
String algorithm = javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm();
@@ -442,7 +509,7 @@ class Instance
//
// Initialize the SSL context.
//
- _context = javax.net.ssl.SSLContext.getInstance("SSL");
+ _context = javax.net.ssl.SSLContext.getInstance("TLS");
_context.init(keyManagers, trustManagers, rand);
}
catch(java.security.GeneralSecurityException ex)
@@ -454,6 +521,13 @@ class Instance
}
}
+ //
+ // Clear cached input streams.
+ //
+ _seeds.clear();
+ _keystoreStream = null;
+ _truststoreStream = null;
+
_initialized = true;
}
@@ -500,6 +574,38 @@ class Instance
return _passwordCallback;
}
+ void
+ setKeystoreStream(java.io.InputStream stream)
+ {
+ if(_initialized)
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: plugin is already initialized";
+ throw ex;
+ }
+
+ _keystoreStream = stream;
+ }
+
+ void
+ setTruststoreStream(java.io.InputStream stream)
+ {
+ if(_initialized)
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: plugin is already initialized";
+ throw ex;
+ }
+
+ _truststoreStream = stream;
+ }
+
+ void
+ addSeedStream(java.io.InputStream stream)
+ {
+ _seeds.add(stream);
+ }
+
Ice.Communicator
communicator()
{
@@ -713,7 +819,6 @@ class Instance
return _protocols;
}
- // TODO: Remove
void
traceConnection(java.nio.channels.SocketChannel fd, javax.net.ssl.SSLEngine engine, boolean incoming)
{
@@ -861,12 +966,12 @@ class Instance
{
String msg = (incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier\n" +
IceInternal.Network.fdToString(fd);
-
+
if(_securityTraceLevel > 0)
{
_logger.trace(_securityTraceCategory, msg);
}
-
+
Ice.SecurityException ex = new Ice.SecurityException();
ex.reason = msg;
throw ex;
@@ -1004,4 +1109,8 @@ class Instance
private CertificateVerifier _verifier;
private PasswordCallback _passwordCallback;
private TrustManager _trustManager;
+
+ private InputStream _keystoreStream;
+ private InputStream _truststoreStream;
+ private List<InputStream> _seeds = new ArrayList<InputStream>();
}
diff --git a/java/src/IceSSL/Plugin.java b/java/src/IceSSL/Plugin.java
index 86ef11d74f8..7e7aabf5651 100644
--- a/java/src/IceSSL/Plugin.java
+++ b/java/src/IceSSL/Plugin.java
@@ -19,7 +19,7 @@ public interface Plugin extends Ice.Plugin
//
// When the application supplies its own SSL context, the
// plug-in skips its normal property-based configuration.
- //
+ //
void setContext(javax.net.ssl.SSLContext context);
//
@@ -28,7 +28,7 @@ public interface Plugin extends Ice.Plugin
//
javax.net.ssl.SSLContext getContext();
- //
+ //
// Establish the certificate verifier object. This should be
// done before any connections are established.
//
@@ -51,4 +51,24 @@ public interface Plugin extends Ice.Plugin
// callback is set.
//
PasswordCallback getPasswordCallback();
+
+ //
+ // Supplies an input stream for the keystore. Calling this method
+ // causes IceSSL to ignore the IceSSL.Keystore property.
+ //
+ void setKeystoreStream(java.io.InputStream stream);
+
+ //
+ // Supplies an input stream for the truststore. Calling this method
+ // causes IceSSL to ignore the IceSSL.Truststore property. It is
+ // legal to supply the same input stream as setKeystoreStream, in
+ // which case IceSSL uses the certificates contained in the keystore.
+ //
+ void setTruststoreStream(java.io.InputStream stream);
+
+ //
+ // Add an input stream for the random number seed. You may call
+ // this method multiple times if necessary.
+ //
+ void addSeedStream(java.io.InputStream stream);
}
diff --git a/java/src/IceSSL/PluginI.java b/java/src/IceSSL/PluginI.java
index 2e9ac2427f8..cb5cc915bc6 100644
--- a/java/src/IceSSL/PluginI.java
+++ b/java/src/IceSSL/PluginI.java
@@ -64,5 +64,23 @@ class PluginI implements Plugin
return _instance.getPasswordCallback();
}
+ public void
+ setKeystoreStream(java.io.InputStream stream)
+ {
+ _instance.setKeystoreStream(stream);
+ }
+
+ public void
+ setTruststoreStream(java.io.InputStream stream)
+ {
+ _instance.setTruststoreStream(stream);
+ }
+
+ public void
+ addSeedStream(java.io.InputStream stream)
+ {
+ _instance.addSeedStream(stream);
+ }
+
private Instance _instance;
}