diff options
author | Jose <jose@zeroc.com> | 2014-08-08 01:32:44 +0200 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2014-08-08 01:32:44 +0200 |
commit | fdae154017d77fc1cbc52573eec5b721854eb5a5 (patch) | |
tree | 3ea6e545b5a2ae2a33e6c9878824ca945a4b775c | |
parent | ICE-5311 - more fixes (diff) | |
download | ice-fdae154017d77fc1cbc52573eec5b721854eb5a5.tar.bz2 ice-fdae154017d77fc1cbc52573eec5b721854eb5a5.tar.xz ice-fdae154017d77fc1cbc52573eec5b721854eb5a5.zip |
Fixed (ICE-5583) - Consider adding IceSSL.CertAuthFile to C# implementation
-rw-r--r-- | cs/demo/Glacier2/callback/config.client | 2 | ||||
-rw-r--r-- | cs/demo/Glacier2/chat/config.client | 2 | ||||
-rw-r--r-- | cs/demo/Ice/callback/config.client | 2 | ||||
-rw-r--r-- | cs/demo/Ice/callback/config.server | 2 | ||||
-rw-r--r-- | cs/demo/Ice/context/config.client | 2 | ||||
-rw-r--r-- | cs/demo/Ice/context/config.server | 2 | ||||
-rw-r--r-- | cs/demo/Ice/hello/config.client | 2 | ||||
-rw-r--r-- | cs/demo/Ice/hello/config.server | 2 | ||||
-rw-r--r-- | cs/demo/Ice/properties/config.client | 2 | ||||
-rw-r--r-- | cs/demo/Ice/properties/config.server | 2 | ||||
-rw-r--r-- | cs/demo/Ice/wpf/config.client | 2 | ||||
-rw-r--r-- | cs/demo/IceBox/hello/config.client | 2 | ||||
-rw-r--r-- | cs/demo/IceBox/hello/config.service | 2 | ||||
-rw-r--r-- | cs/demo/IceDiscovery/hello/config.client | 2 | ||||
-rw-r--r-- | cs/demo/IceDiscovery/hello/config.server | 2 | ||||
-rw-r--r-- | cs/demo/IceDiscovery/replication/config.server | 2 | ||||
-rw-r--r-- | cs/src/IceSSL/Plugin.cs | 13 | ||||
-rw-r--r-- | cs/src/IceSSL/PluginI.cs | 5 | ||||
-rw-r--r-- | cs/src/IceSSL/SSLEngine.cs | 57 | ||||
-rw-r--r-- | cs/src/IceSSL/TransceiverI.cs | 53 | ||||
-rw-r--r-- | cs/test/IceSSL/configuration/AllTests.cs | 39 | ||||
-rwxr-xr-x | scripts/TestUtil.py | 9 |
22 files changed, 181 insertions, 27 deletions
diff --git a/cs/demo/Glacier2/callback/config.client b/cs/demo/Glacier2/callback/config.client index 1a982d96d65..cea66b0f5ec 100644 --- a/cs/demo/Glacier2/callback/config.client +++ b/cs/demo/Glacier2/callback/config.client @@ -50,6 +50,6 @@ Callback.Proxy=callback:tcp -h localhost -p 10000 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Glacier2/chat/config.client b/cs/demo/Glacier2/chat/config.client index 256104a5b3b..26898af4187 100644 --- a/cs/demo/Glacier2/chat/config.client +++ b/cs/demo/Glacier2/chat/config.client @@ -34,7 +34,7 @@ # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/callback/config.client b/cs/demo/Ice/callback/config.client index e95aeb23d31..ed214518a3a 100644 --- a/cs/demo/Ice/callback/config.client +++ b/cs/demo/Ice/callback/config.client @@ -47,6 +47,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/callback/config.server b/cs/demo/Ice/callback/config.server index b4e19652669..4dff589efa6 100644 --- a/cs/demo/Ice/callback/config.server +++ b/cs/demo/Ice/callback/config.server @@ -41,6 +41,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=s_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/context/config.client b/cs/demo/Ice/context/config.client index b1546086745..d1b4911105b 100644 --- a/cs/demo/Ice/context/config.client +++ b/cs/demo/Ice/context/config.client @@ -45,6 +45,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/context/config.server b/cs/demo/Ice/context/config.server index 306d4ec7874..7a97fa5217c 100644 --- a/cs/demo/Ice/context/config.server +++ b/cs/demo/Ice/context/config.server @@ -41,6 +41,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=s_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/hello/config.client b/cs/demo/Ice/hello/config.client index 95624d417e4..0838d3143d4 100644 --- a/cs/demo/Ice/hello/config.client +++ b/cs/demo/Ice/hello/config.client @@ -50,7 +50,7 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/hello/config.server b/cs/demo/Ice/hello/config.server index d88b411e680..136e14b3155 100644 --- a/cs/demo/Ice/hello/config.server +++ b/cs/demo/Ice/hello/config.server @@ -51,7 +51,7 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=s_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/properties/config.client b/cs/demo/Ice/properties/config.client index 76f2f4de50b..9f99baffbab 100644 --- a/cs/demo/Ice/properties/config.client +++ b/cs/demo/Ice/properties/config.client @@ -46,6 +46,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/properties/config.server b/cs/demo/Ice/properties/config.server index 31c7b0431d3..2cf04d54a6c 100644 --- a/cs/demo/Ice/properties/config.server +++ b/cs/demo/Ice/properties/config.server @@ -56,6 +56,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=s_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/Ice/wpf/config.client b/cs/demo/Ice/wpf/config.client index 70c719e2483..885224063d3 100644 --- a/cs/demo/Ice/wpf/config.client +++ b/cs/demo/Ice/wpf/config.client @@ -40,6 +40,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/IceBox/hello/config.client b/cs/demo/IceBox/hello/config.client index 438876b7bb9..5dead60547c 100644 --- a/cs/demo/IceBox/hello/config.client +++ b/cs/demo/IceBox/hello/config.client @@ -32,6 +32,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/IceBox/hello/config.service b/cs/demo/IceBox/hello/config.service index 51765a037de..fc5155105b6 100644 --- a/cs/demo/IceBox/hello/config.service +++ b/cs/demo/IceBox/hello/config.service @@ -32,6 +32,6 @@ Ice.Warn.Connections=1 # Ice.Plugin.IceSSL="IceSSL,Version=3.5.1.0":IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=s_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/IceDiscovery/hello/config.client b/cs/demo/IceDiscovery/hello/config.client index 879b4c378c6..561842811a9 100644 --- a/cs/demo/IceDiscovery/hello/config.client +++ b/cs/demo/IceDiscovery/hello/config.client @@ -44,7 +44,7 @@ Ice.Trace.Locator=1 # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/IceDiscovery/hello/config.server b/cs/demo/IceDiscovery/hello/config.server index 72d439f5275..d9978797d61 100644 --- a/cs/demo/IceDiscovery/hello/config.server +++ b/cs/demo/IceDiscovery/hello/config.server @@ -52,7 +52,7 @@ Ice.Plugin.IceDiscovery=IceDiscovery:IceDiscovery.PluginFactory # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/demo/IceDiscovery/replication/config.server b/cs/demo/IceDiscovery/replication/config.server index 72d439f5275..d9978797d61 100644 --- a/cs/demo/IceDiscovery/replication/config.server +++ b/cs/demo/IceDiscovery/replication/config.server @@ -52,7 +52,7 @@ Ice.Plugin.IceDiscovery=IceDiscovery:IceDiscovery.PluginFactory # Ice.Plugin.IceSSL=IceSSL:IceSSL.PluginFactory IceSSL.DefaultDir=../../../../certs -IceSSL.ImportCert.CurrentUser.Root=cacert.pem +IceSSL.CertAuthFile=cacert.pem IceSSL.CertFile=c_rsa1024.pfx IceSSL.Password=password diff --git a/cs/src/IceSSL/Plugin.cs b/cs/src/IceSSL/Plugin.cs index 12906320f85..77abae5bbed 100644 --- a/cs/src/IceSSL/Plugin.cs +++ b/cs/src/IceSSL/Plugin.cs @@ -56,6 +56,19 @@ namespace IceSSL abstract public void initialize(); /// <summary> + /// Specify the certificate authorities certificates to use + /// when validating SSL peer certificates. This must be done + /// before the plug-in is initialized; therefore, the application + /// must define the property Ice.InitPlugins=0, set the certificates, + /// and finally invoke initializePlugins on the PluginManager. + /// When the application supplies its own certificate authorities + /// certificates, the plug-in skips its normal property-based + /// configuration. + /// </summary> + /// <param name="certs">The certificate authorities certificates to use.</param> + abstract public void setCACertificates(X509Certificate2Collection certs); + + /// <summary> /// Specify the certificates to use for SSL connections. This /// must be done before the plug-in is initialized; therefore, /// the application must define the property Ice.InitPlugins=0, diff --git a/cs/src/IceSSL/PluginI.cs b/cs/src/IceSSL/PluginI.cs index 03fc8fca1b0..96cc476f8e1 100644 --- a/cs/src/IceSSL/PluginI.cs +++ b/cs/src/IceSSL/PluginI.cs @@ -57,6 +57,11 @@ namespace IceSSL { } + public override void setCACertificates(X509Certificate2Collection certs) + { + _engine.setCACertificates(certs); + } + public override void setCertificates(X509Certificate2Collection certs) { _engine.setCertificates(certs); diff --git a/cs/src/IceSSL/SSLEngine.cs b/cs/src/IceSSL/SSLEngine.cs index f75acee4959..1b27ffe1565 100644 --- a/cs/src/IceSSL/SSLEngine.cs +++ b/cs/src/IceSSL/SSLEngine.cs @@ -56,6 +56,13 @@ namespace IceSSL keySet = "DefaultKeySet"; } + _certStore = properties.getPropertyWithDefault(prefix + "CertStore", "CurrentUser"); + if(_certStore != "CurrentUser" && _certStore != "LocalMachine") + { + _logger.warning("Invalid IceSSL.CertStore value `" + _certStore + "' adjusted to `CurrentUser'"); + _certStore = "CurrentUser"; + } + X509KeyStorageFlags keyStorageFlags = X509KeyStorageFlags.DefaultKeySet; if(keySet.Equals("UserKeySet")) { @@ -272,9 +279,57 @@ namespace IceSSL } } + if(_caCerts == null) + { + string certAuthFile = properties.getProperty(prefix + "CertAuthFile"); + if(certAuthFile.Length > 0) + { + if(!checkPath(ref certAuthFile)) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: CA certificate file not found: " + certAuthFile; + throw e; + } + + _caCerts = new X509Certificate2Collection(); + try + { + _caCerts.Add(new X509Certificate2(certAuthFile)); + } + catch(CryptographicException ex) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(ex); + e.reason = "IceSSL: error while attempting to load CA certificate from " + certAuthFile; + throw e; + } + } + } + _initialized = true; } + internal string certStore() + { + return _certStore; + } + + internal X509Certificate2Collection caCerts() + { + return _caCerts; + } + + internal void setCACertificates(X509Certificate2Collection caCerts) + { + if(_initialized) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: plug-in is already initialized"; + throw e; + } + + _caCerts = caCerts; + } + internal void setCertificates(X509Certificate2Collection certs) { if(_initialized) @@ -1126,6 +1181,8 @@ namespace IceSSL private int _verifyDepthMax; private int _checkCRL; private X509Certificate2Collection _certs; + private string _certStore; + private X509Certificate2Collection _caCerts; private CertificateVerifier _verifier; private PasswordCallback _passwordCallback; private TrustManager _trustManager; diff --git a/cs/src/IceSSL/TransceiverI.cs b/cs/src/IceSSL/TransceiverI.cs index 27a5e6e2159..5d7e4f38aa6 100644 --- a/cs/src/IceSSL/TransceiverI.cs +++ b/cs/src/IceSSL/TransceiverI.cs @@ -502,6 +502,27 @@ namespace IceSSL { _verifyPeer = 0; } + + X509Certificate2Collection caCerts = _instance.engine().caCerts(); + if(caCerts != null) + { + _chainEngine = new X509Chain(_instance.engine().certStore() == "LocalMachine"); + // + // We need to set this flag to be able to use a certificate authority from the extra + // store. + // + _chainEngine.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; + + if(_instance.checkCRL() == 0) + { + _chainEngine.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + } + + foreach(X509Certificate2 cert in caCerts) + { + _chainEngine.ChainPolicy.ExtraStore.Add(cert); + } + } } private NativeConnectionInfo getNativeConnectionInfo() @@ -681,9 +702,24 @@ namespace IceSSL } } - private bool validationCallback(object sender, X509Certificate certificate, X509Chain chain, - SslPolicyErrors sslPolicyErrors) + private bool validationCallback(object sender, X509Certificate certificate, X509Chain chainEngine, + SslPolicyErrors policyErrors) { + + SslPolicyErrors sslPolicyErrors = policyErrors; + bool valid = false; + if(_chainEngine != null && certificate != null) + { + sslPolicyErrors = SslPolicyErrors.None; + valid = _chainEngine.Build(new X509Certificate2(certificate)); + if(_chainEngine.ChainStatus.Length > 0) + { + sslPolicyErrors = SslPolicyErrors.RemoteCertificateChainErrors; + } + } + + X509Chain chain = _chainEngine == null ? chainEngine : _chainEngine; + // // The certificate chain is not available via SslStream, and it is destroyed // after this callback returns, so we keep a reference to each of the @@ -748,13 +784,17 @@ namespace IceSSL int errorCount = chain.ChainStatus.Length; foreach(X509ChainStatus status in chain.ChainStatus) { - if((certificate.Subject == certificate.Issuer) && - (status.Status == X509ChainStatusFlags.UntrustedRoot)) + if(status.Status == X509ChainStatusFlags.UntrustedRoot && _chainEngine != null && valid) { // - // Untrusted root for self-signed certificate is OK. + // Untrusted root is OK when using our custom chain engine if + // the CA certificate is present in the chain policy extra store. // - --errorCount; + X509ChainElement e = chain.ChainElements[chain.ChainElements.Count - 1]; + if(_chainEngine.ChainPolicy.ExtraStore.Contains(e.Certificate)) + { + --errorCount; + } } else if(status.Status == X509ChainStatusFlags.Revoked) { @@ -862,6 +902,7 @@ namespace IceSSL private IceInternal.AsyncCallback _readCallback; private IceInternal.AsyncCallback _writeCallback; private X509Certificate2[] _chain; + private X509Chain _chainEngine; private const int StateNeedConnect = 0; private const int StateConnectPending = 1; diff --git a/cs/test/IceSSL/configuration/AllTests.cs b/cs/test/IceSSL/configuration/AllTests.cs index 886534ca7d7..5ee37b3a67e 100644 --- a/cs/test/IceSSL/configuration/AllTests.cs +++ b/cs/test/IceSSL/configuration/AllTests.cs @@ -194,6 +194,45 @@ public class AllTests store.Remove(caCert1); comm.destroy(); } + + { + // + // Supply our own CA certificate. + // + X509Certificate2 cert = new X509Certificate2(defaultDir + "/cacert1.pem"); + X509Certificate2Collection coll = new X509Certificate2Collection(); + coll.Add(cert); + Ice.InitializationData initData = createClientProps(defaultProperties, testDir, defaultHost); + initData.properties.setProperty("Ice.InitPlugins", "0"); + initData.properties.setProperty("IceSSL.CertFile", defaultDir + "/c_rsa_nopass_ca1.pfx"); + initData.properties.setProperty("IceSSL.Password", "password"); + Ice.Communicator comm = Ice.Util.initialize(ref args, initData); + Ice.PluginManager pm = comm.getPluginManager(); + IceSSL.Plugin plugin = (IceSSL.Plugin)pm.getPlugin("IceSSL"); + test(plugin != null); + plugin.setCACertificates(coll); + pm.initializePlugins(); + Ice.ObjectPrx obj = comm.stringToProxy(factoryRef); + test(obj != null); + Test.ServerFactoryPrx fact = Test.ServerFactoryPrxHelper.checkedCast(obj); + Dictionary<string, string> d = createServerProps(defaultProperties, testDir, defaultHost); + d["IceSSL.CertFile"] = defaultDir + "/s_rsa_nopass_ca1.pfx"; + d["IceSSL.CertAuthFile"] = defaultDir + "/cacert1.pem"; + d["IceSSL.Password"] = "password"; + d["IceSSL.VerifyPeer"] = "2"; + Test.ServerPrx server = fact.createServer(d); + try + { + server.ice_ping(); + } + catch(Ice.LocalException ex) + { + Console.WriteLine(ex.ToString()); + test(false); + } + fact.destroyServer(server); + comm.destroy(); + } Console.Out.WriteLine("ok"); Console.Out.Write("testing certificate verification... "); diff --git a/scripts/TestUtil.py b/scripts/TestUtil.py index b3f4751945f..55044f19089 100755 --- a/scripts/TestUtil.py +++ b/scripts/TestUtil.py @@ -699,12 +699,11 @@ sslConfigTree = { "colloc" : " --IceSSL.Keystore=client.jks" }, "cs" : { - "plugin" : " --Ice.Plugin.IceSSL=%(icesslcs)s:IceSSL.PluginFactory " + - " --IceSSL.Password=password --IceSSL.DefaultDir=%(certsdir)s --IceSSL.VerifyPeer=%(verifyPeer)s", + "plugin" : " --Ice.Plugin.IceSSL=%(icesslcs)s:IceSSL.PluginFactory --IceSSL.CertAuthFile=cacert.pem " + + "--IceSSL.Password=password --IceSSL.DefaultDir=%(certsdir)s --IceSSL.VerifyPeer=%(verifyPeer)s", "client" : " --IceSSL.CertFile=c_rsa1024.pfx --IceSSL.CheckCertName=0", - "server" : " --IceSSL.CertFile=s_rsa1024.pfx --IceSSL.ImportCert.CurrentUser.Root=cacert.pem", - "colloc" : " --IceSSL.CertFile=c_rsa1024.pfx --IceSSL.ImportCert.CurrentUser.Root=cacert.pem " + - "--IceSSL.CheckCertName=0" + "server" : " --IceSSL.CertFile=s_rsa1024.pfx", + "colloc" : " --IceSSL.CertFile=c_rsa1024.pfx --IceSSL.CheckCertName=0" }, } |