diff options
author | Mark Spruiell <mes@zeroc.com> | 2006-04-26 17:04:31 +0000 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2006-04-26 17:04:31 +0000 |
commit | 4b7ac6e8197a8e9e729d69fd04b75f327953943f (patch) | |
tree | eb07dc7faa9d7a1b6c09df90b796e8785d1284bb | |
parent | more fixes for two-stage initialization (diff) | |
download | ice-4b7ac6e8197a8e9e729d69fd04b75f327953943f.tar.bz2 ice-4b7ac6e8197a8e9e729d69fd04b75f327953943f.tar.xz ice-4b7ac6e8197a8e9e729d69fd04b75f327953943f.zip |
refactoring to remove Context
-rwxr-xr-x | cs/src/IceSSL/AcceptorI.cs | 19 | ||||
-rwxr-xr-x | cs/src/IceSSL/ConnectorI.cs | 15 | ||||
-rwxr-xr-x | cs/src/IceSSL/Context.cs | 351 | ||||
-rwxr-xr-x | cs/src/IceSSL/IceSSL.csproj | 1 | ||||
-rw-r--r-- | cs/src/IceSSL/Instance.cs | 374 | ||||
-rw-r--r-- | java/src/IceSSL/AcceptorI.java | 23 | ||||
-rw-r--r-- | java/src/IceSSL/ConnectorI.java | 19 | ||||
-rw-r--r-- | java/src/IceSSL/Context.java | 474 | ||||
-rw-r--r-- | java/src/IceSSL/Instance.java | 496 | ||||
-rw-r--r-- | java/src/IceSSL/PluginI.java | 4 |
10 files changed, 855 insertions, 921 deletions
diff --git a/cs/src/IceSSL/AcceptorI.cs b/cs/src/IceSSL/AcceptorI.cs index f8b4afc1d2e..a9326885429 100755 --- a/cs/src/IceSSL/AcceptorI.cs +++ b/cs/src/IceSSL/AcceptorI.cs @@ -71,7 +71,12 @@ namespace IceSSL // // The plugin may not be fully initialized. // - Context ctx = instance_.context(); + if(!instance_.initialized()) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is not initialized"; + throw ex; + } Socket fd = IceInternal.Network.doAccept(fd_, timeout); IceInternal.Network.setBlock(fd, true); // SSL requires a blocking socket. @@ -95,7 +100,7 @@ namespace IceSSL // // Get the certificate collection and select the first one. // - X509Certificate2Collection certs = ctx.certs(); + X509Certificate2Collection certs = instance_.certs(); X509Certificate2 cert = null; if(certs.Count > 0) { @@ -108,9 +113,9 @@ namespace IceSSL AuthInfo info = new AuthInfo(); info.stream = stream; info.done = false; - IAsyncResult ar = stream.BeginAuthenticateAsServer(cert, ctx.verifyPeer() > 1, ctx.protocols(), - ctx.checkCRL(), new AsyncCallback(authCallback), - info); + IAsyncResult ar = stream.BeginAuthenticateAsServer(cert, instance_.verifyPeer() > 1, + instance_.protocols(), instance_.checkCRL(), + new AsyncCallback(authCallback), info); lock(info) { if(!info.done) @@ -237,7 +242,7 @@ namespace IceSSL // // .NET requires that a certificate be supplied. // - X509Certificate2Collection certs = instance.context().certs(); + X509Certificate2Collection certs = instance.certs(); if(certs.Count == 0) { Ice.SecurityException ex = new Ice.SecurityException(); @@ -314,7 +319,7 @@ namespace IceSSL int errors = (int)sslPolicyErrors; if((errors & (int)SslPolicyErrors.RemoteCertificateNotAvailable) > 0) { - if(instance_.context().verifyPeer() > 1) + if(instance_.verifyPeer() > 1) { if(instance_.securityTraceLevel() >= 1) { diff --git a/cs/src/IceSSL/ConnectorI.cs b/cs/src/IceSSL/ConnectorI.cs index aa81fcad001..cdcb8a92092 100755 --- a/cs/src/IceSSL/ConnectorI.cs +++ b/cs/src/IceSSL/ConnectorI.cs @@ -25,7 +25,12 @@ namespace IceSSL // // The plugin may not be fully initialized. // - Context ctx = instance_.context(); + if(!instance_.initialized()) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is not initialized"; + throw ex; + } if(instance_.networkTraceLevel() >= 2) { @@ -53,9 +58,9 @@ namespace IceSSL AuthInfo info = new AuthInfo(); info.stream = stream; info.done = false; - IAsyncResult ar = stream.BeginAuthenticateAsClient(host_, ctx.certs(), ctx.protocols(), - ctx.checkCRL(), new AsyncCallback(authCallback), - info); + IAsyncResult ar = stream.BeginAuthenticateAsClient(host_, instance_.certs(), instance_.protocols(), + instance_.checkCRL(), + new AsyncCallback(authCallback), info); lock(info) { if(!info.done) @@ -196,7 +201,7 @@ namespace IceSSL int errors = (int)sslPolicyErrors; if((errors & (int)SslPolicyErrors.RemoteCertificateNameMismatch) > 0) { - if(!instance_.context().checkCertName()) + if(!instance_.checkCertName()) { errors ^= (int)SslPolicyErrors.RemoteCertificateNameMismatch; message = message + "\nremote certificate name mismatch (ignored)"; diff --git a/cs/src/IceSSL/Context.cs b/cs/src/IceSSL/Context.cs deleted file mode 100755 index 8c936d68cc8..00000000000 --- a/cs/src/IceSSL/Context.cs +++ /dev/null @@ -1,351 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -namespace IceSSL -{ - using System; - using System.Collections; - using System.IO; - using System.Security.Authentication; - using System.Security.Cryptography; - using System.Security.Cryptography.X509Certificates; - - internal class Context - { - internal Context(Instance instance, X509Certificate2Collection certs) - { - instance_ = instance; - logger_ = instance.communicator().getLogger(); - - const string prefix = "IceSSL."; - Ice.Properties properties = instance.communicator().getProperties(); - - // - // If the user doesn't supply a certificate collection, we need to examine - // the property settings. - // - certs_ = certs; - if(certs_ == null) - { - // - // If IceSSL.CertFile is defined, load a certificate from a file and - // add it to the collection. - // - // TODO: tracing? - certs_ = new X509Certificate2Collection(); - string certFile = properties.getProperty(prefix + "CertFile"); - string password = properties.getProperty(prefix + "Password"); - if(certFile.Length > 0) - { - if(!instance_.checkPath(ref certFile)) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: certificate file not found: " + certFile; - throw e; - } - try - { - X509Certificate2 cert = new X509Certificate2(certFile, password); - certs_.Add(cert); - } - catch(CryptographicException ex) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex); - e.reason = "IceSSL: error while attempting to load certificate from " + certFile; - throw e; - } - } - - // - // If IceSSL.FindCert.* properties are defined, add the selected certificates - // to the collection. - // - // TODO: tracing? - const string findPrefix = prefix + "FindCert."; - Ice.PropertyDict certProps = properties.getPropertiesForPrefix(findPrefix); - if(certProps.Count > 0) - { - foreach(DictionaryEntry entry in certProps) - { - string name = (string)entry.Key; - string val = (string)entry.Value; - if(val.Length > 0) - { - string storeSpec = name.Substring(findPrefix.Length); - X509Certificate2Collection coll = findCertificates(name, storeSpec, val); - certs_.AddRange(coll); - } - } - if(certs_.Count == 0) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: no client certificates found"; - throw e; - } - } - } - - // - // Determine whether a certificate is required from the peer. - // - verifyPeer_ = properties.getPropertyAsIntWithDefault(prefix + "VerifyPeer", 2); - - // - // Select protocols. - // - protocols_ = parseProtocols(prefix + "Protocols"); - - // - // CheckCRL determines whether the certificate revocation list is checked. - // - checkCRL_ = properties.getPropertyAsIntWithDefault(prefix + "CheckCRL", 0) > 0; - - // - // CheckCertName determines whether we compare the name in a peer's - // certificate against its hostname. - // - checkCertName_ = properties.getPropertyAsIntWithDefault(prefix + "CheckCertName", 0) > 0; - } - - internal X509Certificate2Collection certs() - { - return certs_; - } - - internal int verifyPeer() - { - return verifyPeer_; - } - - internal SslProtocols protocols() - { - return protocols_; - } - - internal bool checkCRL() - { - return checkCRL_; - } - - internal bool checkCertName() - { - return checkCertName_; - } - - private SslProtocols parseProtocols(string property) - { - SslProtocols result = SslProtocols.Default; - string val = instance_.communicator().getProperties().getProperty(property); - if(val.Length > 0) - { - char[] delim = new char[] {',', ' '}; - string[] arr = val.Split(delim, StringSplitOptions.RemoveEmptyEntries); - if(arr.Length > 0) - { - result = 0; - for(int i = 0; i < arr.Length; ++i) - { - string s = arr[i].ToLower(); - if(s.Equals("ssl3") || s.Equals("sslv3")) - { - result |= SslProtocols.Ssl3; - } - else if(s.Equals("tls") || s.Equals("tls1") || s.Equals("tlsv1")) - { - result |= SslProtocols.Tls; - } - else - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: unrecognized protocol `" + s + "'"; - throw e; - } - } - } - } - return result; - } - - private X509Certificate2Collection findCertificates(string prop, string storeSpec, string value) - { - StoreLocation storeLoc = 0; - StoreName storeName = 0; - string storeNameStr = null; - instance_.parseStore(prop, storeSpec, ref storeLoc, ref storeName, ref storeNameStr); - - // - // Open the X509 certificate store. - // - X509Store store = null; - try - { - if(storeNameStr != null) - { - store = new X509Store(storeNameStr, storeLoc); - } - else - { - store = new X509Store(storeName, storeLoc); - } - store.Open(OpenFlags.ReadOnly); - } - catch(Exception ex) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex); - e.reason = "IceSSL: failure while opening store specified by " + prop; - throw e; - } - - // - // Start with all of the certificates in the collection and filter as necessary. - // - // - If the value is "*", return all certificates. - // - Otherwise, search using key:value pairs. The following keys are supported: - // - // Issuer - // IssuerDN - // Serial - // Subject - // SubjectDN - // SubjectKeyId - // Thumbprint - // - // A value must be enclosed in single or double quotes if it contains whitespace. - // - X509Certificate2Collection result = new X509Certificate2Collection(); - result.AddRange(store.Certificates); - try - { - if(value != "*") - { - int start = 0; - int pos; - while((pos = value.IndexOf(':', start)) != -1) - { - // - // Parse the X509FindType. - // - string field = value.Substring(start, pos - start).Trim().ToLower(); - X509FindType findType; - if(field.Equals("subject")) - { - findType = X509FindType.FindBySubjectName; - } - else if(field.Equals("subjectdn")) - { - findType = X509FindType.FindBySubjectDistinguishedName; - } - else if(field.Equals("issuer")) - { - findType = X509FindType.FindByIssuerName; - } - else if(field.Equals("issuerdn")) - { - findType = X509FindType.FindByIssuerDistinguishedName; - } - else if(field.Equals("thumbprint")) - { - findType = X509FindType.FindByThumbprint; - } - else if(field.Equals("subjectkeyid")) - { - findType = X509FindType.FindBySubjectKeyIdentifier; - } - else if(field.Equals("serial")) - { - findType = X509FindType.FindBySerialNumber; - } - else - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: unknown key in `" + value + "'"; - throw e; - } - - // - // Parse the argument. - // - start = pos + 1; - while(start < value.Length && (value[start] == ' ' || value[start] == '\t')) - { - ++start; - } - if(start == value.Length) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: missing argument in `" + value + "'"; - throw e; - } - - string arg; - if(value[start] == '"' || value[start] == '\'') - { - int end = start; - ++end; - while(end < value.Length) - { - if(value[end] == value[start] && value[end - 1] != '\\') - { - break; - } - ++end; - } - if(end == value.Length || value[end] != value[start]) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: unmatched quote in `" + value + "'"; - throw e; - } - ++start; - arg = value.Substring(start, end - start); - start = end + 1; - } - else - { - char[] ws = new char[] { ' ', '\t' }; - int end = value.IndexOfAny(ws, start); - if(end == -1) - { - arg = value.Substring(start); - start = value.Length; - } - else - { - arg = value.Substring(start, end - start); - start = end + 1; - } - } - - // - // Execute the query. - // - // TODO: allow user to specify a value for validOnly? - // - bool validOnly = false; - result = result.Find(findType, arg, validOnly); - } - } - } - finally - { - store.Close(); - } - - return result; - } - - private Instance instance_; - private Ice.Logger logger_; - private X509Certificate2Collection certs_; - private int verifyPeer_; - private SslProtocols protocols_; - private bool checkCRL_; - private bool checkCertName_; - } -} diff --git a/cs/src/IceSSL/IceSSL.csproj b/cs/src/IceSSL/IceSSL.csproj index 65770e0c830..a9dc0410e4f 100755 --- a/cs/src/IceSSL/IceSSL.csproj +++ b/cs/src/IceSSL/IceSSL.csproj @@ -56,7 +56,6 @@ <ItemGroup>
<Compile Include="AcceptorI.cs" />
<Compile Include="ConnectorI.cs" />
- <Compile Include="Context.cs" />
<Compile Include="EndpointI.cs" />
<Compile Include="Instance.cs" />
<Compile Include="Plugin.cs" />
diff --git a/cs/src/IceSSL/Instance.cs b/cs/src/IceSSL/Instance.cs index 290943b9f00..5241045f5a0 100644 --- a/cs/src/IceSSL/Instance.cs +++ b/cs/src/IceSSL/Instance.cs @@ -12,28 +12,48 @@ namespace IceSSL using System; using System.Collections; using System.IO; + using System.Security.Authentication; + using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; internal class Instance { internal Instance(Ice.Communicator communicator) { - Ice.Properties properties = communicator.getProperties(); - + logger_ = communicator.getLogger(); facade_ = Ice.Util.getProtocolPluginFacade(communicator); - securityTraceLevel_ = properties.getPropertyAsIntWithDefault("IceSSL.Trace.Security", 0); + securityTraceLevel_ = communicator.getProperties().getPropertyAsIntWithDefault("IceSSL.Trace.Security", 0); securityTraceCategory_ = "Security"; + initialized_ = false; + + // + // Register the endpoint factory. We have to do this now, rather than + // in initialize, because the communicator may need to interpret + // proxies before the plugin is fully initialized. + // + facade_.addEndpointFactory(new EndpointFactoryI(this)); + } + + internal void initialize() + { + if(initialized_) + { + return; + } + + const string prefix = "IceSSL."; + Ice.Properties properties = communicator().getProperties(); // // Check for a default directory. We look in this directory for // files mentioned in the configuration. // - defaultDir_ = properties.getProperty("IceSSL.DefaultDir"); + defaultDir_ = properties.getProperty(prefix + "DefaultDir"); // // Process IceSSL.ImportCert.* properties. // - Ice.PropertyDict certs = properties.getPropertiesForPrefix("IceSSL.ImportCert."); + Ice.PropertyDict certs = properties.getPropertiesForPrefix(prefix + "ImportCert."); foreach(DictionaryEntry entry in certs) { string name = (string)entry.Key; @@ -45,26 +65,96 @@ namespace IceSSL } // - // Register the endpoint factory. We have to do this now, rather than - // in initialize, because the communicator may need to interpret - // proxies before the plugin is fully initialized. + // Select protocols. // - facade_.addEndpointFactory(new EndpointFactoryI(this)); - } + protocols_ = parseProtocols(prefix + "Protocols"); - internal void initialize() - { - if(context_ != null) + // + // CheckCertName determines whether we compare the name in a peer's + // certificate against its hostname. + // + checkCertName_ = properties.getPropertyAsIntWithDefault(prefix + "CheckCertName", 0) > 0; + + // + // Determine whether a certificate is required from the peer. + // + verifyPeer_ = properties.getPropertyAsIntWithDefault(prefix + "VerifyPeer", 2); + + // + // CheckCRL determines whether the certificate revocation list is checked. + // + checkCRL_ = properties.getPropertyAsIntWithDefault(prefix + "CheckCRL", 0) > 0; + + // + // If the user hasn't supplied a certificate collection, we need to examine + // the property settings. + // + if(certs_ == null) { - return; + // + // If IceSSL.CertFile is defined, load a certificate from a file and + // add it to the collection. + // + // TODO: tracing? + certs_ = new X509Certificate2Collection(); + string certFile = properties.getProperty(prefix + "CertFile"); + string password = properties.getProperty(prefix + "Password"); + if(certFile.Length > 0) + { + if(!checkPath(ref certFile)) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: certificate file not found: " + certFile; + throw e; + } + try + { + X509Certificate2 cert = new X509Certificate2(certFile, password); + certs_.Add(cert); + } + catch(CryptographicException ex) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex); + e.reason = "IceSSL: error while attempting to load certificate from " + certFile; + throw e; + } + } + + // + // If IceSSL.FindCert.* properties are defined, add the selected certificates + // to the collection. + // + // TODO: tracing? + const string findPrefix = prefix + "FindCert."; + Ice.PropertyDict certProps = properties.getPropertiesForPrefix(findPrefix); + if(certProps.Count > 0) + { + foreach(DictionaryEntry entry in certProps) + { + string name = (string)entry.Key; + string val = (string)entry.Value; + if(val.Length > 0) + { + string storeSpec = name.Substring(findPrefix.Length); + X509Certificate2Collection coll = findCertificates(name, storeSpec, val); + certs_.AddRange(coll); + } + } + if(certs_.Count == 0) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: no client certificates found"; + throw e; + } + } } - context_ = new Context(this, certs_); + initialized_ = true; } internal void setCertificates(X509Certificate2Collection certs) { - if(context_ != null) + if(initialized_) { Ice.PluginInitializationException e = new Ice.PluginInitializationException(); e.reason = "IceSSL: plugin is already initialized"; @@ -109,20 +199,39 @@ namespace IceSSL return securityTraceCategory_; } - internal Context context() + internal CertificateVerifier certificateVerifier() { - if(context_ == null) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: plugin is not fully initialized"; - throw e; - } - return context_; + return verifier_; } - internal CertificateVerifier certificateVerifier() + internal bool initialized() { - return verifier_; + return initialized_; + } + + internal X509Certificate2Collection certs() + { + return certs_; + } + + internal int verifyPeer() + { + return verifyPeer_; + } + + internal SslProtocols protocols() + { + return protocols_; + } + + internal bool checkCRL() + { + return checkCRL_; + } + + internal bool checkCertName() + { + return checkCertName_; } internal void traceStream(System.Net.Security.SslStream stream, string connInfo) @@ -196,7 +305,7 @@ namespace IceSSL } } - internal bool checkPath(ref string path) + private bool checkPath(ref string path) { if(File.Exists(path)) { @@ -375,12 +484,219 @@ namespace IceSSL return (string[])l.ToArray(typeof(string)); } + private SslProtocols parseProtocols(string property) + { + SslProtocols result = SslProtocols.Default; + string val = communicator().getProperties().getProperty(property); + if(val.Length > 0) + { + char[] delim = new char[] {',', ' '}; + string[] arr = val.Split(delim, StringSplitOptions.RemoveEmptyEntries); + if(arr.Length > 0) + { + result = 0; + for(int i = 0; i < arr.Length; ++i) + { + string s = arr[i].ToLower(); + if(s.Equals("ssl3") || s.Equals("sslv3")) + { + result |= SslProtocols.Ssl3; + } + else if(s.Equals("tls") || s.Equals("tls1") || s.Equals("tlsv1")) + { + result |= SslProtocols.Tls; + } + else + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: unrecognized protocol `" + s + "'"; + throw e; + } + } + } + } + return result; + } + + private X509Certificate2Collection findCertificates(string prop, string storeSpec, string value) + { + StoreLocation storeLoc = 0; + StoreName storeName = 0; + string storeNameStr = null; + parseStore(prop, storeSpec, ref storeLoc, ref storeName, ref storeNameStr); + + // + // Open the X509 certificate store. + // + X509Store store = null; + try + { + if(storeNameStr != null) + { + store = new X509Store(storeNameStr, storeLoc); + } + else + { + store = new X509Store(storeName, storeLoc); + } + store.Open(OpenFlags.ReadOnly); + } + catch(Exception ex) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex); + e.reason = "IceSSL: failure while opening store specified by " + prop; + throw e; + } + + // + // Start with all of the certificates in the collection and filter as necessary. + // + // - If the value is "*", return all certificates. + // - Otherwise, search using key:value pairs. The following keys are supported: + // + // Issuer + // IssuerDN + // Serial + // Subject + // SubjectDN + // SubjectKeyId + // Thumbprint + // + // A value must be enclosed in single or double quotes if it contains whitespace. + // + X509Certificate2Collection result = new X509Certificate2Collection(); + result.AddRange(store.Certificates); + try + { + if(value != "*") + { + int start = 0; + int pos; + while((pos = value.IndexOf(':', start)) != -1) + { + // + // Parse the X509FindType. + // + string field = value.Substring(start, pos - start).Trim().ToLower(); + X509FindType findType; + if(field.Equals("subject")) + { + findType = X509FindType.FindBySubjectName; + } + else if(field.Equals("subjectdn")) + { + findType = X509FindType.FindBySubjectDistinguishedName; + } + else if(field.Equals("issuer")) + { + findType = X509FindType.FindByIssuerName; + } + else if(field.Equals("issuerdn")) + { + findType = X509FindType.FindByIssuerDistinguishedName; + } + else if(field.Equals("thumbprint")) + { + findType = X509FindType.FindByThumbprint; + } + else if(field.Equals("subjectkeyid")) + { + findType = X509FindType.FindBySubjectKeyIdentifier; + } + else if(field.Equals("serial")) + { + findType = X509FindType.FindBySerialNumber; + } + else + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: unknown key in `" + value + "'"; + throw e; + } + + // + // Parse the argument. + // + start = pos + 1; + while(start < value.Length && (value[start] == ' ' || value[start] == '\t')) + { + ++start; + } + if(start == value.Length) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: missing argument in `" + value + "'"; + throw e; + } + + string arg; + if(value[start] == '"' || value[start] == '\'') + { + int end = start; + ++end; + while(end < value.Length) + { + if(value[end] == value[start] && value[end - 1] != '\\') + { + break; + } + ++end; + } + if(end == value.Length || value[end] != value[start]) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: unmatched quote in `" + value + "'"; + throw e; + } + ++start; + arg = value.Substring(start, end - start); + start = end + 1; + } + else + { + char[] ws = new char[] { ' ', '\t' }; + int end = value.IndexOfAny(ws, start); + if(end == -1) + { + arg = value.Substring(start); + start = value.Length; + } + else + { + arg = value.Substring(start, end - start); + start = end + 1; + } + } + + // + // Execute the query. + // + // TODO: allow user to specify a value for validOnly? + // + bool validOnly = false; + result = result.Find(findType, arg, validOnly); + } + } + } + finally + { + store.Close(); + } + + return result; + } + + private Ice.Logger logger_; private IceInternal.ProtocolPluginFacade facade_; private int securityTraceLevel_; private string securityTraceCategory_; - private Context context_; - private CertificateVerifier verifier_; + private bool initialized_; private string defaultDir_; + private SslProtocols protocols_; + private bool checkCertName_; + private int verifyPeer_; + private bool checkCRL_; private X509Certificate2Collection certs_; + private CertificateVerifier verifier_; } } diff --git a/java/src/IceSSL/AcceptorI.java b/java/src/IceSSL/AcceptorI.java index ea0e0f102a6..b7fb65d05e7 100644 --- a/java/src/IceSSL/AcceptorI.java +++ b/java/src/IceSSL/AcceptorI.java @@ -60,6 +60,16 @@ class AcceptorI implements IceInternal.Acceptor public IceInternal.Transceiver accept(int timeout) { + // + // The plugin may not be fully initialized. + // + if(!_instance.initialized()) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is not initialized"; + throw ex; + } + javax.net.ssl.SSLSocket fd = null; try { @@ -120,7 +130,7 @@ class AcceptorI implements IceInternal.Acceptor } } - if(!_ctx.verifyPeer(fd, "", true)) + if(!_instance.verifyPeer(fd, "", true)) { try { @@ -226,7 +236,7 @@ class AcceptorI implements IceInternal.Acceptor if(_instance.securityTraceLevel() > 0) { - _ctx.traceConnection(fd, true); + _instance.traceConnection(fd, true); } return new TransceiverI(_instance, fd); @@ -272,7 +282,6 @@ class AcceptorI implements IceInternal.Acceptor AcceptorI(Instance instance, String host, int port) { _instance = instance; - _ctx = instance.context(); _logger = instance.communicator().getLogger(); _backlog = 0; @@ -283,7 +292,7 @@ class AcceptorI implements IceInternal.Acceptor try { - javax.net.ssl.SSLServerSocketFactory factory = _ctx.sslContext().getServerSocketFactory(); + javax.net.ssl.SSLServerSocketFactory factory = _instance.context().getServerSocketFactory(); _addr = new java.net.InetSocketAddress(host, port); if(_instance.networkTraceLevel() >= 2) { @@ -310,7 +319,8 @@ class AcceptorI implements IceInternal.Acceptor _fd.setNeedClientAuth(true); } - String[] cipherSuites = _ctx.filterCiphers(_fd.getSupportedCipherSuites(), _fd.getEnabledCipherSuites()); + String[] cipherSuites = + _instance.filterCiphers(_fd.getSupportedCipherSuites(), _fd.getEnabledCipherSuites()); try { _fd.setEnabledCipherSuites(cipherSuites); @@ -333,7 +343,7 @@ class AcceptorI implements IceInternal.Acceptor _logger.trace(_instance.securityTraceCategory(), s.toString()); } - String[] protocols = _ctx.getProtocols(); + String[] protocols = _instance.protocols(); if(protocols != null) { try @@ -445,7 +455,6 @@ class AcceptorI implements IceInternal.Acceptor } private Instance _instance; - private Context _ctx; private Ice.Logger _logger; private javax.net.ssl.SSLServerSocket _fd; private int _backlog; diff --git a/java/src/IceSSL/ConnectorI.java b/java/src/IceSSL/ConnectorI.java index cf197e1eb95..d7e8796f601 100644 --- a/java/src/IceSSL/ConnectorI.java +++ b/java/src/IceSSL/ConnectorI.java @@ -17,7 +17,12 @@ final class ConnectorI implements IceInternal.Connector // // The plugin may not be fully initialized. // - Context ctx = _instance.context(); + if(!_instance.initialized()) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is not initialized"; + throw ex; + } if(_instance.networkTraceLevel() >= 2) { @@ -33,7 +38,7 @@ final class ConnectorI implements IceInternal.Connector // if(timeout >= 0) { - ConnectThread ct = new ConnectThread(ctx.sslContext(), _addr); + ConnectThread ct = new ConnectThread(_instance.context(), _addr); ct.start(); fd = ct.getFd(timeout == 0 ? 1 : timeout); if(fd == null) @@ -43,13 +48,13 @@ final class ConnectorI implements IceInternal.Connector } else { - javax.net.SocketFactory factory = ctx.sslContext().getSocketFactory(); + javax.net.SocketFactory factory = _instance.context().getSocketFactory(); fd = (javax.net.ssl.SSLSocket)factory.createSocket(_addr.getAddress(), _addr.getPort()); } fd.setUseClientMode(true); - String[] cipherSuites = ctx.filterCiphers(fd.getSupportedCipherSuites(), fd.getEnabledCipherSuites()); + String[] cipherSuites = _instance.filterCiphers(fd.getSupportedCipherSuites(), fd.getEnabledCipherSuites()); try { fd.setEnabledCipherSuites(cipherSuites); @@ -72,7 +77,7 @@ final class ConnectorI implements IceInternal.Connector _logger.trace(_instance.securityTraceCategory(), s.toString()); } - String[] protocols = ctx.getProtocols(); + String[] protocols = _instance.protocols(); if(protocols != null) { try @@ -125,7 +130,7 @@ final class ConnectorI implements IceInternal.Connector } } - if(!ctx.verifyPeer(fd, _host, false)) + if(!_instance.verifyPeer(fd, _host, false)) { Ice.SecurityException ex = new Ice.SecurityException(); ex.reason = "IceSSL: outgoing connection rejected by certificate verifier"; @@ -217,7 +222,7 @@ final class ConnectorI implements IceInternal.Connector if(_instance.securityTraceLevel() > 0) { - ctx.traceConnection(fd, false); + _instance.traceConnection(fd, false); } return new TransceiverI(_instance, fd); diff --git a/java/src/IceSSL/Context.java b/java/src/IceSSL/Context.java deleted file mode 100644 index 1eaa2f881a2..00000000000 --- a/java/src/IceSSL/Context.java +++ /dev/null @@ -1,474 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -package IceSSL; - -class Context -{ - Context(Instance instance, javax.net.ssl.SSLContext context, java.security.SecureRandom rand) - throws java.security.GeneralSecurityException - { - _instance = instance; - _logger = instance.communicator().getLogger(); - - final String prefix = "IceSSL."; - Ice.Properties properties = instance.communicator().getProperties(); - String ciphers = properties.getProperty(prefix + "Ciphers"); - - if(ciphers.length() > 0) - { - 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.getProperty(prefix + "Truststore")); - - // - // The password for the truststore. - // - final String truststorePassword = properties.getProperty(prefix + "TruststorePassword"); - - // - // 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) - { - java.util.ArrayList l = new java.util.ArrayList(); - String[] arr = protocols.split("[ \t,]+"); - for(int i = 0; i < arr.length; ++i) - { - String s = arr[i].toLowerCase(); - if(s.equals("ssl3") || s.equals("sslv3")) - { - l.add("SSLv3"); - } - else if(s.equals("tls") || s.equals("tls1") || s.equals("tlsv1")) - { - l.add("TLSv1"); - } - else - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: unrecognized protocol `" + arr[i] + "'"; - throw e; - } - } - _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)) - { - 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) - { - passwordChars = keystorePassword.toCharArray(); - } - - 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; - } - - 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)) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: keystore does not contain an entry with alias `" + alias + "'"; - throw e; - } - - for(int i = 0; i < keyManagers.length; ++i) - { - keyManagers[i] = new KeyManagerI((javax.net.ssl.X509KeyManager)keyManagers[i], alias); - } - } - } - - // - // Collect the trust managers. - // - javax.net.ssl.TrustManager[] trustManagers = null; - if(truststorePath.value.length() > 0) - { - if(!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 - { - char[] passwordChars = null; - if(truststorePassword.length() > 0) - { - passwordChars = truststorePassword.toCharArray(); - } - - java.io.BufferedInputStream bis = - new java.io.BufferedInputStream(new java.io.FileInputStream(truststorePath.value)); - ts.load(bis, passwordChars); - } - 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(); - javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance(algorithm); - tmf.init(ts); - trustManagers = tmf.getTrustManagers(); - } - - // - // Initialize the SSL context. - // - _ctx = javax.net.ssl.SSLContext.getInstance("SSL"); - _ctx.init(keyManagers, trustManagers, rand); - } - } - - javax.net.ssl.SSLContext - sslContext() - { - return _ctx; - } - - String[] - filterCiphers(String[] supportedCiphers, String[] defaultCiphers) - { - java.util.LinkedList result = new java.util.LinkedList(); - if(_allCiphers) - { - for(int i = 0; i < supportedCiphers.length; ++i) - { - result.add(supportedCiphers[i]); - } - } - else if(!_noCiphers) - { - for(int i = 0; i < defaultCiphers.length; ++i) - { - result.add(defaultCiphers[i]); - } - } - - if(_ciphers != null) - { - for(int i = 0; i < _ciphers.length; ++i) - { - CipherExpression ce = (CipherExpression)_ciphers[i]; - if(ce.not) - { - java.util.Iterator e = result.iterator(); - while(e.hasNext()) - { - String cipher = (String)e.next(); - if(ce.cipher != null) - { - if(ce.cipher.equals(cipher)) - { - e.remove(); - } - } - else - { - assert(ce.re != null); - java.util.regex.Matcher m = ce.re.matcher(cipher); - if(m.find()) - { - e.remove(); - } - } - } - } - else - { - if(ce.cipher != null) - { - result.add(0, ce.cipher); - } - else - { - assert(ce.re != null); - for(int j = 0; j < supportedCiphers.length; ++j) - { - java.util.regex.Matcher m = ce.re.matcher(supportedCiphers[j]); - if(m.find()) - { - result.add(0, supportedCiphers[j]); - } - } - } - } - } - } - - String[] arr = new String[result.size()]; - result.toArray(arr); - 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; - String cipher; - 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; -} diff --git a/java/src/IceSSL/Instance.java b/java/src/IceSSL/Instance.java index 59ae5ed7afa..ea6ab3308e8 100644 --- a/java/src/IceSSL/Instance.java +++ b/java/src/IceSSL/Instance.java @@ -13,9 +13,11 @@ class Instance { Instance(Ice.Communicator communicator) { + _logger = communicator.getLogger(); _facade = Ice.Util.getProtocolPluginFacade(communicator); _securityTraceLevel = communicator.getProperties().getPropertyAsIntWithDefault("IceSSL.Trace.Security", 0); _securityTraceCategory = "Security"; + _initialized = false; // // Register the endpoint factory. We have to do this now, rather than @@ -28,69 +30,252 @@ class Instance void initialize() { - if(_context != null) + if(_initialized) { return; } + final String prefix = "IceSSL."; + Ice.Properties properties = communicator().getProperties(); + // - // If we have to initialize an SSLContext, we'll need a SecureRandom object. + // Parse the cipher list. // - java.security.SecureRandom rand = null; - if(_ctx == null) + String ciphers = properties.getProperty(prefix + "Ciphers"); + if(ciphers.length() > 0) + { + parseCiphers(ciphers); + } + + // + // Select protocols. + // + String protocols = properties.getProperty(prefix + "Protocols"); + if(protocols.length() > 0) + { + java.util.ArrayList l = new java.util.ArrayList(); + String[] arr = protocols.split("[ \t,]+"); + for(int i = 0; i < arr.length; ++i) + { + String s = arr[i].toLowerCase(); + if(s.equals("ssl3") || s.equals("sslv3")) + { + l.add("SSLv3"); + } + else if(s.equals("tls") || s.equals("tls1") || s.equals("tlsv1")) + { + l.add("TLSv1"); + } + else + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: unrecognized protocol `" + arr[i] + "'"; + throw e; + } + } + _protocols = new String[l.size()]; + l.toArray(_protocols); + } + + // + // If the user doesn't supply an SSLContext, we need to create one based + // on property settings. + // + if(_context == null) { try { - rand = java.security.SecureRandom.getInstance("SHA1PRNG"); + // + // We need a SecureRandom object. + // + java.security.SecureRandom rand = java.security.SecureRandom.getInstance("SHA1PRNG"); // // We call nextInt() in order to force the object to perform any time-consuming // initialization tasks now. // rand.nextInt(); + + // + // 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.getProperty(prefix + "Truststore")); + + // + // The password for the truststore. + // + final String truststorePassword = properties.getProperty(prefix + "TruststorePassword"); + + // + // The truststore type defaults to "JKS", but it can also be "PKCS12". + // + String truststoreType = properties.getPropertyWithDefault(prefix + "TruststoreType", + java.security.KeyStore.getDefaultType()); + + // + // Collect the key managers. + // + javax.net.ssl.KeyManager[] keyManagers = null; + if(keystorePath.value.length() > 0) + { + if(!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); + try + { + char[] passwordChars = null; + if(keystorePassword.length() > 0) + { + passwordChars = keystorePassword.toCharArray(); + } + + 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; + } + + 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)) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: keystore does not contain an entry with alias `" + alias + "'"; + throw e; + } + + for(int i = 0; i < keyManagers.length; ++i) + { + keyManagers[i] = new KeyManagerI((javax.net.ssl.X509KeyManager)keyManagers[i], alias); + } + } + } + + // + // Collect the trust managers. + // + javax.net.ssl.TrustManager[] trustManagers = null; + if(truststorePath.value.length() > 0) + { + if(!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 + { + char[] passwordChars = null; + if(truststorePassword.length() > 0) + { + passwordChars = truststorePassword.toCharArray(); + } + + java.io.BufferedInputStream bis = + new java.io.BufferedInputStream(new java.io.FileInputStream(truststorePath.value)); + ts.load(bis, passwordChars); + } + 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(); + javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance(algorithm); + tmf.init(ts); + trustManagers = tmf.getTrustManagers(); + } + + // + // Initialize the SSL context. + // + _context = javax.net.ssl.SSLContext.getInstance("SSL"); + _context.init(keyManagers, trustManagers, rand); } catch(java.security.GeneralSecurityException ex) { Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: unable to initialize secure PRNG"; + e.reason = "IceSSL: unable to initialize context"; e.initCause(ex); throw e; } } - // - // Create the context. - // - try - { - _context = new Context(this, _ctx, rand); - } - catch(java.security.GeneralSecurityException ex) - { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: unable to initialize context"; - e.initCause(ex); - throw e; - } + _initialized = true; } void - setContext(javax.net.ssl.SSLContext context) + context(javax.net.ssl.SSLContext context) { - if(_context != null) + if(_initialized) { Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); ex.reason = "IceSSL: plugin is already initialized"; throw ex; } - _ctx = context; + _context = context; } javax.net.ssl.SSLContext - getContext() + context() { - return _ctx; + return _context; } void @@ -135,28 +320,263 @@ class Instance return _securityTraceCategory; } - Context - context() + boolean + initialized() { - if(_context == null) + return _initialized; + } + + String[] + filterCiphers(String[] supportedCiphers, String[] defaultCiphers) + { + java.util.LinkedList result = new java.util.LinkedList(); + if(_allCiphers) { - Ice.PluginInitializationException e = new Ice.PluginInitializationException(); - e.reason = "IceSSL: plugin is not fully initialized"; - throw e; + for(int i = 0; i < supportedCiphers.length; ++i) + { + result.add(supportedCiphers[i]); + } } - return _context; + else if(!_noCiphers) + { + for(int i = 0; i < defaultCiphers.length; ++i) + { + result.add(defaultCiphers[i]); + } + } + + if(_ciphers != null) + { + for(int i = 0; i < _ciphers.length; ++i) + { + CipherExpression ce = (CipherExpression)_ciphers[i]; + if(ce.not) + { + java.util.Iterator e = result.iterator(); + while(e.hasNext()) + { + String cipher = (String)e.next(); + if(ce.cipher != null) + { + if(ce.cipher.equals(cipher)) + { + e.remove(); + } + } + else + { + assert(ce.re != null); + java.util.regex.Matcher m = ce.re.matcher(cipher); + if(m.find()) + { + e.remove(); + } + } + } + } + else + { + if(ce.cipher != null) + { + result.add(0, ce.cipher); + } + else + { + assert(ce.re != null); + for(int j = 0; j < supportedCiphers.length; ++j) + { + java.util.regex.Matcher m = ce.re.matcher(supportedCiphers[j]); + if(m.find()) + { + result.add(0, supportedCiphers[j]); + } + } + } + } + } + } + + String[] arr = new String[result.size()]; + result.toArray(arr); + return arr; + } + + String[] + protocols() + { + 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(_securityTraceCategory, msg); + } + + boolean + verifyPeer(javax.net.ssl.SSLSocket fd, String host, boolean incoming) + { + CertificateVerifier verifier = _verifier; + 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(_securityTraceLevel > 0) + { + _logger.trace(_securityTraceCategory, + (incoming ? "incoming" : "outgoing") + + " connection rejected by certificate verifier\n" + + IceInternal.Network.fdToString(fd)); + } + return false; + } + } + + return true; } - CertificateVerifier - certificateVerifier() - { - return _verifier; + 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; + String cipher; + java.util.regex.Pattern re; } + private Ice.Logger _logger; private IceInternal.ProtocolPluginFacade _facade; private int _securityTraceLevel; private String _securityTraceCategory; - private Context _context; + private boolean _initialized; + private javax.net.ssl.SSLContext _context; + private String _defaultDir; + private CipherExpression[] _ciphers; + private boolean _allCiphers; + private boolean _noCiphers; + private String[] _protocols; private CertificateVerifier _verifier; - private javax.net.ssl.SSLContext _ctx; } diff --git a/java/src/IceSSL/PluginI.java b/java/src/IceSSL/PluginI.java index 838322ec034..61cdb6e07b3 100644 --- a/java/src/IceSSL/PluginI.java +++ b/java/src/IceSSL/PluginI.java @@ -31,13 +31,13 @@ class PluginI extends Ice.LocalObjectImpl implements Plugin public void setContext(javax.net.ssl.SSLContext context) { - _instance.setContext(context); + _instance.context(context); } public javax.net.ssl.SSLContext getContext() { - return _instance.getContext(); + return _instance.context(); } public void |