summaryrefslogtreecommitdiff
path: root/java/src/IceSSL/Context.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/IceSSL/Context.java')
-rw-r--r--java/src/IceSSL/Context.java453
1 files changed, 337 insertions, 116 deletions
diff --git a/java/src/IceSSL/Context.java b/java/src/IceSSL/Context.java
index 5c99702d5e9..7db3d6450eb 100644
--- a/java/src/IceSSL/Context.java
+++ b/java/src/IceSSL/Context.java
@@ -11,152 +11,212 @@ package IceSSL;
class Context
{
- Context(String ciphers, String keystore, String password, String keystorePassword, String certs,
- String certsPassword, java.security.SecureRandom rand)
+ Context(Instance instance, boolean client, javax.net.ssl.SSLContext context, java.security.SecureRandom rand)
throws java.security.GeneralSecurityException
{
- java.util.ArrayList cipherList = new java.util.ArrayList();
+ _instance = instance;
+ _logger = instance.communicator().getLogger();
+
+ final String prefix = client ? "IceSSL.Client." : "IceSSL.Server.";
+ Ice.Properties properties = instance.communicator().getProperties();
+ String ciphers = properties.getProperty(prefix + "Ciphers");
+
if(ciphers.length() > 0)
{
- String[] expr = ciphers.split("[ \t]+");
- for(int i = 0; i < expr.length; ++i)
+ parseCiphers(ciphers);
+ }
+
+ //
+ // If the user doesn't supply an SSLContext, we need to create one based
+ // on property settings.
+ //
+ _ctx = context;
+ if(_ctx == null)
+ {
+ //
+ // Check for a default directory. We look in this directory for
+ // files mentioned in the configuration.
+ //
+ _defaultDir = properties.getProperty(prefix + "DefaultDir");
+
+ //
+ // The keystore holds private keys and associated certificates.
+ //
+ Ice.StringHolder keystorePath = new Ice.StringHolder(properties.getProperty(prefix + "Keystore"));
+
+ //
+ // The password for the keys.
+ //
+ final String password = properties.getProperty(prefix + "Password");
+
+ //
+ // The password for the keystore.
+ //
+ final String keystorePassword = properties.getProperty(prefix + "KeystorePassword");
+
+ //
+ // The default keystore type value is "JKS", but it can also be "PKCS12".
+ //
+ final String defaultType = java.security.KeyStore.getDefaultType();
+ final String keystoreType = properties.getPropertyWithDefault(prefix + "KeystoreType", defaultType);
+
+ //
+ // The alias of the key to use in authentication.
+ //
+ final String alias = properties.getProperty(prefix + "Alias");
+
+ //
+ // The truststore holds the certificates of trusted CAs.
+ //
+ Ice.StringHolder truststorePath = new Ice.StringHolder(
+ properties.getPropertyWithDefault(prefix + "Truststore", properties.getProperty(prefix + "Certs")));
+
+ //
+ // The password for the truststore.
+ //
+ final String truststorePassword =
+ properties.getPropertyWithDefault(prefix + "TruststorePassword",
+ properties.getProperty(prefix + "CertsPassword"));
+
+ //
+ // The truststore type defaults to "JKS", but it can also be "PKCS12".
+ //
+ String truststoreType =
+ properties.getPropertyWithDefault(prefix + "TruststoreType", java.security.KeyStore.getDefaultType());
+
+ //
+ // Parse the enabled protocols.
+ //
+ String protocols = properties.getProperty(prefix + "Protocols");
+ if(protocols.length() > 0)
{
- if(expr[i].equals("ALL"))
+ java.util.ArrayList l = new java.util.ArrayList();
+ String[] arr = protocols.split("[ \t,]+");
+ for(int i = 0; i < arr.length; ++i)
{
- if(i != 0)
+ String s = arr[i].toLowerCase();
+ if(s.equals("ssl3") || s.equals("sslv3"))
{
- Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
- ex.reason = "IceSSL: `ALL' must be first in cipher list `" + ciphers + "'";
- throw ex;
+ l.add("SSLv3");
}
- _allCiphers = true;
- }
- else if(expr[i].equals("NONE"))
- {
- if(i != 0)
+ else if(s.equals("tls") || s.equals("tls1") || s.equals("tlsv1"))
{
- Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
- ex.reason = "IceSSL: `NONE' must be first in cipher list `" + ciphers + "'";
- throw ex;
+ l.add("TLSv1");
+ }
+ else
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unrecognized protocol `" + arr[i] + "'";
+ throw e;
}
- _noCiphers = true;
}
- else
+ _protocols = new String[l.size()];
+ l.toArray(_protocols);
+ }
+
+ //
+ // Collect the key managers.
+ //
+ javax.net.ssl.KeyManager[] keyManagers = null;
+ if(keystorePath.value.length() > 0)
+ {
+ if(!checkPath(keystorePath, false))
{
- CipherExpression ce = new CipherExpression();
- String exp = expr[i];
- if(exp.charAt(0) == '!')
+ 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);
+ try
+ {
+ char[] passwordChars = null;
+ if(keystorePassword.length() > 0)
{
- ce.not = true;
- if(exp.length() > 1)
- {
- exp = exp.substring(1);
- }
- else
- {
- Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
- ex.reason = "IceSSL: invalid cipher expression `" + exp + "'";
- throw ex;
- }
+ passwordChars = keystorePassword.toCharArray();
}
- if(exp.charAt(0) == '(')
- {
- if(!exp.endsWith(")"))
- {
- Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
- ex.reason = "IceSSL: invalid cipher expression `" + exp + "'";
- throw ex;
- }
+ java.io.BufferedInputStream bis =
+ new java.io.BufferedInputStream(new java.io.FileInputStream(keystorePath.value));
+ keys.load(bis, passwordChars);
+ }
+ catch(java.io.IOException ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unable to load keystore:\n" + keystorePath.value;
+ e.initCause(ex);
+ throw e;
+ }
- try
- {
- ce.re = java.util.regex.Pattern.compile(exp.substring(1, exp.length() - 2));
- }
- catch(java.util.regex.PatternSyntaxException ex)
- {
- Ice.PluginInitializationException e = new Ice.PluginInitializationException();
- e.reason = "IceSSL: invalid cipher expression `" + exp + "'";
- e.initCause(ex);
- throw e;
- }
- }
- else
+ String algorithm = javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm();
+ javax.net.ssl.KeyManagerFactory kmf = javax.net.ssl.KeyManagerFactory.getInstance(algorithm);
+ kmf.init(keys, password.toCharArray());
+ keyManagers = kmf.getKeyManagers();
+
+ //
+ // If the user selected a specific alias, we need to wrap the key managers
+ // in order to return the desired alias.
+ //
+ if(alias.length() > 0)
+ {
+ if(!keys.isKeyEntry(alias))
{
- ce.cipher = exp;
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: keystore does not contain an entry with alias `" + alias + "'";
+ throw e;
}
- cipherList.add(ce);
+ for(int i = 0; i < keyManagers.length; ++i)
+ {
+ keyManagers[i] = new KeyManagerI((javax.net.ssl.X509KeyManager)keyManagers[i], alias, client);
+ }
}
}
- _ciphers = new CipherExpression[cipherList.size()];
- cipherList.toArray(_ciphers);
- }
-
- final String ksType = java.security.KeyStore.getDefaultType();
- javax.net.ssl.KeyManager[] keyManagers = null;
- if(keystore != null && keystore.length() > 0)
- {
- _keys = java.security.KeyStore.getInstance(ksType);
- try
+ //
+ // Collect the trust managers.
+ //
+ javax.net.ssl.TrustManager[] trustManagers = null;
+ if(truststorePath.value.length() > 0)
{
- char[] pass = null;
- if(keystorePassword != null && keystorePassword.length() > 0)
+ if(!checkPath(truststorePath, false))
{
- pass = keystorePassword.toCharArray();
+ 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
+ {
+ char[] passwordChars = null;
+ if(truststorePassword.length() > 0)
+ {
+ passwordChars = truststorePassword.toCharArray();
+ }
- java.io.BufferedInputStream bis =
- new java.io.BufferedInputStream(new java.io.FileInputStream(keystore));
- _keys.load(bis, pass);
- }
- catch(java.io.IOException ex)
- {
- Ice.PluginInitializationException e = new Ice.PluginInitializationException();
- e.reason = "IceSSL: unable to load keystore from `" + keystore + "'";
- e.initCause(ex);
- throw e;
- }
-
- String algorithm = javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm();
- javax.net.ssl.KeyManagerFactory kmf = javax.net.ssl.KeyManagerFactory.getInstance(algorithm);
- kmf.init(_keys, password.toCharArray());
- keyManagers = kmf.getKeyManagers();
- }
-
- javax.net.ssl.TrustManager[] trustManagers = null;
- if(certs != null && certs.length() > 0)
- {
- _certs = java.security.KeyStore.getInstance(ksType);
- try
- {
- char[] pass = null;
- if(certsPassword != null && certsPassword.length() > 0)
+ java.io.BufferedInputStream bis =
+ new java.io.BufferedInputStream(new java.io.FileInputStream(truststorePath.value));
+ ts.load(bis, passwordChars);
+ }
+ catch(java.io.IOException ex)
{
- pass = certsPassword.toCharArray();
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: unable to load truststore:\n" + truststorePath.value;
+ e.initCause(ex);
+ throw e;
}
- java.io.BufferedInputStream bis =
- new java.io.BufferedInputStream(new java.io.FileInputStream(certs));
- _certs.load(bis, pass);
- }
- catch(java.io.IOException ex)
- {
- Ice.PluginInitializationException e = new Ice.PluginInitializationException();
- e.reason = "IceSSL: unable to load keystore from `" + certs + "'";
- e.initCause(ex);
- throw e;
+ String algorithm = javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm();
+ javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance(algorithm);
+ tmf.init(ts);
+ trustManagers = tmf.getTrustManagers();
}
- String algorithm = javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm();
- javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance(algorithm);
- tmf.init(_certs);
- trustManagers = tmf.getTrustManagers();
+ //
+ // Initialize the SSL context.
+ //
+ _ctx = javax.net.ssl.SSLContext.getInstance("SSL");
+ _ctx.init(keyManagers, trustManagers, rand);
}
-
- _ctx = javax.net.ssl.SSLContext.getInstance("SSL");
- _ctx.init(keyManagers, trustManagers, rand);
}
javax.net.ssl.SSLContext
@@ -240,6 +300,165 @@ class Context
return arr;
}
+ String[]
+ getProtocols()
+ {
+ return _protocols;
+ }
+
+ void
+ traceConnection(javax.net.ssl.SSLSocket fd, boolean incoming)
+ {
+ javax.net.ssl.SSLSession session = fd.getSession();
+ String msg = "SSL summary for " + (incoming ? "incoming" : "outgoing") + " connection\n" +
+ "cipher = " + session.getCipherSuite() + "\n" +
+ "protocol = " + session.getProtocol() + "\n" +
+ IceInternal.Network.fdToString(fd);
+ _logger.trace(_instance.securityTraceCategory(), msg);
+ }
+
+ boolean
+ verifyPeer(javax.net.ssl.SSLSocket fd, String host, boolean incoming)
+ {
+ CertificateVerifier verifier = _instance.certificateVerifier();
+ if(verifier != null)
+ {
+ VerifyInfo info = new VerifyInfo();
+ info.incoming = incoming;
+ try
+ {
+ info.certs = fd.getSession().getPeerCertificates();
+ }
+ catch(javax.net.ssl.SSLPeerUnverifiedException ex)
+ {
+ // No peer certificates.
+ }
+ info.socket = fd;
+ info.address = host;
+ if(!verifier.verify(info))
+ {
+ if(_instance.securityTraceLevel() > 0)
+ {
+ _logger.trace(_instance.securityTraceCategory(),
+ (incoming ? "incoming" : "outgoing") +
+ " connection rejected by certificate verifier\n" +
+ IceInternal.Network.fdToString(fd));
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void
+ parseCiphers(String ciphers)
+ {
+ java.util.ArrayList cipherList = new java.util.ArrayList();
+ String[] expr = ciphers.split("[ \t]+");
+ for(int i = 0; i < expr.length; ++i)
+ {
+ if(expr[i].equals("ALL"))
+ {
+ if(i != 0)
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: `ALL' must be first in cipher list `" + ciphers + "'";
+ throw ex;
+ }
+ _allCiphers = true;
+ }
+ else if(expr[i].equals("NONE"))
+ {
+ if(i != 0)
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: `NONE' must be first in cipher list `" + ciphers + "'";
+ throw ex;
+ }
+ _noCiphers = true;
+ }
+ else
+ {
+ CipherExpression ce = new CipherExpression();
+ String exp = expr[i];
+ if(exp.charAt(0) == '!')
+ {
+ ce.not = true;
+ if(exp.length() > 1)
+ {
+ exp = exp.substring(1);
+ }
+ else
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: invalid cipher expression `" + exp + "'";
+ throw ex;
+ }
+ }
+
+ if(exp.charAt(0) == '(')
+ {
+ if(!exp.endsWith(")"))
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: invalid cipher expression `" + exp + "'";
+ throw ex;
+ }
+
+ try
+ {
+ ce.re = java.util.regex.Pattern.compile(exp.substring(1, exp.length() - 2));
+ }
+ catch(java.util.regex.PatternSyntaxException ex)
+ {
+ Ice.PluginInitializationException e = new Ice.PluginInitializationException();
+ e.reason = "IceSSL: invalid cipher expression `" + exp + "'";
+ e.initCause(ex);
+ throw e;
+ }
+ }
+ else
+ {
+ ce.cipher = exp;
+ }
+
+ cipherList.add(ce);
+ }
+ }
+ _ciphers = new CipherExpression[cipherList.size()];
+ cipherList.toArray(_ciphers);
+ }
+
+ private boolean
+ checkPath(Ice.StringHolder path, boolean dir)
+ {
+ //
+ // Check if file exists. If not, try prepending the default
+ // directory and check again. If the file is found, the
+ // string argument is modified and true is returned. Otherwise
+ // false is returned.
+ //
+ java.io.File f = new java.io.File(path.value);
+ if(f.exists())
+ {
+ return dir ? f.isDirectory() : f.isFile();
+ }
+
+ if(_defaultDir.length() > 0)
+ {
+ String s = _defaultDir + java.io.File.separator + path.value;
+ f = new java.io.File(s);
+ if(f.exists() && ((!dir && f.isFile()) || (dir && f.isDirectory())))
+ {
+ path.value = s;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private static class CipherExpression
{
boolean not;
@@ -247,10 +466,12 @@ class Context
java.util.regex.Pattern re;
}
+ private Instance _instance;
+ private Ice.Logger _logger;
+ private String _defaultDir;
private CipherExpression[] _ciphers;
private boolean _allCiphers;
private boolean _noCiphers;
+ private String[] _protocols;
private javax.net.ssl.SSLContext _ctx;
- private java.security.KeyStore _keys;
- private java.security.KeyStore _certs;
}