diff options
Diffstat (limited to 'java/src/IceSSL/Context.java')
-rw-r--r-- | java/src/IceSSL/Context.java | 453 |
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; } |