summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/PropertyNames.xml5
-rw-r--r--cpp/config/Make.rules4
-rw-r--r--cpp/config/Make.rules.Darwin6
-rw-r--r--cpp/demo/Glacier2/callback/config.client2
-rw-r--r--cpp/demo/Glacier2/callback/config.glacier22
-rw-r--r--cpp/demo/Glacier2/chat/config.client2
-rw-r--r--cpp/demo/Glacier2/chat/config.glacier22
-rw-r--r--cpp/demo/Ice/callback/config.client2
-rw-r--r--cpp/demo/Ice/callback/config.server2
-rw-r--r--cpp/demo/Ice/hello/config.client2
-rw-r--r--cpp/demo/Ice/hello/config.server2
-rwxr-xr-xcpp/demo/Ice/interleaved/config.client3
-rwxr-xr-xcpp/demo/Ice/interleaved/config.server2
-rw-r--r--cpp/demo/Ice/invoke/config.client2
-rw-r--r--cpp/demo/Ice/invoke/config.server2
-rw-r--r--cpp/demo/Ice/latency/config.client2
-rw-r--r--cpp/demo/Ice/latency/config.server2
-rw-r--r--cpp/demo/Ice/nested/config.client2
-rw-r--r--cpp/demo/Ice/nested/config.server2
-rw-r--r--cpp/demo/Ice/nrvo/config.client3
-rw-r--r--cpp/demo/Ice/nrvo/config.server2
-rw-r--r--cpp/demo/Ice/properties/config.client2
-rw-r--r--cpp/demo/Ice/properties/config.server2
-rw-r--r--cpp/demo/Ice/throughput/config.client2
-rw-r--r--cpp/demo/Ice/throughput/config.server2
-rw-r--r--cpp/demo/IceBox/hello/config.client2
-rw-r--r--cpp/demo/IceBox/hello/config.service2
-rw-r--r--cpp/demo/IceDiscovery/hello/config.client2
-rw-r--r--cpp/demo/IceDiscovery/hello/config.server2
-rw-r--r--cpp/demo/IceGrid/secure/application.xml2
-rw-r--r--cpp/demo/IceGrid/secure/config.glacier22
-rw-r--r--cpp/demo/IceGrid/secure/config.master2
-rw-r--r--cpp/demo/IceGrid/secure/config.node2
-rw-r--r--cpp/demo/IceGrid/secure/config.slave2
-rwxr-xr-xcpp/demo/IceGrid/secure/expect.py9
-rw-r--r--cpp/include/IceSSL/Config.h16
-rw-r--r--cpp/include/IceSSL/Plugin.h111
-rw-r--r--cpp/include/IceUtil/FileUtil.h3
-rw-r--r--cpp/src/Ice/Network.h2
-rw-r--r--cpp/src/Ice/PropertyNames.cpp11
-rw-r--r--cpp/src/Ice/PropertyNames.h2
-rw-r--r--cpp/src/IceSSL/AcceptorI.cpp4
-rw-r--r--cpp/src/IceSSL/Certificate.cpp531
-rw-r--r--cpp/src/IceSSL/ConnectorI.cpp3
-rw-r--r--cpp/src/IceSSL/EndpointI.cpp2
-rw-r--r--cpp/src/IceSSL/Instance.cpp1156
-rw-r--r--cpp/src/IceSSL/Instance.h93
-rw-r--r--cpp/src/IceSSL/InstanceF.h4
-rw-r--r--cpp/src/IceSSL/Makefile18
-rw-r--r--cpp/src/IceSSL/Makefile.mak4
-rw-r--r--cpp/src/IceSSL/OpenSSLEngine.cpp920
-rw-r--r--cpp/src/IceSSL/PluginI.cpp41
-rw-r--r--cpp/src/IceSSL/PluginI.h22
-rw-r--r--cpp/src/IceSSL/RFC2253.cpp1
-rw-r--r--cpp/src/IceSSL/SSLEngine.cpp291
-rw-r--r--cpp/src/IceSSL/SSLEngine.h179
-rw-r--r--cpp/src/IceSSL/SSLEngineF.h37
-rw-r--r--cpp/src/IceSSL/SecureTransportEngine.cpp1515
-rw-r--r--cpp/src/IceSSL/SecureTransportTransceiverI.cpp1055
-rw-r--r--cpp/src/IceSSL/SecureTransportTransceiverI.h114
-rw-r--r--cpp/src/IceSSL/TransceiverI.cpp49
-rw-r--r--cpp/src/IceSSL/TransceiverI.h10
-rw-r--r--cpp/src/IceSSL/Util.cpp640
-rw-r--r--cpp/src/IceSSL/Util.h78
-rw-r--r--cpp/src/IceUtil/FileUtil.cpp11
-rwxr-xr-xcpp/src/ca/iceca8
-rw-r--r--cpp/test/Ice/hash/Client.cpp2
-rw-r--r--cpp/test/Ice/timeout/AllTests.cpp2
-rw-r--r--cpp/test/Ice/timeout/Client.cpp2
-rw-r--r--cpp/test/Ice/timeout/Server.cpp6
-rw-r--r--cpp/test/IceGrid/session/Server.cpp6
-rw-r--r--cpp/test/IceSSL/certs/dh_params1024.derbin0 -> 138 bytes
-rw-r--r--cpp/test/IceSSL/certs/dh_params512.derbin0 -> 72 bytes
-rwxr-xr-xcpp/test/IceSSL/certs/makecerts11
-rw-r--r--cpp/test/IceSSL/configuration/AllTests.cpp216
-rw-r--r--cpp/test/IceSSL/configuration/Makefile8
-rw-r--r--cpp/test/IceSSL/configuration/TestI.cpp5
-rw-r--r--cpp/test/IceSSL/configuration/Util.h37
-rw-r--r--cs/src/Ice/PropertyNames.cs11
-rw-r--r--java/src/IceInternal/PropertyNames.java11
-rw-r--r--js/src/Ice/PropertyNames.js6
-rw-r--r--py/demo/Glacier2/callback/config.client2
-rw-r--r--py/demo/Glacier2/callback/config.glacier23
-rw-r--r--py/demo/Ice/callback/config.client2
-rw-r--r--py/demo/Ice/callback/config.server2
-rw-r--r--py/demo/Ice/hello/config.client2
-rw-r--r--py/demo/Ice/hello/config.server2
-rw-r--r--py/demo/Ice/latency/config.client2
-rw-r--r--py/demo/Ice/latency/config.server2
-rw-r--r--py/demo/Ice/properties/config.client2
-rw-r--r--py/demo/Ice/properties/config.server2
-rw-r--r--py/demo/Ice/throughput/config.client2
-rw-r--r--py/demo/Ice/throughput/config.server2
-rw-r--r--py/test/Ice/timeout/AllTests.py14
-rwxr-xr-xpy/test/Ice/timeout/Client.py2
-rw-r--r--rb/demo/Ice/hello/config.client2
-rw-r--r--rb/demo/Ice/latency/config.client2
-rw-r--r--rb/demo/Ice/throughput/config.client2
-rw-r--r--rb/test/Ice/timeout/AllTests.rb12
-rwxr-xr-xscripts/TestUtil.py6
100 files changed, 5942 insertions, 1465 deletions
diff --git a/config/PropertyNames.xml b/config/PropertyNames.xml
index 0b718a9c058..f50ff305d7b 100644
--- a/config/PropertyNames.xml
+++ b/config/PropertyNames.xml
@@ -535,12 +535,15 @@ generated from the section label.
<property name="Ciphers" />
<property name="DefaultDir" />
<property name="DH.[any]" />
+ <property name="DHParams" />
<property name="EntropyDaemon" />
<property name="FindCert.[any]" />
<property name="ImportCert.[any]" />
<property name="InitOpenSSL" />
<property name="KeyFile" />
<property name="KeySet"/>
+ <property name="Keychain"/>
+ <property name="KeychainPassword"/>
<property name="Keystore" />
<property name="KeystorePassword" />
<property name="KeystoreType" />
@@ -549,6 +552,8 @@ generated from the section label.
<property name="PasswordRetryMax" />
<property name="PersistKeySet"/>
<property name="Protocols" />
+ <property name="ProtocolVersionMax" />
+ <property name="ProtocolVersionMin" />
<property name="Random" />
<property name="Trace.Security" />
<property name="TrustOnly" />
diff --git a/cpp/config/Make.rules b/cpp/config/Make.rules
index 03e1d2cbb27..54fa9d6c81a 100644
--- a/cpp/config/Make.rules
+++ b/cpp/config/Make.rules
@@ -204,6 +204,10 @@ ifeq ($(OPENSSL_LIBS),)
endif
OPENSSL_RPATH_LINK = $(if $(OPENSSL_HOME),$(call rpathlink,$(OPENSSL_HOME)/$(libsubdir)))
+ifeq ($(SSL_OS_LIBS),)
+ SSL_OS_LIBS = $(OPENSSL_LIBS)
+endif
+
BZIP2_FLAGS = $(if $(BZIP2_HOME),-I$(BZIP2_HOME)/include)
ifeq ($(BZIP2_LIBS),)
BZIP2_LIBS = $(if $(BZIP2_HOME),-L$(BZIP2_HOME)/$(libsubdir)) -lbz2
diff --git a/cpp/config/Make.rules.Darwin b/cpp/config/Make.rules.Darwin
index 7f6cc37e2e4..d59297b43b1 100644
--- a/cpp/config/Make.rules.Darwin
+++ b/cpp/config/Make.rules.Darwin
@@ -15,8 +15,8 @@ OSX_TARGET_MIN_SDK_VERSION = 10.8
CXX = xcrun clang++
-CPPFLAGS += -pthread
-CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -Wall -Werror -mmacosx-version-min=$(OSX_TARGET_MIN_SDK_VERSION)
+CPPFLAGS += -pthread
+CXXFLAGS += -Wall -Werror -mmacosx-version-min=$(OSX_TARGET_MIN_SDK_VERSION)
ifeq ($(OPTIMIZE),yes)
#
@@ -76,4 +76,6 @@ ICONV_LIB = -liconv
ICEUTIL_OS_LIBS =
ICE_OS_LIBS = -ldl
+SSL_OS_LIBS = -framework Security -framework CoreFoundation
+
PLATFORM_HAS_READLINE := yes
diff --git a/cpp/demo/Glacier2/callback/config.client b/cpp/demo/Glacier2/callback/config.client
index 250ed196408..6d6b5365d62 100644
--- a/cpp/demo/Glacier2/callback/config.client
+++ b/cpp/demo/Glacier2/callback/config.client
@@ -49,3 +49,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password \ No newline at end of file
diff --git a/cpp/demo/Glacier2/callback/config.glacier2 b/cpp/demo/Glacier2/callback/config.glacier2
index ff9a3550c2c..b1e379eeb40 100644
--- a/cpp/demo/Glacier2/callback/config.glacier2
+++ b/cpp/demo/Glacier2/callback/config.glacier2
@@ -126,3 +126,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=glacier2.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Glacier2/chat/config.client b/cpp/demo/Glacier2/chat/config.client
index 93312f8c547..64c7e27d6c3 100644
--- a/cpp/demo/Glacier2/chat/config.client
+++ b/cpp/demo/Glacier2/chat/config.client
@@ -43,6 +43,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/cpp/demo/Glacier2/chat/config.glacier2 b/cpp/demo/Glacier2/chat/config.glacier2
index de080939094..e6680be52a7 100644
--- a/cpp/demo/Glacier2/chat/config.glacier2
+++ b/cpp/demo/Glacier2/chat/config.glacier2
@@ -57,6 +57,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=glacier2.keychain
+IceSSL.KeychainPassword=password
#
# Uncomment the properties below if you want run the demo with the
diff --git a/cpp/demo/Ice/callback/config.client b/cpp/demo/Ice/callback/config.client
index acd7e0f4b33..000b2146af1 100644
--- a/cpp/demo/Ice/callback/config.client
+++ b/cpp/demo/Ice/callback/config.client
@@ -50,3 +50,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/callback/config.server b/cpp/demo/Ice/callback/config.server
index ad65f43d4d8..048f0045f62 100644
--- a/cpp/demo/Ice/callback/config.server
+++ b/cpp/demo/Ice/callback/config.server
@@ -44,3 +44,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/hello/config.client b/cpp/demo/Ice/hello/config.client
index 6140a70ea4a..b791b95194a 100644
--- a/cpp/demo/Ice/hello/config.client
+++ b/cpp/demo/Ice/hello/config.client
@@ -53,6 +53,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/cpp/demo/Ice/hello/config.server b/cpp/demo/Ice/hello/config.server
index ae02d1fdbd1..e576633d0b7 100644
--- a/cpp/demo/Ice/hello/config.server
+++ b/cpp/demo/Ice/hello/config.server
@@ -54,6 +54,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
#
# Uncomment the properties below if you want run the demo with the
diff --git a/cpp/demo/Ice/interleaved/config.client b/cpp/demo/Ice/interleaved/config.client
index e3c81d95d64..181a670fe23 100755
--- a/cpp/demo/Ice/interleaved/config.client
+++ b/cpp/demo/Ice/interleaved/config.client
@@ -17,4 +17,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
-
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/interleaved/config.server b/cpp/demo/Ice/interleaved/config.server
index 78ecfdadf53..b3afa959f38 100755
--- a/cpp/demo/Ice/interleaved/config.server
+++ b/cpp/demo/Ice/interleaved/config.server
@@ -29,3 +29,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/invoke/config.client b/cpp/demo/Ice/invoke/config.client
index c9ab176fc28..bbf5b32c3c4 100644
--- a/cpp/demo/Ice/invoke/config.client
+++ b/cpp/demo/Ice/invoke/config.client
@@ -43,3 +43,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/invoke/config.server b/cpp/demo/Ice/invoke/config.server
index 599bffc673b..afb8a12a7e1 100644
--- a/cpp/demo/Ice/invoke/config.server
+++ b/cpp/demo/Ice/invoke/config.server
@@ -44,3 +44,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/latency/config.client b/cpp/demo/Ice/latency/config.client
index 74332ccceab..43061f18a12 100644
--- a/cpp/demo/Ice/latency/config.client
+++ b/cpp/demo/Ice/latency/config.client
@@ -29,6 +29,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/cpp/demo/Ice/latency/config.server b/cpp/demo/Ice/latency/config.server
index 24219cabf08..e324e7659e5 100644
--- a/cpp/demo/Ice/latency/config.server
+++ b/cpp/demo/Ice/latency/config.server
@@ -27,6 +27,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/cpp/demo/Ice/nested/config.client b/cpp/demo/Ice/nested/config.client
index 01c322a06f1..86de72eaed0 100644
--- a/cpp/demo/Ice/nested/config.client
+++ b/cpp/demo/Ice/nested/config.client
@@ -61,3 +61,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/nested/config.server b/cpp/demo/Ice/nested/config.server
index d65b25550e6..92bce3de59a 100644
--- a/cpp/demo/Ice/nested/config.server
+++ b/cpp/demo/Ice/nested/config.server
@@ -55,3 +55,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password \ No newline at end of file
diff --git a/cpp/demo/Ice/nrvo/config.client b/cpp/demo/Ice/nrvo/config.client
index 6a2ab473a5d..fc38babe618 100644
--- a/cpp/demo/Ice/nrvo/config.client
+++ b/cpp/demo/Ice/nrvo/config.client
@@ -12,4 +12,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
-
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/nrvo/config.server b/cpp/demo/Ice/nrvo/config.server
index 053eecddce8..d0f78c0f18a 100644
--- a/cpp/demo/Ice/nrvo/config.server
+++ b/cpp/demo/Ice/nrvo/config.server
@@ -18,3 +18,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/properties/config.client b/cpp/demo/Ice/properties/config.client
index 8b079dfc267..c0d74a6be27 100644
--- a/cpp/demo/Ice/properties/config.client
+++ b/cpp/demo/Ice/properties/config.client
@@ -49,3 +49,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/properties/config.server b/cpp/demo/Ice/properties/config.server
index 3fae2c52d4d..2969290fd56 100644
--- a/cpp/demo/Ice/properties/config.server
+++ b/cpp/demo/Ice/properties/config.server
@@ -59,3 +59,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
diff --git a/cpp/demo/Ice/throughput/config.client b/cpp/demo/Ice/throughput/config.client
index 0329afc63d2..8dd16d1c369 100644
--- a/cpp/demo/Ice/throughput/config.client
+++ b/cpp/demo/Ice/throughput/config.client
@@ -29,6 +29,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/cpp/demo/Ice/throughput/config.server b/cpp/demo/Ice/throughput/config.server
index 85adf59767d..4d422916147 100644
--- a/cpp/demo/Ice/throughput/config.server
+++ b/cpp/demo/Ice/throughput/config.server
@@ -28,6 +28,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/cpp/demo/IceBox/hello/config.client b/cpp/demo/IceBox/hello/config.client
index c6fb2622b1b..59af9979d56 100644
--- a/cpp/demo/IceBox/hello/config.client
+++ b/cpp/demo/IceBox/hello/config.client
@@ -43,3 +43,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password \ No newline at end of file
diff --git a/cpp/demo/IceBox/hello/config.service b/cpp/demo/IceBox/hello/config.service
index 2b91e157f7f..b4a2ff5e2d3 100644
--- a/cpp/demo/IceBox/hello/config.service
+++ b/cpp/demo/IceBox/hello/config.service
@@ -43,3 +43,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=service.keychain
+IceSSL.KeychainPassword=password \ No newline at end of file
diff --git a/cpp/demo/IceDiscovery/hello/config.client b/cpp/demo/IceDiscovery/hello/config.client
index 7303f6c6797..7358239c4a6 100644
--- a/cpp/demo/IceDiscovery/hello/config.client
+++ b/cpp/demo/IceDiscovery/hello/config.client
@@ -21,6 +21,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/cpp/demo/IceDiscovery/hello/config.server b/cpp/demo/IceDiscovery/hello/config.server
index d03024f20cf..bbacf2c65fa 100644
--- a/cpp/demo/IceDiscovery/hello/config.server
+++ b/cpp/demo/IceDiscovery/hello/config.server
@@ -29,6 +29,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
#
# Uncomment the properties below if you want run the demo with the
diff --git a/cpp/demo/IceGrid/secure/application.xml b/cpp/demo/IceGrid/secure/application.xml
index 2f0b2d59374..c0d4d6e17ff 100644
--- a/cpp/demo/IceGrid/secure/application.xml
+++ b/cpp/demo/IceGrid/secure/application.xml
@@ -18,6 +18,8 @@
<property name="IceSSL.CertFile" value="server_cert.pem"/>
<property name="IceSSL.KeyFile" value="server_key.pem"/>
<property name="IceSSL.DefaultDir" value="certs"/>
+ <property name="IceSSL.Keychain" value="server.keychain"/>
+ <property name="IceSSL.KeychainPassword" value="password"/>
<property name="Ice.Admin.Endpoints" value="ssl -h localhost"/>
<property name="IceSSL.TrustOnly.Client" value="CN=Master;CN=Slave"/>
diff --git a/cpp/demo/IceGrid/secure/config.glacier2 b/cpp/demo/IceGrid/secure/config.glacier2
index 83f7317aa22..a54d78c70a2 100644
--- a/cpp/demo/IceGrid/secure/config.glacier2
+++ b/cpp/demo/IceGrid/secure/config.glacier2
@@ -21,6 +21,8 @@ IceSSL.DefaultDir=certs
IceSSL.CertAuthFile=ca_cert.pem
IceSSL.CertFile=glacier2_cert.pem
IceSSL.KeyFile=glacier2_key.pem
+IceSSL.Keychain=glacier2.keychain
+IceSSL.KeychainPassword=password
#
# Don't require certificates. This is useful for admin clients that don't
diff --git a/cpp/demo/IceGrid/secure/config.master b/cpp/demo/IceGrid/secure/config.master
index 2b5a672355b..551bc373cfb 100644
--- a/cpp/demo/IceGrid/secure/config.master
+++ b/cpp/demo/IceGrid/secure/config.master
@@ -40,6 +40,8 @@ IceSSL.DefaultDir=certs
IceSSL.CertAuthFile=ca_cert.pem
IceSSL.CertFile=master_cert.pem
IceSSL.KeyFile=master_key.pem
+IceSSL.Keychain=master.keychain
+IceSSL.KeychainPassword=password
#
# Don't require certificates. This is useful for admin clients that don't
diff --git a/cpp/demo/IceGrid/secure/config.node b/cpp/demo/IceGrid/secure/config.node
index d4323c737d9..7b9864cea3e 100644
--- a/cpp/demo/IceGrid/secure/config.node
+++ b/cpp/demo/IceGrid/secure/config.node
@@ -25,6 +25,8 @@ IceSSL.DefaultDir=certs
IceSSL.CertAuthFile=ca_cert.pem
IceSSL.CertFile=node_cert.pem
IceSSL.KeyFile=node_key.pem
+IceSSL.Keychain=node.keychain
+IceSSL.KeychainPassword=password
IceSSL.TrustOnly.Client=CN="Server";CN="Master";CN="Slave"
IceSSL.TrustOnly.Server=CN="Master";CN="Slave"
diff --git a/cpp/demo/IceGrid/secure/config.slave b/cpp/demo/IceGrid/secure/config.slave
index 0847f9c5207..682651e969a 100644
--- a/cpp/demo/IceGrid/secure/config.slave
+++ b/cpp/demo/IceGrid/secure/config.slave
@@ -45,6 +45,8 @@ IceSSL.DefaultDir=certs
IceSSL.CertAuthFile=ca_cert.pem
IceSSL.CertFile=slave_cert.pem
IceSSL.KeyFile=slave_key.pem
+IceSSL.Keychain=slave.keychain
+IceSSL.KeychainPassword=password
#
# Don't require certificates. This is useful for admin clients that don't
diff --git a/cpp/demo/IceGrid/secure/expect.py b/cpp/demo/IceGrid/secure/expect.py
index 0d74ba486e9..14e62d4a8fa 100755
--- a/cpp/demo/IceGrid/secure/expect.py
+++ b/cpp/demo/IceGrid/secure/expect.py
@@ -29,6 +29,15 @@ Util.cleanDbDir("db/node")
Util.cleanDbDir("certs")
print("ok")
+if sys.platform == "darwin":
+ sys.stdout.write("cleaning keychains... ")
+ for f in ["master", "slave", "node", "glacier2", "admin", "server"]:
+ try:
+ os.remove(f + ".keychain")
+ except:
+ pass
+ print("ok")
+
if Util.defaultHost:
args = ' --IceGrid.Node.PropertiesOverride="Ice.Default.Host=127.0.0.1"'
else:
diff --git a/cpp/include/IceSSL/Config.h b/cpp/include/IceSSL/Config.h
new file mode 100644
index 00000000000..f28999ee1f7
--- /dev/null
+++ b/cpp/include/IceSSL/Config.h
@@ -0,0 +1,16 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#include <Ice/Config.h>
+
+#ifdef __APPLE__
+# define ICE_USE_SECURE_TRANSPORT 1
+#else
+# define ICE_USE_OPENSSL 1
+#endif
diff --git a/cpp/include/IceSSL/Plugin.h b/cpp/include/IceSSL/Plugin.h
index b2456c2eab1..b16db92e40a 100644
--- a/cpp/include/IceSSL/Plugin.h
+++ b/cpp/include/IceSSL/Plugin.h
@@ -12,6 +12,7 @@
#include <IceUtil/Time.h>
#include <Ice/Plugin.h>
+#include <IceSSL/Config.h>
#include <IceSSL/ConnectionInfo.h>
#include <vector>
@@ -32,22 +33,48 @@
# endif
#endif
+#ifdef ICE_USE_OPENSSL
//
-// SSL_CTX is the OpenSSL type that holds configuration settings for
-// all SSL connections.
+// Pointer to an opaque SSL session context object. ssl_ctx_st is the
+// OpenSSL type that holds configuration settings for all SSL
+// connections.
//
-typedef struct ssl_ctx_st SSL_CTX;
+typedef struct ssl_ctx_st* ContextRef;
//
-// X509 is the OpenSSL type that represents a certificate.
+// Pointer to an opaque certificate object. X509_st is the OpenSSL
+// type that represents a certificate.
//
-typedef struct x509_st X509;
-typedef struct X509_name_st X509NAME;
+typedef struct x509_st* X509CertificateRef;
//
// EVP_PKEY is the OpenSSL type that represents a public key.
//
-typedef struct evp_pkey_st EVP_PKEY;
+typedef struct evp_pkey_st* KeyRef;
+
+
+#elif defined(ICE_USE_SECURE_TRANSPORT)
+
+//
+// Pointer to an opaque SSL session context object. The SSL session context
+// object references the state associated with a session.
+//
+struct SSLContext;
+typedef struct SSLContext* ContextRef;
+
+//
+// Pointer to an opanque certificate object.
+//
+struct OpaqueSecCertificateRef;
+typedef struct OpaqueSecCertificateRef* X509CertificateRef;
+
+//
+// Pointer to an opaque connection objecct.
+//
+struct OpaqueSecKeyRef;
+typedef struct OpaqueSecKeyRef* KeyRef;
+
+#endif
namespace IceSSL
{
@@ -127,14 +154,14 @@ public:
~PublicKey();
- EVP_PKEY* key() const;
+ KeyRef key() const;
private:
- PublicKey(EVP_PKEY*);
+ PublicKey(KeyRef);
friend class Certificate;
- EVP_PKEY* _key;
+ KeyRef _key;
};
typedef IceUtil::Handle<PublicKey> PublicKeyPtr;
@@ -155,11 +182,6 @@ class ICE_SSL_API DistinguishedName
public:
//
- // Create a DistinguishedName using an OpenSSL value.
- //
- DistinguishedName(X509NAME*);
-
- //
// Create a DistinguishedName from a string encoded using
// the rules in RFC2253.
//
@@ -215,7 +237,7 @@ public:
// Construct a certificate using a X509*. The Certificate assumes
// ownership of the X509* struct.
//
- Certificate(X509*);
+ Certificate(X509CertificateRef);
~Certificate();
//
@@ -240,10 +262,16 @@ public:
PublicKeyPtr getPublicKey() const;
//
+ // Verify that this certificate was signed by the given certificate
+ // public key. Returns true if signed, false otherwise.
+ //
+ bool verify(const CertificatePtr&) const;
+
+ //
// Verify that this certificate was signed by the given public
// key. Returns true if signed, false otherwise.
//
- bool verify(const PublicKeyPtr&) const;
+ ICE_DEPRECATED_API bool verify(const PublicKeyPtr&) const;
//
// Return a string encoding of the certificate in PEM format.
@@ -347,18 +375,18 @@ public:
// for the lifetime of this object unless the caller increments its
// reference count explicitly using X509_dup.
//
- X509* getCert() const;
+ X509CertificateRef getCert() const;
private:
- X509* _cert;
+ X509CertificateRef _cert;
};
//
// NativeConnectionInfo is an extension of IceSSL::ConnectionInfo that
// provides access to native certificates.
//
-class NativeConnectionInfo : public ConnectionInfo
+class ICE_SSL_API NativeConnectionInfo : public ConnectionInfo
{
public:
@@ -375,7 +403,7 @@ typedef IceUtil::Handle<NativeConnectionInfo> NativeConnectionInfoPtr;
// An application can customize the certificate verification process
// by implementing the CertificateVerifier interface.
//
-class CertificateVerifier : public IceUtil::Shared
+class ICE_SSL_API CertificateVerifier : public IceUtil::Shared
{
public:
@@ -402,7 +430,7 @@ typedef IceUtil::Handle<CertificateVerifier> CertificateVerifierPtr;
// IceSSL.DelayInit=1), configure the PasswordPrompt, then manually
// initialize the plug-in.
//
-class PasswordPrompt : public IceUtil::Shared
+class ICE_SSL_API PasswordPrompt : public IceUtil::Shared
{
public:
@@ -415,11 +443,30 @@ public:
};
typedef IceUtil::Handle<PasswordPrompt> PasswordPromptPtr;
-class Plugin : public Ice::Plugin
+class ICE_SSL_API Plugin : public Ice::Plugin
{
public:
//
+ // Establish the certificate verifier object. This should be done
+ // before any connections are established.
+ //
+ virtual void setCertificateVerifier(const CertificateVerifierPtr&) = 0;
+
+ //
+ // Establish the password prompt object. This must be done before
+ // the plug-in is initialized.
+ //
+ virtual void setPasswordPrompt(const PasswordPromptPtr&) = 0;
+};
+typedef IceUtil::Handle<Plugin> PluginPtr;
+
+#ifdef ICE_USE_OPENSSL
+class ICE_SSL_API OpenSSLPlugin : public Plugin
+{
+public:
+
+ //
// Establish the OpenSSL context. This must be done before the
// plug-in is initialized, therefore the application must define
// the property Ice.InitPlugins=0, set the context, and finally
@@ -431,27 +478,15 @@ public:
//
// Note that the plugin assumes ownership of the given context.
//
- virtual void setContext(SSL_CTX*) = 0;
+ virtual void setContext(ContextRef) = 0;
//
// Obtain the SSL context. Use caution when modifying this value.
// Changes made to this value have no effect on existing connections.
//
- virtual SSL_CTX* getContext() = 0;
-
- //
- // Establish the certificate verifier object. This should be done
- // before any connections are established.
- //
- virtual void setCertificateVerifier(const CertificateVerifierPtr&) = 0;
-
- //
- // Establish the password prompt object. This must be done before
- // the plug-in is initialized.
- //
- virtual void setPasswordPrompt(const PasswordPromptPtr&) = 0;
+ virtual ContextRef getContext() = 0;
};
-typedef IceUtil::Handle<Plugin> PluginPtr;
+#endif
}
diff --git a/cpp/include/IceUtil/FileUtil.h b/cpp/include/IceUtil/FileUtil.h
index 7fabce927b9..57bb8f369cd 100644
--- a/cpp/include/IceUtil/FileUtil.h
+++ b/cpp/include/IceUtil/FileUtil.h
@@ -22,6 +22,9 @@
namespace IceUtilInternal
{
+extern const ICE_UTIL_API std::string pathsep;
+extern const ICE_UTIL_API std::string separator;
+
//
// Detemine if path is an absolute path.
//
diff --git a/cpp/src/Ice/Network.h b/cpp/src/Ice/Network.h
index f8928c11f7b..3bc5856aea6 100644
--- a/cpp/src/Ice/Network.h
+++ b/cpp/src/Ice/Network.h
@@ -168,7 +168,7 @@ public:
{
}
- SOCKET fd()
+ SOCKET fd() const
{
return _fd;
}
diff --git a/cpp/src/Ice/PropertyNames.cpp b/cpp/src/Ice/PropertyNames.cpp
index c9bc11dc890..c173ecfaa82 100644
--- a/cpp/src/Ice/PropertyNames.cpp
+++ b/cpp/src/Ice/PropertyNames.cpp
@@ -6,7 +6,7 @@
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
-// Generated by makeprops.py from file ./config/PropertyNames.xml, Wed Jun 4 19:01:29 2014
+// Generated by makeprops.py from file ../config/PropertyNames.xml, Thu Jun 5 21:19:31 2014
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
@@ -109,8 +109,7 @@ const IceInternal::Property IcePropsData[] =
IceInternal::Property("Ice.IPv6", false, 0),
IceInternal::Property("Ice.EventLog.Source", false, 0),
IceInternal::Property("Ice.FactoryAssemblies", false, 0),
- IceInternal::Property("Ice.GC", false, 0),
- IceInternal::Property("Ice.GC.Interval", true, "Ice.GC"),
+ IceInternal::Property("Ice.CollectObjects", false, 0),
IceInternal::Property("Ice.ImplicitContext", false, 0),
IceInternal::Property("Ice.InitPlugins", false, 0),
IceInternal::Property("Ice.LogFile", false, 0),
@@ -155,7 +154,6 @@ const IceInternal::Property IcePropsData[] =
IceInternal::Property("Ice.ThreadPool.Server.ThreadPriority", false, 0),
IceInternal::Property("Ice.ThreadPriority", false, 0),
IceInternal::Property("Ice.Trace.Admin.Properties", false, 0),
- IceInternal::Property("Ice.Trace.GC", true, 0),
IceInternal::Property("Ice.Trace.Locator", false, 0),
IceInternal::Property("Ice.Trace.Network", false, 0),
IceInternal::Property("Ice.Trace.Protocol", false, 0),
@@ -841,12 +839,15 @@ const IceInternal::Property IceSSLPropsData[] =
IceInternal::Property("IceSSL.Ciphers", false, 0),
IceInternal::Property("IceSSL.DefaultDir", false, 0),
IceInternal::Property("IceSSL.DH.*", false, 0),
+ IceInternal::Property("IceSSL.DHParams", false, 0),
IceInternal::Property("IceSSL.EntropyDaemon", false, 0),
IceInternal::Property("IceSSL.FindCert.*", false, 0),
IceInternal::Property("IceSSL.ImportCert.*", false, 0),
IceInternal::Property("IceSSL.InitOpenSSL", false, 0),
IceInternal::Property("IceSSL.KeyFile", false, 0),
IceInternal::Property("IceSSL.KeySet", false, 0),
+ IceInternal::Property("IceSSL.Keychain", false, 0),
+ IceInternal::Property("IceSSL.KeychainPassword", false, 0),
IceInternal::Property("IceSSL.Keystore", false, 0),
IceInternal::Property("IceSSL.KeystorePassword", false, 0),
IceInternal::Property("IceSSL.KeystoreType", false, 0),
@@ -855,6 +856,8 @@ const IceInternal::Property IceSSLPropsData[] =
IceInternal::Property("IceSSL.PasswordRetryMax", false, 0),
IceInternal::Property("IceSSL.PersistKeySet", false, 0),
IceInternal::Property("IceSSL.Protocols", false, 0),
+ IceInternal::Property("IceSSL.ProtocolVersionMax", false, 0),
+ IceInternal::Property("IceSSL.ProtocolVersionMin", false, 0),
IceInternal::Property("IceSSL.Random", false, 0),
IceInternal::Property("IceSSL.Trace.Security", false, 0),
IceInternal::Property("IceSSL.TrustOnly", false, 0),
diff --git a/cpp/src/Ice/PropertyNames.h b/cpp/src/Ice/PropertyNames.h
index 7c33f285caf..8637fb4f1cd 100644
--- a/cpp/src/Ice/PropertyNames.h
+++ b/cpp/src/Ice/PropertyNames.h
@@ -6,7 +6,7 @@
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
-// Generated by makeprops.py from file ./config/PropertyNames.xml, Wed Jun 4 19:01:29 2014
+// Generated by makeprops.py from file ../config/PropertyNames.xml, Thu Jun 5 21:19:31 2014
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
diff --git a/cpp/src/IceSSL/AcceptorI.cpp b/cpp/src/IceSSL/AcceptorI.cpp
index 5780a9bae89..f835f6b8044 100644
--- a/cpp/src/IceSSL/AcceptorI.cpp
+++ b/cpp/src/IceSSL/AcceptorI.cpp
@@ -9,7 +9,9 @@
#include <IceSSL/AcceptorI.h>
#include <IceSSL/Instance.h>
+#include <IceSSL/SecureTransportTransceiverI.h>
#include <IceSSL/TransceiverI.h>
+
#include <IceSSL/Util.h>
#include <Ice/Communicator.h>
@@ -144,7 +146,7 @@ IceSSL::AcceptorI::accept()
//
// The plug-in may not be initialized.
//
- if(!_instance->context())
+ if(!_instance->initialized())
{
PluginInitializationException ex(__FILE__, __LINE__);
ex.reason = "IceSSL: plug-in is not initialized";
diff --git a/cpp/src/IceSSL/Certificate.cpp b/cpp/src/IceSSL/Certificate.cpp
index 71ef9a9fd96..5c7f7bf08d7 100644
--- a/cpp/src/IceSSL/Certificate.cpp
+++ b/cpp/src/IceSSL/Certificate.cpp
@@ -16,12 +16,11 @@
#include <IceSSL/RFC2253.h>
#include <Ice/Object.h>
-#include <openssl/x509v3.h>
-#include <openssl/pem.h>
-
-// Ignore OS X OpenSSL deprecation warnings
-#ifdef __APPLE__
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#ifdef ICE_USE_OPENSSL
+# include <openssl/x509v3.h>
+# include <openssl/pem.h>
+#elif defined(ICE_USE_SECURE_TRANSPORT)
+# include <Security/Security.h>
#endif
#ifdef __SUNPRO_CC
@@ -46,6 +45,270 @@ using namespace IceSSL;
const char* IceSSL::CertificateReadException::_name = "IceSSL::CertificateReadException";
+#ifdef ICE_USE_SECURE_TRANSPORT
+//
+// Map a certificate OID to its alias
+//
+struct CertificateOID
+{
+ const char* name;
+ const char* alias;
+};
+
+const CertificateOID certificateOIDS[] =
+{
+ {"2.5.4.3", "CN"},
+ {"2.5.4.4", "SN"},
+ {"2.5.4.5", "DeviceSerialNumber"},
+ {"2.5.4.6", "C"},
+ {"2.5.4.7", "L"},
+ {"2.5.4.8", "ST"},
+ {"2.5.4.9", "STREET"},
+ {"2.5.4.10", "O"},
+ {"2.5.4.11", "OU"},
+ {"2.5.4.12", "T"},
+ {"2.5.4.42", "G"},
+ {"2.5.4.43", "I"},
+ {"1.2.840.113549.1.9.8", "unstructuredAddress"},
+ {"1.2.840.113549.1.9.2", "unstructuredName"},
+ {"1.2.840.113549.1.9.1", "emailAddress"},
+ {"0.9.2342.19200300.100.1.25", "DC"}
+};
+
+const int certificateOIDSSize = sizeof(certificateOIDS) / sizeof(CertificateOID);
+
+string
+certificateOIDAlias(const string& name)
+{
+ for(int i = 0; i < certificateOIDSSize; ++i)
+ {
+ if(name == certificateOIDS[i].name)
+ {
+ return certificateOIDS[i].alias;
+ }
+ }
+ return name;
+}
+
+//
+// Map alternative name alias to its types.
+//
+const char* certificateAlternativeNameTypes[] = {"", "Email Address", "DNS Name", "", "Directory Name", "", "URI",
+ "IP Address"};
+const int certificateAlternativeNameTypesSize = sizeof(certificateAlternativeNameTypes) / sizeof(char*);
+
+int
+certificateAlternativeNameType(const string& alias)
+{
+ if(!alias.empty())
+ {
+ for(int i = 0; i < certificateAlternativeNameTypesSize; ++i)
+ {
+ if(alias == certificateAlternativeNameTypes[i])
+ {
+ return i;
+ }
+ }
+ }
+ return -1; // Not supported
+}
+
+string
+scapeX509Name(const string& name)
+{
+ ostringstream os;
+ for(string::const_iterator i = name.begin(); i != name.end(); ++i)
+ {
+ switch(*i)
+ {
+ case ',':
+ case '=':
+ case '+':
+ case '<':
+ case '>':
+ case '#':
+ case ';':
+ {
+ os << '\\';
+ }
+ default:
+ {
+ break;
+ }
+ }
+ os << *i;
+ }
+ return os.str();
+}
+
+DistinguishedName
+getX509Name(SecCertificateRef cert, CFTypeRef key)
+{
+ CFErrorRef err = 0;
+ assert(key == kSecOIDX509V1IssuerName || key == kSecOIDX509V1SubjectName);
+ CFArrayRef keys = CFArrayCreate(NULL, &key , 1, &kCFTypeArrayCallBacks);
+ CFDictionaryRef values = SecCertificateCopyValues(cert, keys, &err);
+ CFRelease(keys);
+
+ if(err)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CFRelease(err);
+
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ assert(values);
+
+ CFArrayRef dn = (CFArrayRef)CFDictionaryGetValue((CFDictionaryRef)CFDictionaryGetValue(values, key), kSecPropertyKeyValue);
+ int size = CFArrayGetCount(dn);
+ list<pair<string, string> > rdnPairs;
+ for(int i = 0; i < size; ++i)
+ {
+ CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex(dn, i);
+ rdnPairs.push_front(make_pair(
+ certificateOIDAlias(fromCFString((CFStringRef)CFDictionaryGetValue(dict, kSecPropertyKeyLabel))),
+ scapeX509Name(fromCFString((CFStringRef)CFDictionaryGetValue(dict, kSecPropertyKeyValue)))));
+ }
+ CFRelease(values);
+ return DistinguishedName(rdnPairs);
+}
+
+vector<pair<int, string> >
+getX509AltName(SecCertificateRef cert, CFTypeRef key)
+{
+ CFErrorRef err = 0;
+ assert(key == kSecOIDIssuerAltName || key == kSecOIDSubjectAltName);
+ CFArrayRef keys = CFArrayCreate(NULL, &key , 1, &kCFTypeArrayCallBacks);
+ CFDictionaryRef values = SecCertificateCopyValues(cert, keys, &err);
+ CFRelease(keys);
+
+ if(err)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CFRelease(err);
+
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ assert(values);
+
+ vector<pair<int, string> > pairs;
+ CFDictionaryRef property = (CFDictionaryRef)CFDictionaryGetValue(values, key);
+ if(property)
+ {
+ CFArrayRef names = (CFArrayRef)CFDictionaryGetValue(property, kSecPropertyKeyValue);
+ int size = CFArrayGetCount(names);
+
+ for(int i = 0; i < size; ++i)
+ {
+ CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex(names, i);
+
+ int type = certificateAlternativeNameType(fromCFString(
+ (CFStringRef)CFDictionaryGetValue(dict, kSecPropertyKeyLabel)));
+ if(type != -1)
+ {
+ CFTypeRef v = (CFTypeRef)CFDictionaryGetValue(dict, kSecPropertyKeyValue);
+ CFStringRef t = (CFStringRef)CFDictionaryGetValue(dict, kSecPropertyKeyType);
+ if(CFEqual(t, kSecPropertyTypeString) || CFEqual(t, kSecPropertyTypeTitle))
+ {
+ pairs.push_back(make_pair(type, fromCFString((CFStringRef)v)));
+ }
+ else if(CFEqual(t, kSecPropertyTypeURL))
+ {
+ pairs.push_back(make_pair(type, fromCFString(CFURLGetString((CFURLRef)v))));
+ }
+ else if(CFEqual(t, kSecPropertyTypeSection))
+ {
+ CFArrayRef section = (CFArrayRef)v;
+ ostringstream os;
+ for(int i = 0, count = CFArrayGetCount(section); i < count;)
+ {
+ CFDictionaryRef d = (CFDictionaryRef)CFArrayGetValueAtIndex(section, i);
+
+ CFStringRef sectionLabel = (CFStringRef)CFDictionaryGetValue(d, kSecPropertyKeyLabel);
+ CFStringRef sectionValue = (CFStringRef)CFDictionaryGetValue(d, kSecPropertyKeyValue);
+
+ os << certificateOIDAlias(fromCFString(sectionLabel))
+ << "=" << fromCFString(sectionValue);
+ if(++i < count)
+ {
+ os << ",";
+ }
+ }
+ pairs.push_back(make_pair(type, os.str()));
+ }
+ }
+ }
+ }
+ CFRelease(values);
+ return pairs;
+}
+
+IceUtil::Time
+getX509Date(SecCertificateRef cert, CFTypeRef key)
+{
+ assert(key == kSecOIDX509V1ValidityNotAfter || key == kSecOIDX509V1ValidityNotBefore);
+ CFErrorRef err = 0;
+ const void* keyValues[] = { key };
+ CFArrayRef keys = CFArrayCreate(NULL, keyValues , 1, &kCFTypeArrayCallBacks);
+ CFDictionaryRef values = SecCertificateCopyValues(cert, keys, &err);
+ CFRelease(keys);
+
+ if(err)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CFRelease(err);
+
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ assert(values);
+
+ CFNumberRef date = (CFNumberRef)CFDictionaryGetValue(
+ (CFDictionaryRef)CFDictionaryGetValue(values, key), kSecPropertyKeyValue);
+
+ CFAbsoluteTime seconds;
+ CFNumberGetValue(date, kCFNumberDoubleType, &seconds);
+ CFRelease(values);
+ return IceUtil::Time::secondsDouble(kCFAbsoluteTimeIntervalSince1970 + seconds);
+}
+
+string
+getX509String(SecCertificateRef cert, CFTypeRef key)
+{
+ assert(key == kSecOIDX509V1SerialNumber || key == kSecOIDX509V1Version);
+ CFErrorRef err = 0;
+ const void* keyValues[] = { key };
+ CFArrayRef keys = CFArrayCreate(NULL, keyValues , 1, &kCFTypeArrayCallBacks);
+ CFDictionaryRef values = SecCertificateCopyValues(cert, keys, &err);
+ CFRelease(keys);
+
+ if(err)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CFRelease(err);
+
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ assert(values);
+
+ string value = fromCFString((CFStringRef)CFDictionaryGetValue(
+ (CFDictionaryRef)CFDictionaryGetValue(values, key), kSecPropertyKeyValue));
+ CFRelease(values);
+ return value;
+}
+#endif
+
CertificateReadException::CertificateReadException(const char* file, int line, const string& r) :
Exception(file, line),
reason(r)
@@ -104,6 +367,8 @@ CertificateEncodingException::ice_throw() const
throw *this;
}
+#ifdef ICE_USE_OPENSSL
+
namespace
{
@@ -137,7 +402,7 @@ ASMUtcTimeToIceUtilTime(const ASN1_UTCTIME* s)
memset(&tm, '\0', sizeof tm);
-#define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
+# define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
tm.tm_year = g2(s->data);
if(tm.tm_year < 50)
tm.tm_year += 100;
@@ -158,7 +423,7 @@ ASMUtcTimeToIceUtilTime(const ASN1_UTCTIME* s)
offset = -offset;
}
}
-#undef g2
+# undef g2
//
// If timegm was on all systems this code could be
@@ -176,7 +441,7 @@ ASMUtcTimeToIceUtilTime(const ASN1_UTCTIME* s)
}
static string
-convertX509NameToString(X509NAME* name)
+convertX509NameToString(X509_NAME* name)
{
BIO* out = BIO_new(BIO_s_mem());
X509_NAME_print_ex(out, name, 0, XN_FLAG_RFC2253);
@@ -272,6 +537,7 @@ convertGeneralNames(GENERAL_NAMES* gens)
sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
return alt;
}
+#endif
const char* ParseException::_name = "IceSSL::ParseException";
@@ -303,12 +569,6 @@ ParseException::ice_throw() const
throw *this;
}
-DistinguishedName::DistinguishedName(X509NAME* name) :
- _rdns(RFC2253::parseStrict(convertX509NameToString(name)))
-{
- unescape();
-}
-
DistinguishedName::DistinguishedName(const string& dn) :
_rdns(RFC2253::parseStrict(dn))
{
@@ -395,17 +655,21 @@ DistinguishedName::unescape()
}
}
-PublicKey::PublicKey(EVP_PKEY* key) :
+PublicKey::PublicKey(KeyRef key) :
_key(key)
{
}
PublicKey::~PublicKey()
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ CFRelease(_key);
+#else
EVP_PKEY_free(_key);
+#endif
}
-EVP_PKEY*
+KeyRef
PublicKey::key() const
{
return _key;
@@ -414,7 +678,7 @@ PublicKey::key() const
//
// The caller is responsible for incrementing the reference count.
//
-Certificate::Certificate(X509* cert) :
+Certificate::Certificate(X509CertificateRef cert) :
_cert(cert)
{
assert(_cert != 0);
@@ -422,12 +686,21 @@ Certificate::Certificate(X509* cert) :
Certificate::~Certificate()
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ CFRelease(_cert);
+#else
X509_free(_cert);
+#endif
}
CertificatePtr
Certificate::load(const string& file)
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ SecCertificateRef cert = 0;
+ loadCertificate(&cert, 0, 0, 0, file);
+ return new Certificate(cert);
+#else
BIO *cert = BIO_new(BIO_s_file());
if(BIO_read_filename(cert, file.c_str()) <= 0)
{
@@ -435,7 +708,7 @@ Certificate::load(const string& file)
throw CertificateReadException(__FILE__, __LINE__, "error opening file");
}
- X509* x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
+ X509CertificateRef x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
if(x == NULL)
{
BIO_free(cert);
@@ -443,13 +716,47 @@ Certificate::load(const string& file)
}
BIO_free(cert);
return new Certificate(x);
+#endif
}
CertificatePtr
Certificate::decode(const string& encoding)
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(encoding.c_str()),
+ encoding.size(), kCFAllocatorNull);
+
+ SecExternalFormat format = kSecFormatUnknown;
+ SecExternalItemType type = kSecItemTypeCertificate;
+
+ SecItemImportExportKeyParameters params;
+ memset(&params, 0, sizeof(params));
+ params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+
+ CFArrayRef items = 0;
+
+ OSStatus err = SecItemImport(data, 0, &format, &type, 0, &params, 0, &items);
+
+ CFRelease(data);
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "error decoding certificate:\n" << errorToString(err);
+ CertificateReadException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ SecKeychainItemRef item = (SecKeychainItemRef)CFArrayGetValueAtIndex(items, 0);
+
+ CFRetain(item);
+ CFRelease(items);
+
+ assert(SecCertificateGetTypeID() == CFGetTypeID(item));
+ return new Certificate((SecCertificateRef)item);
+#else
BIO *cert = BIO_new_mem_buf(static_cast<void*>(const_cast<char*>(&encoding[0])), static_cast<int>(encoding.size()));
- X509* x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
+ X509CertificateRef x = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL);
if(x == NULL)
{
BIO_free(cert);
@@ -457,35 +764,179 @@ Certificate::decode(const string& encoding)
}
BIO_free(cert);
return new Certificate(x);
+#endif
}
bool
Certificate::operator==(const Certificate& other) const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return CFEqual(_cert, other._cert);
+#else
return X509_cmp(_cert, other._cert) == 0;
+#endif
}
bool
Certificate::operator!=(const Certificate& other) const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return !CFEqual(_cert, other._cert);
+#else
return X509_cmp(_cert, other._cert) != 0;
+#endif
}
PublicKeyPtr
Certificate::getPublicKey() const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ SecKeyRef key;
+ OSStatus err = SecCertificateCopyPublicKey(_cert, &key);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ return new PublicKey(key);
+#else
return new PublicKey(X509_get_pubkey(_cert));
+#endif
+}
+
+bool
+Certificate::verify(const CertificatePtr& cert) const
+{
+#ifdef ICE_USE_SECURE_TRANSPORT
+
+ bool valid = false;
+
+ CFErrorRef error = 0;
+ CFDataRef issuer = 0;
+ CFDataRef subject = 0;
+
+ issuer = SecCertificateCopyNormalizedIssuerContent(_cert, &error);
+ if(error)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(error);
+ CFRelease(error);
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ subject = SecCertificateCopyNormalizedSubjectContent(cert->getCert(), &error);
+ if(error)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(error);
+ CFRelease(error);
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ //
+ // The certificate issuer must match the CA subject.
+ //
+ valid = CFEqual(issuer, subject);
+
+ CFRelease(issuer);
+ CFRelease(subject);
+
+ if(valid)
+ {
+ SecPolicyRef policy = 0;
+ SecTrustRef trust = 0;
+ try
+ {
+ SecPolicyRef policy = SecPolicyCreateBasicX509();
+ SecTrustResultType trustResult = kSecTrustResultInvalid;
+ SecTrustRef trust;
+ OSStatus err = SecTrustCreateWithCertificates(_cert, policy, &trust);
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ SecCertificateRef certs[1] = { cert->getCert() };
+
+ CFArrayRef anchorCertificates = CFArrayCreate(kCFAllocatorDefault, (const void**)&certs, 1, &kCFTypeArrayCallBacks);
+ err = SecTrustSetAnchorCertificates(trust, anchorCertificates);
+ CFRelease(anchorCertificates);
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ err = SecTrustEvaluate(trust, &trustResult);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ valid = trustResult == kSecTrustResultUnspecified;
+
+ CFRelease(policy);
+ CFRelease(trust);
+ }
+ catch(...)
+ {
+ if(policy)
+ {
+ CFRelease(policy);
+ }
+
+ if(trust)
+ {
+ CFRelease(trust);
+ }
+ throw;
+ }
+ }
+ return valid;
+#else
+ return X509_verify(_cert, cert->getPublicKey()->key()) > 0;
+#endif
}
+#ifndef ICE_USE_SECURE_TRANSPORT
bool
Certificate::verify(const PublicKeyPtr& key) const
{
return X509_verify(_cert, key->key()) > 0;
}
+#endif
string
Certificate::encode() const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ CFDataRef exported;
+ OSStatus err = SecItemExport(_cert, kSecFormatPEMSequence, kSecItemPemArmour, 0, &exported);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "error encoding certificate:\n" << errorToString(err);
+ CertificateEncodingException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ string data(reinterpret_cast<const char*>(CFDataGetBytePtr(exported)), CFDataGetLength(exported));
+ CFRelease(exported);
+ return data;
+#else
BIO* out = BIO_new(BIO_s_mem());
int i = PEM_write_bio_X509_AUX(out, _cert);
if(i <= 0)
@@ -498,6 +949,7 @@ Certificate::encode() const
string result = string(p->data, p->length);
BIO_free(out);
return result;
+#endif
}
bool
@@ -516,18 +968,29 @@ Certificate::checkValidity(const IceUtil::Time& now) const
IceUtil::Time
Certificate::getNotAfter() const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return getX509Date(_cert, kSecOIDX509V1ValidityNotAfter);
+#else
return ASMUtcTimeToIceUtilTime(X509_get_notAfter(_cert));
+#endif
}
IceUtil::Time
Certificate::getNotBefore() const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return getX509Date(_cert, kSecOIDX509V1ValidityNotBefore);
+#else
return ASMUtcTimeToIceUtilTime(X509_get_notBefore(_cert));
+#endif
}
string
Certificate::getSerialNumber() const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return getX509String(_cert, kSecOIDX509V1SerialNumber);
+#else
BIGNUM* bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(_cert), 0);
char* dec = BN_bn2dec(bn);
string result = dec;
@@ -535,6 +998,7 @@ Certificate::getSerialNumber() const
BN_free(bn);
return result;
+#endif
}
//string
@@ -550,33 +1014,53 @@ Certificate::getSerialNumber() const
DistinguishedName
Certificate::getIssuerDN() const
{
- return DistinguishedName(X509_get_issuer_name(_cert));
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return getX509Name(_cert, kSecOIDX509V1IssuerName);
+#else
+ return DistinguishedName(RFC2253::parseStrict(convertX509NameToString(X509_get_issuer_name(_cert))));
+#endif
}
vector<pair<int, string> >
Certificate::getIssuerAlternativeNames()
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return getX509AltName(_cert, kSecOIDIssuerAltName);
+#else
return convertGeneralNames(reinterpret_cast<GENERAL_NAMES*>(
X509_get_ext_d2i(_cert, NID_issuer_alt_name, 0, 0)));
+#endif
}
DistinguishedName
Certificate::getSubjectDN() const
{
- return DistinguishedName(X509_get_subject_name(_cert));
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return getX509Name(_cert, kSecOIDX509V1SubjectName);
+#else
+ return DistinguishedName(RFC2253::parseStrict(convertX509NameToString(X509_get_subject_name(_cert))));
+#endif
}
vector<pair<int, string> >
Certificate::getSubjectAlternativeNames()
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return getX509AltName(_cert, kSecOIDSubjectAltName);
+#else
return convertGeneralNames(
reinterpret_cast<GENERAL_NAMES*>(X509_get_ext_d2i(_cert, NID_subject_alt_name, 0, 0)));
+#endif
}
int
Certificate::getVersion() const
{
+#ifdef ICE_USE_SECURE_TRANSPORT
+ return atoi(getX509String(_cert, kSecOIDX509V1Version).c_str());
+#else
return static_cast<int>(X509_get_version(_cert));
+#endif
}
string
@@ -588,11 +1072,10 @@ Certificate::toString() const
os << "subject: " << string(getSubjectDN()) << "\n";
os << "notBefore: " << getNotBefore().toDateTime() << "\n";
os << "notAfter: " << getNotAfter().toDateTime();
-
return os.str();
}
-X509*
+X509CertificateRef
Certificate::getCert() const
{
return _cert;
diff --git a/cpp/src/IceSSL/ConnectorI.cpp b/cpp/src/IceSSL/ConnectorI.cpp
index fb9386d0a89..74db5e52cb6 100644
--- a/cpp/src/IceSSL/ConnectorI.cpp
+++ b/cpp/src/IceSSL/ConnectorI.cpp
@@ -9,6 +9,7 @@
#include <IceSSL/ConnectorI.h>
#include <IceSSL/Instance.h>
+#include <IceSSL/SecureTransportTransceiverI.h>
#include <IceSSL/TransceiverI.h>
#include <IceSSL/EndpointI.h>
#include <IceSSL/Util.h>
@@ -26,7 +27,7 @@ IceSSL::ConnectorI::connect()
//
// The plug-in may not be initialized.
//
- if(!_instance->context())
+ if(!_instance->initialized())
{
PluginInitializationException ex(__FILE__, __LINE__);
ex.reason = "IceSSL: plug-in is not initialized";
diff --git a/cpp/src/IceSSL/EndpointI.cpp b/cpp/src/IceSSL/EndpointI.cpp
index de769b1186e..93994804783 100644
--- a/cpp/src/IceSSL/EndpointI.cpp
+++ b/cpp/src/IceSSL/EndpointI.cpp
@@ -381,5 +381,5 @@ IceSSL::EndpointFactoryI::destroy()
IceInternal::EndpointFactoryPtr
IceSSL::EndpointFactoryI::clone(const IceInternal::ProtocolInstancePtr& instance) const
{
- return new EndpointFactoryI(new Instance(_instance->sharedInstance(), instance->type(), instance->protocol()));
+ return new EndpointFactoryI(new Instance(_instance->engine(), instance->type(), instance->protocol()));
}
diff --git a/cpp/src/IceSSL/Instance.cpp b/cpp/src/IceSSL/Instance.cpp
index 44c4704b2bc..3d3f24e58d8 100644
--- a/cpp/src/IceSSL/Instance.cpp
+++ b/cpp/src/IceSSL/Instance.cpp
@@ -11,1143 +11,18 @@
#ifdef _WIN32
# include <winsock2.h>
#endif
-
#include <IceSSL/Instance.h>
-#include <IceSSL/Util.h>
-#include <IceSSL/TrustManager.h>
-
-#include <Ice/Communicator.h>
-#include <Ice/LocalException.h>
-#include <Ice/Logger.h>
-#include <Ice/LoggerUtil.h>
#include <Ice/Properties.h>
-#include <IceUtil/Mutex.h>
-#include <IceUtil/MutexPtrLock.h>
-#include <IceUtil/StringUtil.h>
-
-#include <openssl/rand.h>
-#include <openssl/err.h>
-
-#include <IceUtil/DisableWarnings.h>
-
-// Ignore OS X OpenSSL deprecation warnings
-#ifdef __APPLE__
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
using namespace std;
using namespace Ice;
using namespace IceSSL;
IceUtil::Shared* IceSSL::upCast(IceSSL::Instance* p) { return p; }
-IceUtil::Shared* IceSSL::upCast(IceSSL::SharedInstance* p) { return p; }
-
-namespace
-{
-
-IceUtil::Mutex* staticMutex = 0;
-int instanceCount = 0;
-IceUtil::Mutex* locks = 0;
-
-class Init
-{
-public:
-
- Init()
- {
- staticMutex = new IceUtil::Mutex;
- }
-
- ~Init()
- {
- delete staticMutex;
- staticMutex = 0;
- if(locks)
- {
- delete[] locks;
- locks = 0;
- }
- }
-};
-
-Init init;
-
-}
-
-extern "C"
-{
-
-//
-// OpenSSL mutex callback.
-//
-void
-IceSSL_opensslLockCallback(int mode, int n, const char* /*file*/, int /*line*/)
-{
- assert(locks);
- if(mode & CRYPTO_LOCK)
- {
- locks[n].lock();
- }
- else
- {
- locks[n].unlock();
- }
-}
-
-//
-// OpenSSL thread id callback.
-//
-unsigned long
-IceSSL_opensslThreadIdCallback()
-{
-#if defined(_WIN32)
- return static_cast<unsigned long>(GetCurrentThreadId());
-#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__osf1__)
- //
- // On some platforms, pthread_t is a pointer to a per-thread structure.
- //
- return reinterpret_cast<unsigned long>(pthread_self());
-#elif (defined(__linux) || defined(__sun) || defined(__hpux)) || defined(_AIX)
- //
- // On Linux, Solaris, HP-UX and AIX, pthread_t is an integer.
- //
- return static_cast<unsigned long>(pthread_self());
-#else
-# error "Unknown platform"
-#endif
-}
-
-int
-IceSSL_opensslPasswordCallback(char* buf, int size, int flag, void* userData)
-{
- IceSSL::SharedInstance* p = reinterpret_cast<IceSSL::SharedInstance*>(userData);
- string passwd = p->password(flag == 1);
- int sz = static_cast<int>(passwd.size());
- if(sz > size)
- {
- sz = size - 1;
- }
- strncpy(buf, passwd.c_str(), sz);
- buf[sz] = '\0';
-
- for(string::iterator i = passwd.begin(); i != passwd.end(); ++i)
- {
- *i = '\0';
- }
-
- return sz;
-}
-
-#ifndef OPENSSL_NO_DH
-DH*
-IceSSL_opensslDHCallback(SSL* ssl, int /*isExport*/, int keyLength)
-{
- IceSSL::SharedInstance* p = reinterpret_cast<IceSSL::SharedInstance*>(SSL_CTX_get_ex_data(ssl->ctx, 0));
- return p->dhParams(keyLength);
-}
-#endif
-
-int
-IceSSL_opensslVerifyCallback(int ok, X509_STORE_CTX* ctx)
-{
- SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
- IceSSL::SharedInstance* p = reinterpret_cast<IceSSL::SharedInstance*>(SSL_CTX_get_ex_data(ssl->ctx, 0));
- return p->verifyCallback(ok, ssl, ctx);
-}
-
-}
-
-static bool
-passwordError()
-{
- int reason = ERR_GET_REASON(ERR_peek_error());
- return (reason == PEM_R_BAD_BASE64_DECODE ||
- reason == PEM_R_BAD_DECRYPT ||
- reason == PEM_R_BAD_PASSWORD_READ ||
- reason == PEM_R_PROBLEMS_GETTING_PASSWORD);
-}
-
-IceSSL::SharedInstance::SharedInstance(const CommunicatorPtr& communicator) :
- _communicator(communicator),
- _logger(communicator->getLogger()),
- _initialized(false),
- _ctx(0)
-{
- __setNoDelete(true);
-
- //
- // Initialize OpenSSL if necessary.
- //
- IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(staticMutex);
- instanceCount++;
-
- if(instanceCount == 1)
- {
- PropertiesPtr properties = communicator->getProperties();
-
- //
- // The IceSSL.InitOpenSSL property specifies whether we should perform the global
- // startup (and shutdown) tasks for the OpenSSL library.
- //
- // If an application uses multiple components that each depend on OpenSSL, the
- // application should disable OpenSSL initialization in those components and
- // perform the initialization itself.
- //
- _initOpenSSL = properties->getPropertyAsIntWithDefault("IceSSL.InitOpenSSL", 1) > 0;
- if(_initOpenSSL)
- {
- //
- // Create the mutexes and set the callbacks.
- //
- if(!locks)
- {
- locks = new IceUtil::Mutex[CRYPTO_num_locks()];
- CRYPTO_set_locking_callback(IceSSL_opensslLockCallback);
- CRYPTO_set_id_callback(IceSSL_opensslThreadIdCallback);
- }
-
- //
- // Load human-readable error messages.
- //
- SSL_load_error_strings();
-
- //
- // Initialize the SSL library.
- //
- SSL_library_init();
-
- //
- // This is necessary to allow programs that use OpenSSL 0.9.x to
- // load private key files generated by OpenSSL 1.x.
- //
- OpenSSL_add_all_algorithms();
-
- //
- // Initialize the PRNG.
- //
-#ifdef WINDOWS
- RAND_screen(); // Uses data from the screen if possible.
-#endif
- char randFile[1024];
- if(RAND_file_name(randFile, sizeof(randFile))) // Gets the name of a default seed file.
- {
- RAND_load_file(randFile, 1024);
- }
-
- string randFiles = properties->getProperty("IceSSL.Random");
-
- if(!randFiles.empty())
- {
- vector<string> files;
-#ifdef _WIN32
- const string sep = ";";
-#else
- const string sep = ":";
-#endif
- string defaultDir = properties->getProperty("IceSSL.DefaultDir");
-
- if(!IceUtilInternal::splitString(randFiles, sep, files))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: invalid value for IceSSL.Random:\n" + randFiles;
- throw ex;
- }
- for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
- {
- string file = *p;
- if(!checkPath(file, defaultDir, false))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: entropy data file not found:\n" + file;
- throw ex;
- }
- if(!RAND_load_file(file.c_str(), 1024))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: unable to load entropy data from " + file;
- throw ex;
- }
- }
- }
-#ifndef _WIN32
- //
- // The Entropy Gathering Daemon (EGD) is not available on Windows.
- // The file should be a Unix domain socket for the daemon.
- //
- string entropyDaemon = properties->getProperty("IceSSL.EntropyDaemon");
- if(!entropyDaemon.empty())
- {
- if(RAND_egd(entropyDaemon.c_str()) <= 0)
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: EGD failure using file " + entropyDaemon;
- throw ex;
- }
- }
-#endif
- if(!RAND_status())
- {
- communicator->getLogger()->warning("IceSSL: insufficient data to initialize PRNG");
- }
- }
- else
- {
- if(!properties->getProperty("IceSSL.Random").empty())
- {
- _logger->warning("IceSSL: ignoring IceSSL.Random because OpenSSL initialization is disabled");
- }
-#ifndef _WIN32
- else if(!properties->getProperty("IceSSL.EntropyDaemon").empty())
- {
- _logger->warning("IceSSL: ignoring IceSSL.EntropyDaemon because OpenSSL initialization is disabled");
- }
-#endif
- }
- }
-
- _securityTraceLevel = communicator->getProperties()->getPropertyAsInt("IceSSL.Trace.Security");
- _securityTraceCategory = "Security";
- _trustManager = new TrustManager(communicator);
-
- __setNoDelete(false);
-}
-
-IceSSL::SharedInstance::~SharedInstance()
-{
- //
- // Clean up OpenSSL resources.
- //
- IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(staticMutex);
-
- if(--instanceCount == 0 && _initOpenSSL)
- {
- //
- // NOTE: We can't destroy the locks here: threads which might have called openssl methods
- // might access openssl locks upon termination (from DllMain/THREAD_DETACHED). Instead,
- // we release the locks in the ~Init() static destructor. See bug #4156.
- //
- //CRYPTO_set_locking_callback(0);
- //CRYPTO_set_id_callback(0);
- //delete[] locks;
- //locks = 0;
-
- CRYPTO_cleanup_all_ex_data();
- RAND_cleanup();
- ERR_free_strings();
- EVP_cleanup();
- }
-}
-
-void
-IceSSL::SharedInstance::initialize()
-{
- if(_initialized)
- {
- return;
- }
-
- try
- {
- const string propPrefix = "IceSSL.";
- PropertiesPtr properties = communicator()->getProperties();
-
- //
- // CheckCertName determines whether we compare the name in a peer's
- // certificate against its hostname.
- //
- _checkCertName = properties->getPropertyAsIntWithDefault(propPrefix + "CheckCertName", 0) > 0;
-
- //
- // VerifyDepthMax establishes the maximum length of a peer's certificate
- // chain, including the peer's certificate. A value of 0 means there is
- // no maximum.
- //
- _verifyDepthMax = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyDepthMax", 2);
-
- //
- // VerifyPeer determines whether certificate validation failures abort a connection.
- //
- _verifyPeer = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyPeer", 2);
-
- //
- // Protocols selects which protocols to enable.
- //
- const int protocols = parseProtocols(properties->getPropertyAsList(propPrefix + "Protocols"));
-
- //
- // Create an SSL context if the application hasn't supplied one.
- //
- if(!_ctx)
- {
- _ctx = SSL_CTX_new(getMethod(protocols));
- if(!_ctx)
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: unable to create SSL context:\n" + sslErrors();
- throw ex;
- }
-
- //
- // Check for a default directory. We look in this directory for
- // files mentioned in the configuration.
- //
- string defaultDir = properties->getProperty(propPrefix + "DefaultDir");
-
- //
- // If the configuration defines a password, or the application has supplied
- // a password prompt object, then register a password callback. Otherwise,
- // let OpenSSL use its default behavior.
- //
- {
- // TODO: Support quoted value?
- string password = properties->getProperty(propPrefix + "Password");
- if(!password.empty() || _prompt)
- {
- SSL_CTX_set_default_passwd_cb(_ctx, IceSSL_opensslPasswordCallback);
- SSL_CTX_set_default_passwd_cb_userdata(_ctx, this);
- _password = password;
- }
- }
-
- int passwordRetryMax = properties->getPropertyAsIntWithDefault(propPrefix + "PasswordRetryMax", 3);
-
- //
- // Establish the location of CA certificates.
- //
- {
- string caFile = properties->getProperty(propPrefix + "CertAuthFile");
- string caDir = properties->getPropertyWithDefault(propPrefix + "CertAuthDir", defaultDir);
- const char* file = 0;
- const char* dir = 0;
- if(!caFile.empty())
- {
- if(!checkPath(caFile, defaultDir, false))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: CA certificate file not found:\n" + caFile;
- throw ex;
- }
- file = caFile.c_str();
- }
- if(!caDir.empty())
- {
- if(!checkPath(caDir, defaultDir, true))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: CA certificate directory not found:\n" + caDir;
- throw ex;
- }
- dir = caDir.c_str();
- }
- if(file || dir)
- {
- //
- // The certificate may be stored in an encrypted file, so handle
- // password retries.
- //
- int count = 0;
- int err = 0;
- while(count < passwordRetryMax)
- {
- ERR_clear_error();
- err = SSL_CTX_load_verify_locations(_ctx, file, dir);
- if(err)
- {
- break;
- }
- ++count;
- }
- if(err == 0)
- {
- string msg = "IceSSL: unable to establish CA certificates";
- if(passwordError())
- {
- msg += ":\ninvalid password";
- }
- else
- {
- string err = sslErrors();
- if(!err.empty())
- {
- msg += ":\n" + err;
- }
- }
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- }
- }
-
- //
- // Establish the certificate chains and private keys. One RSA certificate and
- // one DSA certificate are allowed.
- //
- {
-#ifdef _WIN32
- const string sep = ";";
-#else
- const string sep = ":";
-#endif
- string certFile = properties->getProperty(propPrefix + "CertFile");
- string keyFile = properties->getProperty(propPrefix + "KeyFile");
- vector<string>::size_type numCerts = 0;
- if(!certFile.empty())
- {
- vector<string> files;
- if(!IceUtilInternal::splitString(certFile, sep, files) || files.size() > 2)
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: invalid value for " + propPrefix + "CertFile:\n" + certFile;
- throw ex;
- }
- numCerts = files.size();
- for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
- {
- string file = *p;
- if(!checkPath(file, defaultDir, false))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: certificate file not found:\n" + file;
- throw ex;
- }
- //
- // The certificate may be stored in an encrypted file, so handle
- // password retries.
- //
- int count = 0;
- int err = 0;
- while(count < passwordRetryMax)
- {
- ERR_clear_error();
- err = SSL_CTX_use_certificate_chain_file(_ctx, file.c_str());
- if(err)
- {
- break;
- }
- ++count;
- }
- if(err == 0)
- {
- string msg = "IceSSL: unable to load certificate chain from file " + file;
- if(passwordError())
- {
- msg += ":\ninvalid password";
- }
- else
- {
- string err = sslErrors();
- if(!err.empty())
- {
- msg += ":\n" + err;
- }
- }
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- }
- }
- if(keyFile.empty())
- {
- keyFile = certFile; // Assume the certificate file also contains the private key.
- }
- if(!keyFile.empty())
- {
- vector<string> files;
- if(!IceUtilInternal::splitString(keyFile, sep, files) || files.size() > 2)
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: invalid value for " + propPrefix + "KeyFile:\n" + keyFile;
- throw ex;
- }
- if(files.size() != numCerts)
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: " + propPrefix + "KeyFile does not agree with " + propPrefix + "CertFile";
- throw ex;
- }
- for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
- {
- string file = *p;
- if(!checkPath(file, defaultDir, false))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: key file not found:\n" + file;
- throw ex;
- }
- //
- // The private key may be stored in an encrypted file, so handle
- // password retries.
- //
- int count = 0;
- int err = 0;
- while(count < passwordRetryMax)
- {
- ERR_clear_error();
- err = SSL_CTX_use_PrivateKey_file(_ctx, file.c_str(), SSL_FILETYPE_PEM);
- if(err)
- {
- break;
- }
- ++count;
- }
- if(err == 0)
- {
- string msg = "IceSSL: unable to load private key from file " + file;
- if(passwordError())
- {
- msg += ":\ninvalid password";
- }
- else
- {
- string err = sslErrors();
- if(!err.empty())
- {
- msg += ":\n" + err;
- }
- }
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- }
- if(!SSL_CTX_check_private_key(_ctx))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: unable to validate private key(s):\n" + sslErrors();
- throw ex;
- }
- }
- }
-
- //
- // Diffie Hellman configuration.
- //
- {
-#ifndef OPENSSL_NO_DH
- _dhParams = new DHParams;
- SSL_CTX_set_options(_ctx, SSL_OP_SINGLE_DH_USE);
- SSL_CTX_set_tmp_dh_callback(_ctx, IceSSL_opensslDHCallback);
-#endif
- //
- // Properties have the following form:
- //
- // ...DH.<keyLength>=file
- //
- const string dhPrefix = propPrefix + "DH.";
- PropertyDict d = properties->getPropertiesForPrefix(dhPrefix);
- if(!d.empty())
- {
-#ifdef OPENSSL_NO_DH
- _logger->warning("IceSSL: OpenSSL is not configured for Diffie Hellman");
-#else
- for(PropertyDict::iterator p = d.begin(); p != d.end(); ++p)
- {
- string s = p->first.substr(dhPrefix.size());
- int keyLength = atoi(s.c_str());
- if(keyLength > 0)
- {
- string file = p->second;
- if(!checkPath(file, defaultDir, false))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: DH parameter file not found:\n" + file;
- throw ex;
- }
- if(!_dhParams->add(keyLength, file))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: unable to read DH parameter file " + file;
- throw ex;
- }
- }
- }
-#endif
- }
- }
- }
-
- //
- // Store a pointer to ourself for use in OpenSSL callbacks.
- //
- SSL_CTX_set_ex_data(_ctx, 0, this);
-
- //
- // This is necessary for successful interop with Java. Without it, a Java
- // client would fail to reestablish a connection: the server gets the
- // error "session id context uninitialized" and the client receives
- // "SSLHandshakeException: Remote host closed connection during handshake".
- //
- SSL_CTX_set_session_cache_mode(_ctx, SSL_SESS_CACHE_OFF);
-
- //
- // Although we disable session caching, we still need to set a session ID
- // context (ICE-5103). The value can be anything; here we just use the
- // pointer to this SharedInstance object.
- //
- SSL_CTX_set_session_id_context(_ctx, reinterpret_cast<unsigned char*>(this),
- static_cast<unsigned int>(sizeof(this)));
-
- //
- // Select protocols.
- //
- if(protocols != 0)
- {
- setOptions(protocols);
- }
-
- //
- // Establish the cipher list.
- //
- string ciphers = properties->getProperty(propPrefix + "Ciphers");
- if(!ciphers.empty())
- {
- if(!SSL_CTX_set_cipher_list(_ctx, ciphers.c_str()))
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: unable to set ciphers using `" + ciphers + "':\n" + sslErrors();
- throw ex;
- }
- }
-
- //
- // Determine whether a certificate is required from the peer.
- //
- {
- int sslVerifyMode;
- switch(_verifyPeer)
- {
- case 0:
- sslVerifyMode = SSL_VERIFY_NONE;
- break;
- case 1:
- sslVerifyMode = SSL_VERIFY_PEER;
- break;
- case 2:
- sslVerifyMode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
- break;
- default:
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: invalid value for " + propPrefix + "VerifyPeer";
- throw ex;
- }
- }
- SSL_CTX_set_verify(_ctx, sslVerifyMode, IceSSL_opensslVerifyCallback);
- }
- }
- catch(...)
- {
- //
- // We free the SSL context regardless of whether the plugin created it
- // or the application supplied it.
- //
- SSL_CTX_free(_ctx);
- _ctx = 0;
- throw;
- }
-
- _initialized = true;
-}
-
-void
-IceSSL::SharedInstance::context(SSL_CTX* context)
-{
- if(_initialized)
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: plug-in is already initialized";
- throw ex;
- }
-
- assert(!_ctx);
- _ctx = context;
-}
-
-SSL_CTX*
-IceSSL::SharedInstance::context() const
-{
- return _ctx;
-}
-
-void
-IceSSL::SharedInstance::setCertificateVerifier(const CertificateVerifierPtr& verifier)
-{
- _verifier = verifier;
-}
-
-void
-IceSSL::SharedInstance::setPasswordPrompt(const PasswordPromptPtr& prompt)
-{
- _prompt = prompt;
-}
-
-CommunicatorPtr
-IceSSL::SharedInstance::communicator() const
-{
- return _communicator;
-}
-
-void
-IceSSL::SharedInstance::verifyPeer(SSL* ssl, SOCKET fd, const string& address, const NativeConnectionInfoPtr& info)
-{
- long result = SSL_get_verify_result(ssl);
- if(result != X509_V_OK)
- {
- if(_verifyPeer == 0)
- {
- if(_securityTraceLevel >= 1)
- {
- ostringstream ostr;
- ostr << "IceSSL: ignoring certificate verification failure:\n" << X509_verify_cert_error_string(result);
- _logger->trace(_securityTraceCategory, ostr.str());
- }
- }
- else
- {
- ostringstream ostr;
- ostr << "IceSSL: certificate verification failed:\n" << X509_verify_cert_error_string(result);
- string msg = ostr.str();
- if(_securityTraceLevel >= 1)
- {
- _logger->trace(_securityTraceCategory, msg);
- }
- SecurityException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- }
-
- X509* rawCert = SSL_get_peer_certificate(ssl);
- CertificatePtr cert;
- if(rawCert != 0)
- {
- cert = new Certificate(rawCert);
- }
-
- //
- // For an outgoing connection, we compare the proxy address (if any) against
- // fields in the server's certificate (if any).
- //
- if(cert && !address.empty())
- {
- //
- // Extract the IP addresses and the DNS names from the subject
- // alternative names.
- //
- vector<pair<int, string> > subjectAltNames = cert->getSubjectAlternativeNames();
- vector<string> ipAddresses;
- vector<string> dnsNames;
- for(vector<pair<int, string> >::const_iterator p = subjectAltNames.begin(); p != subjectAltNames.end(); ++p)
- {
- if(p->first == 7)
- {
- ipAddresses.push_back(IceUtilInternal::toLower(p->second));
- }
- else if(p->first == 2)
- {
- dnsNames.push_back(IceUtilInternal::toLower(p->second));
- }
- }
-
- //
- // Compare the peer's address against the common name.
- //
- bool certNameOK = false;
- string dn;
- string addrLower = IceUtilInternal::toLower(address);
- {
- DistinguishedName d = cert->getSubjectDN();
- dn = IceUtilInternal::toLower(string(d));
- string cn = "cn=" + addrLower;
- string::size_type pos = dn.find(cn);
- if(pos != string::npos)
- {
- //
- // Ensure we match the entire common name.
- //
- certNameOK = (pos + cn.size() == dn.size()) || (dn[pos + cn.size()] == ',');
- }
- }
-
- //
- // Compare the peer's address against the dnsName and ipAddress
- // values in the subject alternative name.
- //
- if(!certNameOK)
- {
- certNameOK = find(ipAddresses.begin(), ipAddresses.end(), addrLower) != ipAddresses.end();
- }
- if(!certNameOK)
- {
- certNameOK = find(dnsNames.begin(), dnsNames.end(), addrLower) != dnsNames.end();
- }
-
- //
- // Log a message if the name comparison fails. If CheckCertName is defined,
- // we also raise an exception to abort the connection. Don't log a message if
- // CheckCertName is not defined and a verifier is present.
- //
- if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && !_verifier)))
- {
- ostringstream ostr;
- ostr << "IceSSL: ";
- if(!_checkCertName)
- {
- ostr << "ignoring ";
- }
- ostr << "certificate validation failure:\npeer certificate does not have `" << address
- << "' as its commonName or in its subjectAltName extension";
- if(!dn.empty())
- {
- ostr << "\nSubject DN: " << dn;
- }
- if(!dnsNames.empty())
- {
- ostr << "\nDNS names found in certificate: ";
- for(vector<string>::const_iterator p = dnsNames.begin(); p != dnsNames.end(); ++p)
- {
- if(p != dnsNames.begin())
- {
- ostr << ", ";
- }
- ostr << *p;
- }
- }
- if(!ipAddresses.empty())
- {
- ostr << "\nIP addresses found in certificate: ";
- for(vector<string>::const_iterator p = ipAddresses.begin(); p != ipAddresses.end(); ++p)
- {
- if(p != ipAddresses.begin())
- {
- ostr << ", ";
- }
- ostr << *p;
- }
- }
- string msg = ostr.str();
- if(_securityTraceLevel >= 1)
- {
- Trace out(_logger, _securityTraceCategory);
- out << msg;
- }
- if(_checkCertName)
- {
- SecurityException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- }
- }
-
- if(_verifyDepthMax > 0 && static_cast<int>(info->certs.size()) > _verifyDepthMax)
- {
- ostringstream ostr;
- ostr << (info->incoming ? "incoming" : "outgoing") << " connection rejected:\n"
- << "length of peer's certificate chain (" << info->certs.size() << ") exceeds maximum of "
- << _verifyDepthMax;
- string msg = ostr.str();
- if(_securityTraceLevel >= 1)
- {
- _logger->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
- }
- SecurityException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
-
- if(!_trustManager->verify(info))
- {
- string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by trust manager";
- if(_securityTraceLevel >= 1)
- {
- _logger->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
- }
- SecurityException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
-
- if(_verifier && !_verifier->verify(info))
- {
- string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier";
- if(_securityTraceLevel >= 1)
- {
- _logger->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
- }
- SecurityException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
-}
-
-string
-IceSSL::SharedInstance::sslErrors() const
-{
- return getSslErrors(_securityTraceLevel >= 1);
-}
-
-void
-IceSSL::SharedInstance::destroy()
-{
- if(_ctx)
- {
- SSL_CTX_free(_ctx);
- }
-}
-
-string
-IceSSL::SharedInstance::password(bool /*encrypting*/)
-{
- if(_prompt)
- {
- try
- {
- return _prompt->getPassword();
- }
- catch(...)
- {
- //
- // Don't allow exceptions to cross an OpenSSL boundary.
- //
- return string();
- }
- }
- else
- {
- return _password;
- }
-}
-
-int
-IceSSL::SharedInstance::verifyCallback(int ok, SSL* ssl, X509_STORE_CTX* c)
-{
- if(!ok && _securityTraceLevel >= 1)
- {
- X509* cert = X509_STORE_CTX_get_current_cert(c);
- int err = X509_STORE_CTX_get_error(c);
- char buf[256];
-
- Trace out(_logger, _securityTraceCategory);
- out << "certificate verification failure\n";
-
- X509_NAME_oneline(X509_get_issuer_name(cert), buf, static_cast<int>(sizeof(buf)));
- out << "issuer = " << buf << '\n';
- X509_NAME_oneline(X509_get_subject_name(cert), buf, static_cast<int>(sizeof(buf)));
- out << "subject = " << buf << '\n';
- out << "depth = " << X509_STORE_CTX_get_error_depth(c) << '\n';
- out << "error = " << X509_verify_cert_error_string(err) << '\n';
- out << IceInternal::fdToString(SSL_get_fd(ssl));
- }
- return ok;
-}
-
-#ifndef OPENSSL_NO_DH
-DH*
-IceSSL::SharedInstance::dhParams(int keyLength)
-{
- return _dhParams->get(keyLength);
-}
-#endif
-
-int
-IceSSL::SharedInstance::parseProtocols(const StringSeq& protocols)
-{
- int v = 0;
-
- for(Ice::StringSeq::const_iterator p = protocols.begin(); p != protocols.end(); ++p)
- {
- string prot = *p;
-
- if(prot == "ssl3" || prot == "sslv3")
- {
- v |= SSLv3;
- }
- else if(prot == "tls" || prot == "tls1" || prot == "tlsv1" || prot == "tls1_0" || prot == "tlsv1_0")
- {
- v |= TLSv1_0;
- }
- else if(prot == "tls1_1" || prot == "tlsv1_1")
- {
- v |= TLSv1_1;
- }
- else if(prot == "tls1_2" || prot == "tlsv1_2")
- {
- v |= TLSv1_2;
- }
- else
- {
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = "IceSSL: unrecognized protocol `" + prot + "'";
- throw ex;
- }
- }
-
- return v;
-}
-
-SSL_METHOD*
-IceSSL::SharedInstance::getMethod(int /*protocols*/)
-{
- //
- // Despite its name, the SSLv23 method can negotiate SSL3, TLS1.0, TLS1.1, and TLS1.2.
- // We use the const_cast for backward compatibility with older OpenSSL releases.
- //
- SSL_METHOD* meth = const_cast<SSL_METHOD*>(SSLv23_method());
-
- /*
- * Early versions of OpenSSL 1.0.1 would not negotiate a TLS1.2 connection using
- * the SSLv23 method. You can enable the code below to override the method.
- if(protocols & TLSv1_2)
- {
- meth = const_cast<SSL_METHOD*>(TLSv1_2_method());
- }
- */
-
- return meth;
-}
-
-void
-IceSSL::SharedInstance::setOptions(int protocols)
-{
- long opts = SSL_OP_NO_SSLv2; // SSLv2 is not supported.
- if(!(protocols & SSLv3))
- {
- opts |= SSL_OP_NO_SSLv3;
- }
- if(!(protocols & TLSv1_0))
- {
- opts |= SSL_OP_NO_TLSv1;
- }
-#ifdef SSL_OP_NO_TLSv1_1
- if(!(protocols & TLSv1_1))
- {
- opts |= SSL_OP_NO_TLSv1_1;
- //
- // The value of SSL_OP_NO_TLSv1_1 changed between 1.0.1a and 1.0.1b.
- //
- if(SSL_OP_NO_TLSv1_1 == 0x00000400L)
- {
- opts |= 0x10000000L; // New value of SSL_OP_NO_TLSv1_1.
- }
- }
-#endif
-#ifdef SSL_OP_NO_TLSv1_2
- if(!(protocols & TLSv1_2))
- {
- opts |= SSL_OP_NO_TLSv1_2;
- }
-#endif
- SSL_CTX_set_options(_ctx, opts);
-}
-
-IceSSL::Instance::Instance(const SharedInstancePtr& sharedInstance, Ice::Short type, const std::string& protocol) :
- ProtocolInstance(sharedInstance->communicator(), type, protocol),
- _sharedInstance(sharedInstance)
+IceSSL::Instance::Instance(const SSLEnginePtr& engine, Short type, const string& protocol) :
+ ProtocolInstance(engine->communicator(), type, protocol),
+ _engine(engine)
{
_securityTraceLevel = properties()->getPropertyAsInt("IceSSL.Trace.Security");
_securityTraceCategory = "Security";
@@ -1157,28 +32,10 @@ IceSSL::Instance::~Instance()
{
}
-void
-IceSSL::Instance::traceConnection(SSL* ssl, bool incoming)
+bool
+IceSSL::Instance::initialized() const
{
- Trace out(_logger, _securityTraceCategory);
- out << "SSL summary for " << (incoming ? "incoming" : "outgoing") << " connection\n";
-
- //
- // The const_cast is necesary because Solaris still uses OpenSSL 0.9.7.
- //
- //const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
- SSL_CIPHER *cipher = const_cast<SSL_CIPHER*>(SSL_get_current_cipher(ssl));
- if(!cipher)
- {
- out << "unknown cipher\n";
- }
- else
- {
- out << "cipher = " << SSL_CIPHER_get_name(cipher) << "\n";
- out << "bits = " << SSL_CIPHER_get_bits(cipher, 0) << "\n";
- out << "protocol = " << SSL_get_version(ssl) << "\n";
- }
- out << IceInternal::fdToString(SSL_get_fd(ssl));
+ return _engine->initialized();
}
int
@@ -1192,4 +49,3 @@ IceSSL::Instance::securityTraceCategory() const
{
return _securityTraceCategory;
}
-
diff --git a/cpp/src/IceSSL/Instance.h b/cpp/src/IceSSL/Instance.h
index d549b60f179..ee295a6d7d1 100644
--- a/cpp/src/IceSSL/Instance.h
+++ b/cpp/src/IceSSL/Instance.h
@@ -12,114 +12,37 @@
#include <IceSSL/InstanceF.h>
#include <IceSSL/UtilF.h>
-#include <Ice/CommunicatorF.h>
-#include <Ice/Network.h>
#include <Ice/ProtocolInstance.h>
#include <Ice/ProtocolPluginFacadeF.h>
#include <IceSSL/Plugin.h>
+#include <IceSSL/SSLEngine.h>
#include <IceSSL/TrustManagerF.h>
#include <Ice/BuiltinSequences.h>
namespace IceSSL
{
-class SharedInstance : public IceUtil::Shared
-{
-public:
-
- SharedInstance(const Ice::CommunicatorPtr&);
- ~SharedInstance();
-
- void initialize();
- void context(SSL_CTX*);
- SSL_CTX* context() const;
- void setCertificateVerifier(const CertificateVerifierPtr&);
- void setPasswordPrompt(const PasswordPromptPtr&);
-
- Ice::CommunicatorPtr communicator() const;
-
- void verifyPeer(SSL*, SOCKET, const std::string&, const NativeConnectionInfoPtr&);
-
- std::string sslErrors() const;
-
- void destroy();
-
- //
- // OpenSSL callbacks.
- //
- std::string password(bool);
- int verifyCallback(int, SSL*, X509_STORE_CTX*);
-#ifndef OPENSSL_NO_DH
- DH* dhParams(int);
-#endif
-
-private:
-
- enum Protocols { SSLv3 = 0x01, TLSv1_0 = 0x02, TLSv1_1 = 0x04, TLSv1_2 = 0x08 };
- static int parseProtocols(const Ice::StringSeq&);
-
- static SSL_METHOD* getMethod(int);
-
- void setOptions(int);
-
- bool _initOpenSSL;
- const Ice::CommunicatorPtr _communicator;
- const Ice::LoggerPtr _logger;
- int _securityTraceLevel;
- std::string _securityTraceCategory;
- bool _initialized;
- SSL_CTX* _ctx;
- std::string _defaultDir;
- bool _checkCertName;
- int _verifyDepthMax;
- int _verifyPeer;
- std::string _password;
-#ifndef OPENSSL_NO_DH
- DHParamsPtr _dhParams;
-#endif
- CertificateVerifierPtr _verifier;
- PasswordPromptPtr _prompt;
- TrustManagerPtr _trustManager;
-};
-
class Instance : public IceInternal::ProtocolInstance
{
public:
- Instance(const SharedInstancePtr&, Ice::Short, const std::string&);
+ Instance(const SSLEnginePtr&, Ice::Short, const std::string&);
virtual ~Instance();
- SSL_CTX*
- context() const
- {
- return _sharedInstance->context();
- }
-
- std::string
- sslErrors() const
- {
- return _sharedInstance->sslErrors();
- }
-
- SharedInstancePtr
- sharedInstance() const
- {
- return _sharedInstance;
- }
-
- void
- verifyPeer(SSL* ssl, SOCKET fd, const std::string& host, const NativeConnectionInfoPtr& info)
+ SSLEnginePtr
+ engine() const
{
- _sharedInstance->verifyPeer(ssl, fd, host, info);
+ return _engine;
}
+
+ bool initialized() const;
- void traceConnection(SSL*, bool);
int securityTraceLevel() const;
std::string securityTraceCategory() const;
private:
- const SharedInstancePtr _sharedInstance;
+ const SSLEnginePtr _engine;
int _securityTraceLevel;
std::string _securityTraceCategory;
};
diff --git a/cpp/src/IceSSL/InstanceF.h b/cpp/src/IceSSL/InstanceF.h
index 3c2bcac856b..6c8f7f33d92 100644
--- a/cpp/src/IceSSL/InstanceF.h
+++ b/cpp/src/IceSSL/InstanceF.h
@@ -21,10 +21,6 @@ class Instance;
IceUtil::Shared* upCast(IceSSL::Instance*);
typedef IceInternal::Handle<Instance> InstancePtr;
-class SharedInstance;
-IceUtil::Shared* upCast(IceSSL::SharedInstance*);
-typedef IceInternal::Handle<SharedInstance> SharedInstancePtr;
-
}
#endif
diff --git a/cpp/src/IceSSL/Makefile b/cpp/src/IceSSL/Makefile
index adfe54a84db..0b77453d20e 100644
--- a/cpp/src/IceSSL/Makefile
+++ b/cpp/src/IceSSL/Makefile
@@ -21,13 +21,17 @@ OBJS = AcceptorI.o \
ConnectorI.o \
EndpointInfo.o \
ConnectionInfo.o \
- EndpointI.o \
- Instance.o \
- PluginI.o \
- TransceiverI.o \
- Util.o \
+ EndpointI.o \
+ Instance.o \
+ PluginI.o \
+ TransceiverI.o \
+ SecureTransportTransceiverI.o \
+ Util.o \
RFC2253.o \
- TrustManager.o
+ TrustManager.o \
+ SSLEngine.o \
+ OpenSSLEngine.o \
+ SecureTransportEngine.o
SRCS = $(OBJS:.o=.cpp)
@@ -42,7 +46,7 @@ include $(top_srcdir)/config/Make.rules
CPPFLAGS := -I.. $(CPPFLAGS) -DICE_SSL_API_EXPORTS $(OPENSSL_FLAGS)
SLICE2CPPFLAGS := --ice --include-dir IceSSL --dll-export ICE_SSL_API $(SLICE2CPPFLAGS)
-LINKWITH := $(BZIP2_RPATH_LINK) -lIce -lIceUtil $(OPENSSL_LIBS) $(CXXLIBS)
+LINKWITH := $(BZIP2_RPATH_LINK) -lIce -lIceUtil $(SSL_OS_LIBS) $(CXXLIBS)
ifeq ($(STATICLIBS),yes)
$(libdir)/$(LIBNAME): $(OBJS)
diff --git a/cpp/src/IceSSL/Makefile.mak b/cpp/src/IceSSL/Makefile.mak
index 5dc4328322a..33ea5d194b5 100644
--- a/cpp/src/IceSSL/Makefile.mak
+++ b/cpp/src/IceSSL/Makefile.mak
@@ -25,7 +25,9 @@ OBJS = AcceptorI.obj \
TransceiverI.obj \
Util.obj \
RFC2253.obj \
- TrustManager.obj
+ TrustManager.obj \
+ SSLEngine.obj \
+ OpenSSLEngine.obj
SRCS = $(OBJS:.obj=.cpp)
diff --git a/cpp/src/IceSSL/OpenSSLEngine.cpp b/cpp/src/IceSSL/OpenSSLEngine.cpp
new file mode 100644
index 00000000000..c73e27da33a
--- /dev/null
+++ b/cpp/src/IceSSL/OpenSSLEngine.cpp
@@ -0,0 +1,920 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#include <IceSSL/Config.h>
+
+#include <IceSSL/SSLEngine.h>
+#include <IceSSL/Util.h>
+#include <IceSSL/TrustManager.h>
+
+#include <Ice/Communicator.h>
+#include <Ice/LocalException.h>
+#include <Ice/Logger.h>
+#include <Ice/LoggerUtil.h>
+#include <Ice/Properties.h>
+
+#include <IceUtil/StringConverter.h>
+#include <IceUtil/StringUtil.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/MutexPtrLock.h>
+#include <IceUtil/FileUtil.h>
+
+#ifdef ICE_USE_OPENSSL
+
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+using namespace std;
+using namespace Ice;
+using namespace IceSSL;
+
+namespace
+{
+
+IceUtil::Mutex* staticMutex = 0;
+int instanceCount = 0;
+IceUtil::Mutex* locks = 0;
+
+class Init
+{
+public:
+
+ Init()
+ {
+ staticMutex = new IceUtil::Mutex;
+ }
+
+ ~Init()
+ {
+ delete staticMutex;
+ staticMutex = 0;
+
+ if(locks)
+ {
+ delete[] locks;
+ locks = 0;
+ }
+ }
+};
+
+Init init;
+}
+
+extern "C"
+{
+
+//
+// OpenSSL mutex callback.
+//
+void
+IceSSL_opensslLockCallback(int mode, int n, const char* /*file*/, int /*line*/)
+{
+ assert(locks);
+ if(mode & CRYPTO_LOCK)
+ {
+ locks[n].lock();
+ }
+ else
+ {
+ locks[n].unlock();
+ }
+}
+
+//
+// OpenSSL thread id callback.
+//
+unsigned long
+IceSSL_opensslThreadIdCallback()
+{
+# if defined(_WIN32)
+ return static_cast<unsigned long>(GetCurrentThreadId());
+# elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__osf1__)
+ //
+ // On some platforms, pthread_t is a pointer to a per-thread structure.
+ //
+ return reinterpret_cast<unsigned long>(pthread_self());
+# elif (defined(__linux) || defined(__sun) || defined(__hpux)) || defined(_AIX)
+ //
+ // On Linux, Solaris, HP-UX and AIX, pthread_t is an integer.
+ //
+ return static_cast<unsigned long>(pthread_self());
+# else
+# error "Unknown platform"
+# endif
+}
+
+int
+IceSSL_opensslPasswordCallback(char* buf, int size, int flag, void* userData)
+{
+ OpenSSLEngine* p = reinterpret_cast<OpenSSLEngine*>(userData);
+ string passwd = p->password(flag == 1);
+ int sz = static_cast<int>(passwd.size());
+ if(sz > size)
+ {
+ sz = size - 1;
+ }
+# if defined(_WIN32)
+ strncpy_s(buf, size, passwd.c_str(), sz);
+# else
+ strncpy(buf, passwd.c_str(), sz);
+# endif
+ buf[sz] = '\0';
+
+ for(string::iterator i = passwd.begin(); i != passwd.end(); ++i)
+ {
+ *i = '\0';
+ }
+
+ return sz;
+}
+
+# ifndef OPENSSL_NO_DH
+DH*
+IceSSL_opensslDHCallback(SSL* ssl, int /*isExport*/, int keyLength)
+{
+ OpenSSLEngine* p = reinterpret_cast<OpenSSLEngine*>(SSL_CTX_get_ex_data(ssl->ctx, 0));
+ return p->dhParams(keyLength);
+}
+# endif
+
+int
+IceSSL_opensslVerifyCallback(int ok, X509_STORE_CTX* ctx)
+{
+ SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
+ OpenSSLEngine* p = reinterpret_cast<OpenSSLEngine*>(SSL_CTX_get_ex_data(ssl->ctx, 0));
+ return p->verifyCallback(ok, ssl, ctx);
+}
+
+}
+
+namespace
+{
+bool
+passwordError()
+{
+ int reason = ERR_GET_REASON(ERR_peek_error());
+ return (reason == PEM_R_BAD_BASE64_DECODE ||
+ reason == PEM_R_BAD_DECRYPT ||
+ reason == PEM_R_BAD_PASSWORD_READ ||
+ reason == PEM_R_PROBLEMS_GETTING_PASSWORD);
+}
+
+}
+
+IceUtil::Shared* IceSSL::upCast(IceSSL::OpenSSLEngine* p) { return p; }
+
+OpenSSLEngine::OpenSSLEngine(const CommunicatorPtr& communicator) :
+ SSLEngine(communicator),
+ _initialized(false),
+ _ctx(0)
+{
+ __setNoDelete(true);
+
+ //
+ // Initialize OpenSSL if necessary.
+ //
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(staticMutex);
+ instanceCount++;
+
+ if(instanceCount == 1)
+ {
+ PropertiesPtr properties = communicator->getProperties();
+
+ //
+ // The IceSSL.InitOpenSSL property specifies whether we should perform the global
+ // startup (and shutdown) tasks for the OpenSSL library.
+ //
+ // If an application uses multiple components that each depend on OpenSSL, the
+ // application should disable OpenSSL initialization in those components and
+ // perform the initialization itself.
+ //
+ _initOpenSSL = properties->getPropertyAsIntWithDefault("IceSSL.InitOpenSSL", 1) > 0;
+ if(_initOpenSSL)
+ {
+ //
+ // Create the mutexes and set the callbacks.
+ //
+ if(!locks)
+ {
+ locks = new IceUtil::Mutex[CRYPTO_num_locks()];
+ CRYPTO_set_locking_callback(IceSSL_opensslLockCallback);
+ CRYPTO_set_id_callback(IceSSL_opensslThreadIdCallback);
+ }
+
+ //
+ // Load human-readable error messages.
+ //
+ SSL_load_error_strings();
+
+ //
+ // Initialize the SSL library.
+ //
+ SSL_library_init();
+
+ //
+ // This is necessary to allow programs that use OpenSSL 0.9.x to
+ // load private key files generated by OpenSSL 1.x.
+ //
+ OpenSSL_add_all_algorithms();
+
+ //
+ // Initialize the PRNG.
+ //
+# ifdef WINDOWS
+ RAND_screen(); // Uses data from the screen if possible.
+# endif
+ char randFile[1024];
+ if(RAND_file_name(randFile, sizeof(randFile))) // Gets the name of a default seed file.
+ {
+ RAND_load_file(randFile, 1024);
+ }
+
+ string randFiles = properties->getProperty("IceSSL.Random");
+
+ if(!randFiles.empty())
+ {
+ vector<string> files;
+ string defaultDir = properties->getProperty("IceSSL.DefaultDir");
+
+ if(!IceUtilInternal::splitString(randFiles, IceUtilInternal::pathsep, files))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: invalid value for IceSSL.Random:\n" + randFiles;
+ throw ex;
+ }
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ {
+ string file = *p;
+ if(!checkPath(file, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: entropy data file not found:\n" + file;
+ throw ex;
+ }
+ if(!RAND_load_file(file.c_str(), 1024))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unable to load entropy data from " + file;
+ throw ex;
+ }
+ }
+ }
+# ifndef _WIN32
+ //
+ // The Entropy Gathering Daemon (EGD) is not available on Windows.
+ // The file should be a Unix domain socket for the daemon.
+ //
+ string entropyDaemon = properties->getProperty("IceSSL.EntropyDaemon");
+ if(!entropyDaemon.empty())
+ {
+ if(RAND_egd(entropyDaemon.c_str()) <= 0)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: EGD failure using file " + entropyDaemon;
+ throw ex;
+ }
+ }
+# endif
+ if(!RAND_status())
+ {
+ getLogger()->warning("IceSSL: insufficient data to initialize PRNG");
+ }
+ }
+ else
+ {
+ if(!properties->getProperty("IceSSL.Random").empty())
+ {
+ getLogger()->warning("IceSSL: ignoring IceSSL.Random because OpenSSL initialization is disabled");
+ }
+# ifndef _WIN32
+ else if(!properties->getProperty("IceSSL.EntropyDaemon").empty())
+ {
+ getLogger()->warning("IceSSL: ignoring IceSSL.EntropyDaemon because OpenSSL initialization is disabled");
+ }
+# endif
+ }
+ }
+ __setNoDelete(false);
+}
+
+OpenSSLEngine::~OpenSSLEngine()
+{
+ //
+ // Clean up OpenSSL resources.
+ //
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(staticMutex);
+
+ if(--instanceCount == 0 && _initOpenSSL)
+ {
+ //
+ // NOTE: We can't destroy the locks here: threads which might have called openssl methods
+ // might access openssl locks upon termination (from DllMain/THREAD_DETACHED). Instead,
+ // we release the locks in the ~Init() static destructor. See bug #4156.
+ //
+ //CRYPTO_set_locking_callback(0);
+ //CRYPTO_set_id_callback(0);
+ //delete[] locks;
+ //locks = 0;
+
+ CRYPTO_cleanup_all_ex_data();
+ RAND_cleanup();
+ ERR_free_strings();
+ EVP_cleanup();
+ }
+}
+
+bool
+OpenSSLEngine::initialized() const
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+ return _initialized;
+}
+
+void
+OpenSSLEngine::initialize()
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+ if(_initialized)
+ {
+ return;
+ }
+
+ try
+ {
+ SSLEngine::initialize();
+
+ const string propPrefix = "IceSSL.";
+ PropertiesPtr properties = communicator()->getProperties();
+
+ //
+ // Protocols selects which protocols to enable.
+ //
+ const int protocols = parseProtocols(properties->getPropertyAsList(propPrefix + "Protocols"));
+
+ //
+ // Create an SSL context if the application hasn't supplied one.
+ //
+ if(!_ctx)
+ {
+ _ctx = SSL_CTX_new(getMethod(protocols));
+ if(!_ctx)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unable to create SSL context:\n" + sslErrors();
+ throw ex;
+ }
+
+ //
+ // Check for a default directory. We look in this directory for
+ // files mentioned in the configuration.
+ //
+ string defaultDir = properties->getProperty(propPrefix + "DefaultDir");
+
+ //
+ // If the configuration defines a password, or the application has supplied
+ // a password prompt object, then register a password callback. Otherwise,
+ // let OpenSSL use its default behavior.
+ //
+ {
+ // TODO: Support quoted value?
+ string password = properties->getProperty(propPrefix + "Password");
+ if(!password.empty() || getPasswordPrompt())
+ {
+ SSL_CTX_set_default_passwd_cb(_ctx, IceSSL_opensslPasswordCallback);
+ SSL_CTX_set_default_passwd_cb_userdata(_ctx, this);
+ setPassword(password);
+ }
+ }
+
+ int passwordRetryMax = properties->getPropertyAsIntWithDefault(propPrefix + "PasswordRetryMax", 3);
+
+ //
+ // Establish the location of CA certificates.
+ //
+ {
+ string caFile = properties->getProperty(propPrefix + "CertAuthFile");
+ string caDir = properties->getPropertyWithDefault(propPrefix + "CertAuthDir", defaultDir);
+ const char* file = 0;
+ const char* dir = 0;
+ if(!caFile.empty())
+ {
+ if(!checkPath(caFile, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: CA certificate file not found:\n" + caFile;
+ throw ex;
+ }
+ file = caFile.c_str();
+ }
+ if(!caDir.empty())
+ {
+ if(!checkPath(caDir, defaultDir, true))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: CA certificate directory not found:\n" + caDir;
+ throw ex;
+ }
+ dir = caDir.c_str();
+ }
+ if(file || dir)
+ {
+ //
+ // The certificate may be stored in an encrypted file, so handle
+ // password retries.
+ //
+ int count = 0;
+ int err = 0;
+ while(count < passwordRetryMax)
+ {
+ ERR_clear_error();
+ err = SSL_CTX_load_verify_locations(_ctx, file, dir);
+ if(err)
+ {
+ break;
+ }
+ ++count;
+ }
+ if(err == 0)
+ {
+ string msg = "IceSSL: unable to establish CA certificates";
+ if(passwordError())
+ {
+ msg += ":\ninvalid password";
+ }
+ else
+ {
+ string err = sslErrors();
+ if(!err.empty())
+ {
+ msg += ":\n" + err;
+ }
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+ }
+ }
+
+ //
+ // Establish the certificate chains and private keys. One RSA certificate and
+ // one DSA certificate are allowed.
+ //
+ {
+ string certFile = properties->getProperty(propPrefix + "CertFile");
+ string keyFile = properties->getProperty(propPrefix + "KeyFile");
+ vector<string>::size_type numCerts = 0;
+ if(!certFile.empty())
+ {
+ vector<string> files;
+ if(!IceUtilInternal::splitString(certFile, IceUtilInternal::pathsep, files) || files.size() > 2)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: invalid value for " + propPrefix + "CertFile:\n" + certFile;
+ throw ex;
+ }
+ numCerts = files.size();
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ {
+ string file = *p;
+ if(!checkPath(file, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: certificate file not found:\n" + file;
+ throw ex;
+ }
+ //
+ // The certificate may be stored in an encrypted file, so handle
+ // password retries.
+ //
+ int count = 0;
+ int err = 0;
+ while(count < passwordRetryMax)
+ {
+ ERR_clear_error();
+ err = SSL_CTX_use_certificate_chain_file(_ctx, file.c_str());
+ if(err)
+ {
+ break;
+ }
+ ++count;
+ }
+ if(err == 0)
+ {
+ string msg = "IceSSL: unable to load certificate chain from file " + file;
+ if(passwordError())
+ {
+ msg += ":\ninvalid password";
+ }
+ else
+ {
+ string err = sslErrors();
+ if(!err.empty())
+ {
+ msg += ":\n" + err;
+ }
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+ }
+ }
+ if(keyFile.empty())
+ {
+ keyFile = certFile; // Assume the certificate file also contains the private key.
+ }
+ if(!keyFile.empty())
+ {
+ vector<string> files;
+ if(!IceUtilInternal::splitString(keyFile, IceUtilInternal::pathsep, files) || files.size() > 2)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: invalid value for " + propPrefix + "KeyFile:\n" + keyFile;
+ throw ex;
+ }
+ if(files.size() != numCerts)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: " + propPrefix + "KeyFile does not agree with " + propPrefix + "CertFile";
+ throw ex;
+ }
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ {
+ string file = *p;
+ if(!checkPath(file, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: key file not found:\n" + file;
+ throw ex;
+ }
+ //
+ // The private key may be stored in an encrypted file, so handle
+ // password retries.
+ //
+ int count = 0;
+ int err = 0;
+ while(count < passwordRetryMax)
+ {
+ ERR_clear_error();
+ err = SSL_CTX_use_PrivateKey_file(_ctx, file.c_str(), SSL_FILETYPE_PEM);
+ if(err)
+ {
+ break;
+ }
+ ++count;
+ }
+ if(err == 0)
+ {
+ string msg = "IceSSL: unable to load private key from file " + file;
+ if(passwordError())
+ {
+ msg += ":\ninvalid password";
+ }
+ else
+ {
+ string err = sslErrors();
+ if(!err.empty())
+ {
+ msg += ":\n" + err;
+ }
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+ }
+ if(!SSL_CTX_check_private_key(_ctx))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unable to validate private key(s):\n" + sslErrors();
+ throw ex;
+ }
+ }
+ }
+
+ //
+ // Diffie Hellman configuration.
+ //
+ {
+# ifndef OPENSSL_NO_DH
+ _dhParams = new DHParams;
+ SSL_CTX_set_options(_ctx, SSL_OP_SINGLE_DH_USE);
+ SSL_CTX_set_tmp_dh_callback(_ctx, IceSSL_opensslDHCallback);
+# endif
+ //
+ // Properties have the following form:
+ //
+ // ...DH.<keyLength>=file
+ //
+ const string dhPrefix = propPrefix + "DH.";
+ PropertyDict d = properties->getPropertiesForPrefix(dhPrefix);
+ if(!d.empty())
+ {
+# ifdef OPENSSL_NO_DH
+ getLogger()->warning("IceSSL: OpenSSL is not configured for Diffie Hellman");
+# else
+ for(PropertyDict::iterator p = d.begin(); p != d.end(); ++p)
+ {
+ string s = p->first.substr(dhPrefix.size());
+ int keyLength = atoi(s.c_str());
+ if(keyLength > 0)
+ {
+ string file = p->second;
+ if(!checkPath(file, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: DH parameter file not found:\n" + file;
+ throw ex;
+ }
+ if(!_dhParams->add(keyLength, file))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unable to read DH parameter file " + file;
+ throw ex;
+ }
+ }
+ }
+# endif
+ }
+ }
+ }
+
+ //
+ // Store a pointer to ourself for use in OpenSSL callbacks.
+ //
+ SSL_CTX_set_ex_data(_ctx, 0, this);
+
+ //
+ // This is necessary for successful interop with Java. Without it, a Java
+ // client would fail to reestablish a connection: the server gets the
+ // error "session id context uninitialized" and the client receives
+ // "SSLHandshakeException: Remote host closed connection during handshake".
+ //
+ SSL_CTX_set_session_cache_mode(_ctx, SSL_SESS_CACHE_OFF);
+
+ //
+ // Although we disable session caching, we still need to set a session ID
+ // context (ICE-5103). The value can be anything; here we just use the
+ // pointer to this SharedInstance object.
+ //
+ SSL_CTX_set_session_id_context(_ctx, reinterpret_cast<unsigned char*>(this),
+ static_cast<unsigned int>(sizeof(this)));
+
+ //
+ // Select protocols.
+ //
+ if(protocols != 0)
+ {
+ setOptions(protocols);
+ }
+
+ //
+ // Establish the cipher list.
+ //
+ string ciphers = properties->getProperty(propPrefix + "Ciphers");
+ if(!ciphers.empty())
+ {
+ if(!SSL_CTX_set_cipher_list(_ctx, ciphers.c_str()))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unable to set ciphers using `" + ciphers + "':\n" + sslErrors();
+ throw ex;
+ }
+ }
+
+ //
+ // Determine whether a certificate is required from the peer.
+ //
+ {
+ int sslVerifyMode;
+ switch(getVerifyPeer())
+ {
+ case 0:
+ sslVerifyMode = SSL_VERIFY_NONE;
+ break;
+ case 1:
+ sslVerifyMode = SSL_VERIFY_PEER;
+ break;
+ case 2:
+ sslVerifyMode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ break;
+ default:
+ {
+ assert(false);
+ }
+ }
+ SSL_CTX_set_verify(_ctx, sslVerifyMode, IceSSL_opensslVerifyCallback);
+ }
+ }
+ catch(...)
+ {
+ //
+ // We free the SSL context regardless of whether the plugin created it
+ // or the application supplied it.
+ //
+ SSL_CTX_free(_ctx);
+ _ctx = 0;
+ throw;
+ }
+
+ _initialized = true;
+}
+
+void
+OpenSSLEngine::context(ContextRef context)
+{
+ if(initialized())
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: plug-in is already initialized";
+ throw ex;
+ }
+
+ assert(!_ctx);
+ _ctx = context;
+}
+
+ContextRef
+OpenSSLEngine::context() const
+{
+ return _ctx;
+}
+
+void
+OpenSSLEngine::verifyPeer(SSL* ssl, SOCKET fd, const string& address, const NativeConnectionInfoPtr& info)
+{
+ long result = SSL_get_verify_result(ssl);
+ if(result != X509_V_OK)
+ {
+ if(getVerifyPeer() == 0)
+ {
+ if(securityTraceLevel() >= 1)
+ {
+ ostringstream ostr;
+ ostr << "IceSSL: ignoring certificate verification failure:\n" << X509_verify_cert_error_string(result);
+ getLogger()->trace(securityTraceCategory(), ostr.str());
+ }
+ }
+ else
+ {
+ ostringstream ostr;
+ ostr << "IceSSL: certificate verification failed:\n" << X509_verify_cert_error_string(result);
+ string msg = ostr.str();
+ if(securityTraceLevel() >= 1)
+ {
+ getLogger()->trace(securityTraceCategory(), msg);
+ }
+ SecurityException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+ }
+ SSLEngine::verifyPeer(fd, address, info);
+}
+
+string
+OpenSSLEngine::sslErrors() const
+{
+ return getSslErrors(securityTraceLevel() >= 1);
+}
+
+void
+OpenSSLEngine::destroy()
+{
+ if(_ctx)
+ {
+ SSL_CTX_free(_ctx);
+ }
+}
+
+int
+OpenSSLEngine::verifyCallback(int ok, SSL* ssl, X509_STORE_CTX* c)
+{
+ if(!ok && securityTraceLevel() >= 1)
+ {
+ X509* cert = X509_STORE_CTX_get_current_cert(c);
+ int err = X509_STORE_CTX_get_error(c);
+ char buf[256];
+
+ Trace out(getLogger(), securityTraceCategory());
+ out << "certificate verification failure\n";
+
+ X509_NAME_oneline(X509_get_issuer_name(cert), buf, static_cast<int>(sizeof(buf)));
+ out << "issuer = " << buf << '\n';
+ X509_NAME_oneline(X509_get_subject_name(cert), buf, static_cast<int>(sizeof(buf)));
+ out << "subject = " << buf << '\n';
+ out << "depth = " << X509_STORE_CTX_get_error_depth(c) << '\n';
+ out << "error = " << X509_verify_cert_error_string(err) << '\n';
+ out << IceInternal::fdToString(SSL_get_fd(ssl));
+ }
+ return ok;
+}
+
+# ifndef OPENSSL_NO_DH
+DH*
+OpenSSLEngine::dhParams(int keyLength)
+{
+ return _dhParams->get(keyLength);
+}
+# endif
+
+int
+OpenSSLEngine::parseProtocols(const StringSeq& protocols) const
+{
+ int v = 0;
+
+ for(Ice::StringSeq::const_iterator p = protocols.begin(); p != protocols.end(); ++p)
+ {
+ string prot = *p;
+
+ if(prot == "ssl3" || prot == "sslv3")
+ {
+ v |= SSLv3;
+ }
+ else if(prot == "tls" || prot == "tls1" || prot == "tlsv1" || prot == "tls1_0" || prot == "tlsv1_0")
+ {
+ v |= TLSv1_0;
+ }
+ else if(prot == "tls1_1" || prot == "tlsv1_1")
+ {
+ v |= TLSv1_1;
+ }
+ else if(prot == "tls1_2" || prot == "tlsv1_2")
+ {
+ v |= TLSv1_2;
+ }
+ else
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unrecognized protocol `" + prot + "'";
+ throw ex;
+ }
+ }
+
+ return v;
+}
+
+SSL_METHOD*
+OpenSSLEngine::getMethod(int /*protocols*/)
+{
+ //
+ // Despite its name, the SSLv23 method can negotiate SSL3, TLS1.0, TLS1.1, and TLS1.2.
+ // We use the const_cast for backward compatibility with older OpenSSL releases.
+ //
+ SSL_METHOD* meth = const_cast<SSL_METHOD*>(SSLv23_method());
+
+ /*
+ * Early versions of OpenSSL 1.0.1 would not negotiate a TLS1.2 connection using
+ * the SSLv23 method. You can enable the code below to override the method.
+ if(protocols & TLSv1_2)
+ {
+ meth = const_cast<SSL_METHOD*>(TLSv1_2_method());
+ }
+ */
+
+ return meth;
+}
+
+void
+OpenSSLEngine::setOptions(int protocols)
+{
+ long opts = SSL_OP_NO_SSLv2; // SSLv2 is not supported.
+ if(!(protocols & SSLv3))
+ {
+ opts |= SSL_OP_NO_SSLv3;
+ }
+ if(!(protocols & TLSv1_0))
+ {
+ opts |= SSL_OP_NO_TLSv1;
+ }
+# ifdef SSL_OP_NO_TLSv1_1
+ if(!(protocols & TLSv1_1))
+ {
+ opts |= SSL_OP_NO_TLSv1_1;
+ //
+ // The value of SSL_OP_NO_TLSv1_1 changed between 1.0.1a and 1.0.1b.
+ //
+ if(SSL_OP_NO_TLSv1_1 == 0x00000400L)
+ {
+ opts |= 0x10000000L; // New value of SSL_OP_NO_TLSv1_1.
+ }
+ }
+# endif
+# ifdef SSL_OP_NO_TLSv1_2
+ if(!(protocols & TLSv1_2))
+ {
+ opts |= SSL_OP_NO_TLSv1_2;
+ }
+# endif
+ SSL_CTX_set_options(_ctx, opts);
+}
+
+#endif // ICESSL_USE_OPENSSL
diff --git a/cpp/src/IceSSL/PluginI.cpp b/cpp/src/IceSSL/PluginI.cpp
index 91e07455ff8..02f9cf1a6e1 100644
--- a/cpp/src/IceSSL/PluginI.cpp
+++ b/cpp/src/IceSSL/PluginI.cpp
@@ -30,8 +30,7 @@ extern "C"
ICE_DECLSPEC_EXPORT Ice::Plugin*
createIceSSL(const CommunicatorPtr& communicator, const string& /*name*/, const StringSeq& /*args*/)
{
- PluginI* plugin = new PluginI(communicator);
- return plugin;
+ return new PluginI(communicator);
}
}
@@ -41,8 +40,12 @@ createIceSSL(const CommunicatorPtr& communicator, const string& /*name*/, const
//
IceSSL::PluginI::PluginI(const Ice::CommunicatorPtr& communicator)
{
- _sharedInstance = new SharedInstance(communicator);
-
+#ifdef ICE_USE_OPENSSL
+ _engine = new OpenSSLEngine(communicator);
+#else
+ _engine = new SecureTransportEngine(communicator);
+#endif
+
IceInternal::ProtocolPluginFacadePtr facade = IceInternal::getProtocolPluginFacade(communicator);
//
@@ -50,42 +53,44 @@ IceSSL::PluginI::PluginI(const Ice::CommunicatorPtr& communicator)
// in initialize, because the communicator may need to interpret
// proxies before the plug-in is fully initialized.
//
- facade->addEndpointFactory(new EndpointFactoryI(new Instance(_sharedInstance, EndpointType, "ssl")));
+ facade->addEndpointFactory(new EndpointFactoryI(new Instance(_engine, EndpointType, "ssl")));
}
void
IceSSL::PluginI::initialize()
{
- _sharedInstance->initialize();
+ _engine->initialize();
}
void
IceSSL::PluginI::destroy()
{
- _sharedInstance->destroy();
- _sharedInstance = 0;
+ _engine->destroy();
+ _engine = 0;
}
void
-IceSSL::PluginI::setContext(SSL_CTX* context)
+IceSSL::PluginI::setCertificateVerifier(const CertificateVerifierPtr& verifier)
{
- _sharedInstance->context(context);
+ _engine->setCertificateVerifier(verifier);
}
-SSL_CTX*
-IceSSL::PluginI::getContext()
+void
+IceSSL::PluginI::setPasswordPrompt(const PasswordPromptPtr& prompt)
{
- return _sharedInstance->context();
+ _engine->setPasswordPrompt(prompt);
}
+#ifdef ICE_USE_OPENSSL
void
-IceSSL::PluginI::setCertificateVerifier(const CertificateVerifierPtr& verifier)
+IceSSL::PluginI::setContext(ContextRef context)
{
- _sharedInstance->setCertificateVerifier(verifier);
+ _engine->context(context);
}
-void
-IceSSL::PluginI::setPasswordPrompt(const PasswordPromptPtr& prompt)
+ContextRef
+IceSSL::PluginI::getContext()
{
- _sharedInstance->setPasswordPrompt(prompt);
+ return _engine->context();
}
+#endif
diff --git a/cpp/src/IceSSL/PluginI.h b/cpp/src/IceSSL/PluginI.h
index 4a0a030987b..7d1903aa7bd 100644
--- a/cpp/src/IceSSL/PluginI.h
+++ b/cpp/src/IceSSL/PluginI.h
@@ -11,13 +11,18 @@
#define ICE_SSL_PLUGIN_I_H
#include <IceSSL/Plugin.h>
-#include <IceSSL/InstanceF.h>
+#include <IceSSL/SSLEngineF.h>
#include <Ice/CommunicatorF.h>
namespace IceSSL
{
-class PluginI : public IceSSL::Plugin
+class PluginI :
+#ifdef ICE_USE_OPENSSL
+ public OpenSSLPlugin
+#else
+ public IceSSL::Plugin
+#endif
{
public:
@@ -32,14 +37,21 @@ public:
//
// From IceSSL::Plugin.
//
- virtual void setContext(SSL_CTX*);
- virtual SSL_CTX* getContext();
virtual void setCertificateVerifier(const CertificateVerifierPtr&);
virtual void setPasswordPrompt(const PasswordPromptPtr&);
+#ifdef ICE_USE_OPENSSL
+ virtual void setContext(ContextRef);
+ virtual ContextRef getContext();
+#endif
+
private:
- SharedInstancePtr _sharedInstance;
+#ifdef ICE_USE_OPENSSL
+ OpenSSLEnginePtr _engine;
+#else
+ SecureTransportEnginePtr _engine;
+#endif
};
}
diff --git a/cpp/src/IceSSL/RFC2253.cpp b/cpp/src/IceSSL/RFC2253.cpp
index 331838bf928..eaa86e979c5 100644
--- a/cpp/src/IceSSL/RFC2253.cpp
+++ b/cpp/src/IceSSL/RFC2253.cpp
@@ -231,6 +231,7 @@ parseAttributeTypeAndValue(const string& data, size_t& pos)
pair<string, string> p;
p.first = parseAttributeType(data, pos);
eatWhite(data, pos);
+
if(pos >= data.size())
{
throw ParseException(__FILE__, __LINE__, "invalid attribute type/value pair (unexpected end of data)");
diff --git a/cpp/src/IceSSL/SSLEngine.cpp b/cpp/src/IceSSL/SSLEngine.cpp
new file mode 100644
index 00000000000..adbfb439bc0
--- /dev/null
+++ b/cpp/src/IceSSL/SSLEngine.cpp
@@ -0,0 +1,291 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#include <IceSSL/SSLEngine.h>
+#include <IceSSL/TrustManager.h>
+
+#include <IceUtil/StringUtil.h>
+
+#include <Ice/Communicator.h>
+#include <Ice/Properties.h>
+#include <Ice/Logger.h>
+#include <Ice/LoggerUtil.h>
+#include <Ice/LocalException.h>
+
+#include <string>
+
+using namespace std;
+using namespace Ice;
+using namespace IceSSL;
+
+IceUtil::Shared* IceSSL::upCast(IceSSL::SSLEngine* p) { return p; }
+
+IceSSL::SSLEngine::SSLEngine(const Ice::CommunicatorPtr& communicator) :
+ _communicator(communicator),
+ _logger(communicator->getLogger()),
+ _trustManager(new TrustManager(communicator))
+{
+}
+
+IceSSL::CertificateVerifierPtr
+IceSSL::SSLEngine::getCertificateVerifier() const
+{
+ return _verifier;
+}
+
+void
+IceSSL::SSLEngine::setCertificateVerifier(const IceSSL::CertificateVerifierPtr& verifier)
+{
+ _verifier = verifier;
+}
+
+IceSSL::PasswordPromptPtr
+IceSSL::SSLEngine::getPasswordPrompt() const
+{
+ return _prompt;
+}
+
+void
+IceSSL::SSLEngine::setPasswordPrompt(const IceSSL::PasswordPromptPtr& prompt)
+{
+ _prompt = prompt;
+}
+
+string
+IceSSL::SSLEngine::password(bool /*encrypting*/)
+{
+ if(_prompt)
+ {
+ try
+ {
+ return _prompt->getPassword();
+ }
+ catch(...)
+ {
+ //
+ // Don't allow exceptions to cross an OpenSSL boundary.
+ //
+ return string();
+ }
+ }
+ else
+ {
+ return _password;
+ }
+}
+
+string
+IceSSL::SSLEngine::getPassword() const
+{
+ return _password;
+}
+
+void
+IceSSL::SSLEngine::setPassword(const std::string& password)
+{
+ _password = password;
+}
+
+void
+IceSSL::SSLEngine::initialize()
+{
+ const string propPrefix = "IceSSL.";
+ const PropertiesPtr properties = communicator()->getProperties();
+
+ //
+ // CheckCertName determines whether we compare the name in a peer's
+ // certificate against its hostname.
+ //
+ _checkCertName = properties->getPropertyAsIntWithDefault(propPrefix + "CheckCertName", 0) > 0;
+
+ //
+ // VerifyDepthMax establishes the maximum length of a peer's certificate
+ // chain, including the peer's certificate. A value of 0 means there is
+ // no maximum.
+ //
+ _verifyDepthMax = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyDepthMax", 2);
+
+ //
+ // VerifyPeer determines whether certificate validation failures abort a connection.
+ //
+ _verifyPeer = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyPeer", 2);
+
+ if(_verifyPeer < 0 || _verifyPeer > 2)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: invalid value for " + propPrefix + "VerifyPeer";
+ throw ex;
+ }
+
+ _securityTraceLevel = properties->getPropertyAsInt("IceSSL.Trace.Security");
+ _securityTraceCategory = "Security";
+}
+
+void
+IceSSL::SSLEngine::verifyPeer(SOCKET fd, const string& address, const NativeConnectionInfoPtr& info)
+{
+ const CertificateVerifierPtr verifier = getCertificateVerifier();
+
+ //
+ // For an outgoing connection, we compare the proxy address (if any) against
+ // fields in the server's certificate (if any).
+ //
+ if(!info->nativeCerts.empty() && !address.empty())
+ {
+ const CertificatePtr cert = info->nativeCerts[0];
+ //
+ // Extract the IP addresses and the DNS names from the subject
+ // alternative names.
+ //
+ vector<pair<int, string> > subjectAltNames = cert->getSubjectAlternativeNames();
+ vector<string> ipAddresses;
+ vector<string> dnsNames;
+ for(vector<pair<int, string> >::const_iterator p = subjectAltNames.begin(); p != subjectAltNames.end(); ++p)
+ {
+ if(p->first == 7)
+ {
+ ipAddresses.push_back(IceUtilInternal::toLower(p->second));
+ }
+ else if(p->first == 2)
+ {
+ dnsNames.push_back(IceUtilInternal::toLower(p->second));
+ }
+ }
+
+ //
+ // Compare the peer's address against the common name.
+ //
+ bool certNameOK = false;
+ string dn;
+ string addrLower = IceUtilInternal::toLower(address);
+ {
+ DistinguishedName d = cert->getSubjectDN();
+ dn = IceUtilInternal::toLower(string(d));
+ string cn = "cn=" + addrLower;
+ string::size_type pos = dn.find(cn);
+ if(pos != string::npos)
+ {
+ //
+ // Ensure we match the entire common name.
+ //
+ certNameOK = (pos + cn.size() == dn.size()) || (dn[pos + cn.size()] == ',');
+ }
+ }
+
+ //
+ // Compare the peer's address against the dnsName and ipAddress
+ // values in the subject alternative name.
+ //
+ if(!certNameOK)
+ {
+ certNameOK = find(ipAddresses.begin(), ipAddresses.end(), addrLower) != ipAddresses.end();
+ }
+ if(!certNameOK)
+ {
+ certNameOK = find(dnsNames.begin(), dnsNames.end(), addrLower) != dnsNames.end();
+ }
+
+ //
+ // Log a message if the name comparison fails. If CheckCertName is defined,
+ // we also raise an exception to abort the connection. Don't log a message if
+ // CheckCertName is not defined and a verifier is present.
+ //
+ if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && !verifier)))
+ {
+ ostringstream ostr;
+ ostr << "IceSSL: ";
+ if(!_checkCertName)
+ {
+ ostr << "ignoring ";
+ }
+ ostr << "certificate validation failure:\npeer certificate does not have `" << address
+ << "' as its commonName or in its subjectAltName extension";
+ if(!dn.empty())
+ {
+ ostr << "\nSubject DN: " << dn;
+ }
+ if(!dnsNames.empty())
+ {
+ ostr << "\nDNS names found in certificate: ";
+ for(vector<string>::const_iterator p = dnsNames.begin(); p != dnsNames.end(); ++p)
+ {
+ if(p != dnsNames.begin())
+ {
+ ostr << ", ";
+ }
+ ostr << *p;
+ }
+ }
+ if(!ipAddresses.empty())
+ {
+ ostr << "\nIP addresses found in certificate: ";
+ for(vector<string>::const_iterator p = ipAddresses.begin(); p != ipAddresses.end(); ++p)
+ {
+ if(p != ipAddresses.begin())
+ {
+ ostr << ", ";
+ }
+ ostr << *p;
+ }
+ }
+ string msg = ostr.str();
+ if(_securityTraceLevel >= 1)
+ {
+ Trace out(getLogger(), _securityTraceCategory);
+ out << msg;
+ }
+ if(_checkCertName)
+ {
+ SecurityException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+ }
+ }
+
+ if(_verifyDepthMax > 0 && static_cast<int>(info->certs.size()) > _verifyDepthMax)
+ {
+ ostringstream ostr;
+ ostr << (info->incoming ? "incoming" : "outgoing") << " connection rejected:\n"
+ << "length of peer's certificate chain (" << info->certs.size() << ") exceeds maximum of "
+ << _verifyDepthMax;
+ string msg = ostr.str();
+ if(_securityTraceLevel >= 1)
+ {
+ getLogger()->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
+ }
+ SecurityException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+
+ if(!_trustManager->verify(info))
+ {
+ string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by trust manager";
+ if(_securityTraceLevel >= 1)
+ {
+ getLogger()->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
+ }
+ SecurityException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+
+ if(verifier && !verifier->verify(info))
+ {
+ string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier";
+ if(_securityTraceLevel >= 1)
+ {
+ getLogger()->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
+ }
+ SecurityException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+}
diff --git a/cpp/src/IceSSL/SSLEngine.h b/cpp/src/IceSSL/SSLEngine.h
new file mode 100644
index 00000000000..e4f1891222a
--- /dev/null
+++ b/cpp/src/IceSSL/SSLEngine.h
@@ -0,0 +1,179 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#ifndef ICE_SSL_ENGINE_H
+#define ICE_SSL_ENGINE_H
+
+#include <IceSSL/Plugin.h>
+#include <IceSSL/Util.h>
+#include <IceSSL/SSLEngineF.h>
+#include <IceSSL/TrustManagerF.h>
+
+#include <IceUtil/ScopedArray.h>
+#include <IceUtil/UniquePtr.h>
+#include <IceUtil/Shared.h>
+#include <IceUtil/Mutex.h>
+#include <Ice/CommunicatorF.h>
+#include <Ice/Network.h>
+
+#ifdef ICE_USE_SECURE_TRANSPORT
+# include <Security/Security.h>
+#endif
+
+namespace IceSSL
+{
+
+class SSLEngine : public IceUtil::Shared
+{
+public:
+
+ SSLEngine(const Ice::CommunicatorPtr&);
+
+ Ice::CommunicatorPtr communicator() const { return _communicator; }
+ Ice::LoggerPtr getLogger() const { return _logger; };
+
+ void setCertificateVerifier(const CertificateVerifierPtr&);
+ void setPasswordPrompt(const PasswordPromptPtr&);
+ std::string password(bool);
+
+ //
+ // Setup the engine.
+ //
+ virtual void initialize() = 0;
+
+ virtual bool initialized() const = 0;
+
+ //
+ // Destroy the engine.
+ //
+ virtual void destroy() = 0;
+
+ //
+ // Verify peer certificate
+ //
+ virtual void verifyPeer(SOCKET, const std::string&, const NativeConnectionInfoPtr&);
+
+
+ CertificateVerifierPtr getCertificateVerifier() const;
+ PasswordPromptPtr getPasswordPrompt() const;
+
+ std::string getPassword() const;
+ void setPassword(const std::string& password);
+
+ int getVerifyPeer() const { return _verifyPeer; }
+ int securityTraceLevel() const { return _securityTraceLevel; }
+ std::string securityTraceCategory() const { return _securityTraceCategory; }
+
+private:
+
+ const Ice::CommunicatorPtr _communicator;
+ const Ice::LoggerPtr _logger;
+ const TrustManagerPtr _trustManager;
+
+ std::string _password;
+ CertificateVerifierPtr _verifier;
+ PasswordPromptPtr _prompt;
+
+ bool _checkCertName;
+ int _verifyDepthMax;
+ int _verifyPeer;
+ int _securityTraceLevel;
+ std::string _securityTraceCategory;
+};
+
+#ifdef ICE_USE_SECURE_TRANSPORT
+
+class SecureTransportEngine : public SSLEngine
+{
+public:
+
+ SecureTransportEngine(const Ice::CommunicatorPtr&);
+
+ virtual void initialize();
+ virtual bool initialized() const;
+ virtual void destroy();
+
+ ContextRef newContext(bool);
+ CFArrayRef getCertificateAuthorities() const;
+ std::string getCipherName(SSLCipherSuite) const;
+ SecCertificateRef getCertificate() const;
+ SecKeychainRef getKeychain() const;
+
+private:
+
+ void parseCiphers(const std::string& ciphers);
+
+ bool _initialized;
+ ContextRef _ctx;
+ CFArrayRef _certificateAuthorities;
+ SecCertificateRef _cert;
+ SecKeyRef _key;
+ SecIdentityRef _identity;
+ SecKeychainRef _keychain;
+
+ SSLProtocol _protocolVersionMax;
+ SSLProtocol _protocolVersionMin;
+
+ std::string _defaultDir;
+
+
+ IceUtil::UniquePtr< IceUtil::ScopedArray<char> > _dhParams;
+ size_t _dhParamsLength;
+
+ IceUtil::UniquePtr< IceUtil::ScopedArray<SSLCipherSuite> > _ciphers;
+ bool _allCiphers;
+ size_t _numCiphers;
+ IceUtil::Mutex _mutex;
+};
+
+#else
+class OpenSSLEngine : public SSLEngine
+{
+public:
+
+ OpenSSLEngine(const Ice::CommunicatorPtr&);
+ ~OpenSSLEngine();
+
+ virtual void initialize();
+ virtual bool initialized() const;
+ virtual void destroy();
+ virtual void verifyPeer(SSL*, SOCKET, const std::string&, const NativeConnectionInfoPtr&);
+ virtual void traceConnection();
+
+ int verifyCallback(int , SSL*, X509_STORE_CTX*);
+# ifndef OPENSSL_NO_DH
+ DH* dhParams(int);
+# endif
+ ContextRef context() const;
+ void context(ContextRef);
+ std::string sslErrors() const;
+
+private:
+
+ SSL_METHOD* getMethod(int);
+ void setOptions(int);
+ enum Protocols { SSLv3 = 0x01, TLSv1_0 = 0x02, TLSv1_1 = 0x04, TLSv1_2 = 0x08 };
+ int parseProtocols(const Ice::StringSeq&) const;
+
+
+ bool _initOpenSSL;
+ bool _initialized;
+ ContextRef _ctx;
+ std::string _defaultDir;
+
+# ifndef OPENSSL_NO_DH
+ DHParamsPtr _dhParams;
+# endif
+ IceUtil::Mutex _mutex;
+};
+#endif
+
+}
+
+#endif
diff --git a/cpp/src/IceSSL/SSLEngineF.h b/cpp/src/IceSSL/SSLEngineF.h
new file mode 100644
index 00000000000..c064c2f4250
--- /dev/null
+++ b/cpp/src/IceSSL/SSLEngineF.h
@@ -0,0 +1,37 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#ifndef ICE_SSL_ENGINE_F_H
+#define ICE_SSL_ENGINE_F_H
+
+#include <IceUtil/Shared.h>
+#include <Ice/Handle.h>
+
+#include <IceSSL/Plugin.h>
+
+namespace IceSSL
+{
+
+class SSLEngine;
+ICE_SSL_API IceUtil::Shared* upCast(IceSSL::SSLEngine*);
+typedef IceInternal::Handle<SSLEngine> SSLEnginePtr;
+
+# ifdef ICE_USE_SECURE_TRANSPORT
+class SecureTransportEngine;
+ICE_SSL_API IceUtil::Shared* upCast(IceSSL::SecureTransportEngine*);
+typedef IceInternal::Handle<SecureTransportEngine> SecureTransportEnginePtr;
+# else
+class OpenSSLEngine;
+ICE_SSL_API IceUtil::Shared* upCast(IceSSL::OpenSSLEngine*);
+typedef IceInternal::Handle<OpenSSLEngine> OpenSSLEnginePtr;
+# endif
+
+}
+
+#endif
diff --git a/cpp/src/IceSSL/SecureTransportEngine.cpp b/cpp/src/IceSSL/SecureTransportEngine.cpp
new file mode 100644
index 00000000000..5bf401947bd
--- /dev/null
+++ b/cpp/src/IceSSL/SecureTransportEngine.cpp
@@ -0,0 +1,1515 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#include <IceSSL/Config.h>
+
+#include <IceUtil/FileUtil.h>
+#include <IceUtil/StringUtil.h>
+
+#include <Ice/LocalException.h>
+#include <Ice/Properties.h>
+#include <Ice/Communicator.h>
+#include <Ice/Logger.h>
+#include <Ice/LoggerUtil.h>
+
+#include <IceSSL/SecureTransportTransceiverI.h>
+#include <IceSSL/Plugin.h>
+#include <IceSSL/SSLEngine.h>
+#include <IceSSL/Util.h>
+
+#ifdef ICE_USE_SECURE_TRANSPORT
+
+#include <regex.h>
+#include <dirent.h>
+
+using namespace std;
+using namespace IceUtil;
+using namespace Ice;
+using namespace IceSSL;
+
+namespace
+{
+
+vector<string>
+dir(const string& path)
+{
+ vector<string> result;
+
+ DIR* d = opendir(path.c_str());
+ if(!d)
+ {
+ ostringstream os;
+ os << "failed to open dir `" << path << "'";
+ throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, os.str());
+ }
+
+ struct dirent* dp = 0;
+ while((dp = readdir(d)))
+ {
+ string name(dp->d_name);
+ if(IceUtilInternal::fileExists(path + "/" + name))
+ {
+ result.push_back(name);
+ }
+ }
+ closedir(d);
+ return result;
+}
+
+class RegExp : public IceUtil::Shared
+{
+public:
+
+ RegExp(const std::string&);
+ ~RegExp();
+ bool match(const std::string&);
+
+private:
+
+ regex_t _preg;
+};
+typedef IceUtil::Handle<RegExp> RegExpPtr;
+
+RegExp::RegExp(const std::string& regexp)
+{
+ int err = regcomp(&_preg, regexp.c_str(), REG_EXTENDED | REG_NOSUB);
+ if(err != 0)
+ {
+ ostringstream os;
+ os << "failed to compiler regular expression `" << regexp << "' (error = " << err << ")";
+ throw IllegalArgumentException(__FILE__, __LINE__, os.str());
+ }
+}
+
+RegExp::~RegExp()
+{
+ regfree(&_preg);
+}
+
+bool
+RegExp::match(const std::string& value)
+{
+ return regexec(&_preg, value.c_str(), 0, 0, 0) == 0;
+}
+
+struct CipherExpression
+{
+ bool negation;
+ string cipher;
+ RegExpPtr re;
+};
+
+class CiphersHelper
+{
+public:
+
+ static void initialize();
+ static SSLCipherSuite cipherForName(const string& name);
+ static string cipherName(SSLCipherSuite cipher);
+
+private:
+
+ static map<string, SSLCipherSuite> _ciphers;
+};
+
+map<string, SSLCipherSuite> CiphersHelper::_ciphers;
+
+//
+// Initialize a dictionary with the names of ciphers
+//
+void
+CiphersHelper::initialize()
+{
+ _ciphers["NULL_WITH_NULL_NULL"] = SSL_NULL_WITH_NULL_NULL;
+ _ciphers["RSA_WITH_NULL_MD5"] = SSL_RSA_WITH_NULL_MD5;
+ _ciphers["RSA_WITH_NULL_SHA"] = SSL_RSA_WITH_NULL_SHA;
+ _ciphers["RSA_EXPORT_WITH_RC4_40_MD5"] = SSL_RSA_EXPORT_WITH_RC4_40_MD5;
+ _ciphers["RSA_WITH_RC4_128_MD5"] = SSL_RSA_WITH_RC4_128_MD5;
+ _ciphers["RSA_WITH_RC4_128_SHA"] = SSL_RSA_WITH_RC4_128_SHA;
+ _ciphers["RSA_EXPORT_WITH_RC2_CBC_40_MD5"] = SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5;
+ _ciphers["RSA_WITH_IDEA_CBC_SHA"] = SSL_RSA_WITH_IDEA_CBC_SHA;
+ _ciphers["RSA_EXPORT_WITH_DES40_CBC_SHA"] = SSL_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ _ciphers["RSA_WITH_DES_CBC_SHA"] = SSL_RSA_WITH_DES_CBC_SHA;
+ _ciphers["RSA_WITH_3DES_EDE_CBC_SHA"] = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DH_DSS_EXPORT_WITH_DES40_CBC_SHA"] = SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ _ciphers["DH_DSS_WITH_DES_CBC_SHA"] = SSL_DH_DSS_WITH_DES_CBC_SHA;
+ _ciphers["DH_DSS_WITH_3DES_EDE_CBC_SHA"] = SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DH_RSA_EXPORT_WITH_DES40_CBC_SHA"] = SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ _ciphers["DH_RSA_WITH_DES_CBC_SHA"] = SSL_DH_RSA_WITH_DES_CBC_SHA;
+ _ciphers["DH_RSA_WITH_3DES_EDE_CBC_SHA"] = SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"] = SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ _ciphers["DHE_DSS_WITH_DES_CBC_SHA"] = SSL_DHE_DSS_WITH_DES_CBC_SHA;
+ _ciphers["DHE_DSS_WITH_3DES_EDE_CBC_SHA"] = SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"] = SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ _ciphers["DHE_RSA_WITH_DES_CBC_SHA"] = SSL_DHE_RSA_WITH_DES_CBC_SHA;
+ _ciphers["DHE_RSA_WITH_3DES_EDE_CBC_SHA"] = SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DH_anon_EXPORT_WITH_RC4_40_MD5"] = SSL_DH_anon_EXPORT_WITH_RC4_40_MD5;
+ _ciphers["DH_anon_WITH_RC4_128_MD5"] = SSL_DH_anon_WITH_RC4_128_MD5;
+ _ciphers["DH_anon_EXPORT_WITH_DES40_CBC_SHA"] = SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA;
+ _ciphers["DH_anon_WITH_DES_CBC_SHA"] = SSL_DH_anon_WITH_DES_CBC_SHA;
+ _ciphers["DH_anon_WITH_3DES_EDE_CBC_SHA"] = SSL_DH_anon_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["FORTEZZA_DMS_WITH_NULL_SHA"] = SSL_FORTEZZA_DMS_WITH_NULL_SHA;
+ _ciphers["FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"] = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA;
+
+ //
+ // TLS addenda using AES, per RFC 3268
+ //
+ _ciphers["RSA_WITH_AES_128_CBC_SHA"] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ _ciphers["DH_DSS_WITH_AES_128_CBC_SHA"] = TLS_DH_DSS_WITH_AES_128_CBC_SHA;
+ _ciphers["DH_RSA_WITH_AES_128_CBC_SHA"] = TLS_DH_RSA_WITH_AES_128_CBC_SHA;
+ _ciphers["DHE_DSS_WITH_AES_128_CBC_SHA"] = TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
+ _ciphers["DHE_RSA_WITH_AES_128_CBC_SHA"] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+ _ciphers["DH_anon_WITH_AES_128_CBC_SHA"] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+ _ciphers["RSA_WITH_AES_256_CBC_SHA"] = TLS_RSA_WITH_AES_256_CBC_SHA;
+ _ciphers["DH_DSS_WITH_AES_256_CBC_SHA"] = TLS_DH_DSS_WITH_AES_256_CBC_SHA;
+ _ciphers["DH_RSA_WITH_AES_256_CBC_SHA"] = TLS_DH_RSA_WITH_AES_256_CBC_SHA;
+ _ciphers["DHE_DSS_WITH_AES_256_CBC_SHA"] = TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+ _ciphers["DHE_RSA_WITH_AES_256_CBC_SHA"] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+ _ciphers["DH_anon_WITH_AES_256_CBC_SHA"] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+
+ //
+ // ECDSA addenda, RFC 4492
+ //
+ _ciphers["ECDH_ECDSA_WITH_NULL_SHA"] = TLS_ECDH_ECDSA_WITH_NULL_SHA;
+ _ciphers["ECDH_ECDSA_WITH_RC4_128_SHA"] = TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+ _ciphers["ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"] = TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["ECDH_ECDSA_WITH_AES_128_CBC_SHA"] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+ _ciphers["ECDH_ECDSA_WITH_AES_256_CBC_SHA"] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+ _ciphers["ECDHE_ECDSA_WITH_NULL_SHA"] = TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+ _ciphers["ECDHE_ECDSA_WITH_RC4_128_SHA"] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+ _ciphers["ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["ECDHE_ECDSA_WITH_AES_128_CBC_SHA"] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+ _ciphers["ECDHE_ECDSA_WITH_AES_256_CBC_SHA"] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+ _ciphers["ECDH_RSA_WITH_NULL_SHA"] = TLS_ECDH_RSA_WITH_NULL_SHA;
+ _ciphers["ECDH_RSA_WITH_RC4_128_SHA"] = TLS_ECDH_RSA_WITH_RC4_128_SHA;
+ _ciphers["ECDH_RSA_WITH_3DES_EDE_CBC_SHA"] = TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["ECDH_RSA_WITH_AES_128_CBC_SHA"] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+ _ciphers["ECDH_RSA_WITH_AES_256_CBC_SHA"] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+ _ciphers["ECDHE_RSA_WITH_NULL_SHA"] = TLS_ECDHE_RSA_WITH_NULL_SHA;
+ _ciphers["ECDHE_RSA_WITH_RC4_128_SHA"] = TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+ _ciphers["ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["ECDHE_RSA_WITH_AES_128_CBC_SHA"] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+ _ciphers["ECDHE_RSA_WITH_AES_256_CBC_SHA"] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+ _ciphers["ECDH_anon_WITH_NULL_SHA"] = TLS_ECDH_anon_WITH_NULL_SHA;
+ _ciphers["ECDH_anon_WITH_RC4_128_SHA"] = TLS_ECDH_anon_WITH_RC4_128_SHA;
+ _ciphers["ECDH_anon_WITH_3DES_EDE_CBC_SHA"] = TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["ECDH_anon_WITH_AES_128_CBC_SHA"] = TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+ _ciphers["ECDH_anon_WITH_AES_256_CBC_SHA"] = TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+
+ //
+ // TLS 1.2 addenda, RFC 5246
+ //
+ //_ciphers["NULL_WITH_NULL_NULL"] = TLS_NULL_WITH_NULL_NULL;
+
+ //
+ // Server provided RSA certificate for key exchange.
+ //
+ //_ciphers["RSA_WITH_NULL_MD5"] = TLS_RSA_WITH_NULL_MD5;
+ //_ciphers["RSA_WITH_NULL_SHA"] = TLS_RSA_WITH_NULL_SHA;
+ //_ciphers["RSA_WITH_RC4_128_MD5"] = TLS_RSA_WITH_RC4_128_MD5;
+ //_ciphers["RSA_WITH_RC4_128_SHA"] = TLS_RSA_WITH_RC4_128_SHA;
+ //_ciphers["RSA_WITH_3DES_EDE_CBC_SHA"] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["RSA_WITH_NULL_SHA256"] = TLS_RSA_WITH_NULL_SHA256;
+ _ciphers["RSA_WITH_AES_128_CBC_SHA256"] = TLS_RSA_WITH_AES_128_CBC_SHA256;
+ _ciphers["RSA_WITH_AES_256_CBC_SHA256"] = TLS_RSA_WITH_AES_256_CBC_SHA256;
+
+ //
+ // Server-authenticated (and optionally client-authenticated) Diffie-Hellman.
+ //
+ //_ciphers["DH_DSS_WITH_3DES_EDE_CBC_SHA"] = TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA;
+ //_ciphers["DH_RSA_WITH_3DES_EDE_CBC_SHA"] = TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA;
+ //_ciphers["DHE_DSS_WITH_3DES_EDE_CBC_SHA"] = TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+ //_ciphers["DHE_RSA_WITH_3DES_EDE_CBC_SHA"] = TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DH_DSS_WITH_AES_128_CBC_SHA256"] = TLS_DH_DSS_WITH_AES_128_CBC_SHA256;
+ _ciphers["DH_RSA_WITH_AES_128_CBC_SHA256"] = TLS_DH_RSA_WITH_AES_128_CBC_SHA256;
+ _ciphers["DHE_DSS_WITH_AES_128_CBC_SHA256"] = TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
+ _ciphers["DHE_RSA_WITH_AES_128_CBC_SHA256"] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+ _ciphers["DH_DSS_WITH_AES_256_CBC_SHA256"] = TLS_DH_DSS_WITH_AES_256_CBC_SHA256;
+ _ciphers["DH_RSA_WITH_AES_256_CBC_SHA256"] = TLS_DH_RSA_WITH_AES_256_CBC_SHA256;
+ _ciphers["DHE_DSS_WITH_AES_256_CBC_SHA256"] = TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
+ _ciphers["DHE_RSA_WITH_AES_256_CBC_SHA256"] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+
+ //
+ // Completely anonymous Diffie-Hellman
+ //
+ //_ciphers["DH_anon_WITH_RC4_128_MD5"] = TLS_DH_anon_WITH_RC4_128_MD5;
+ //_ciphers["DH_anon_WITH_3DES_EDE_CBC_SHA"] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DH_anon_WITH_AES_128_CBC_SHA256"] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
+ _ciphers["DH_anon_WITH_AES_256_CBC_SHA256"] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+
+ //
+ // Addendum from RFC 4279, TLS PSK
+ //
+ _ciphers["PSK_WITH_RC4_128_SHA"] = TLS_PSK_WITH_RC4_128_SHA;
+ _ciphers["PSK_WITH_3DES_EDE_CBC_SHA"] = TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["PSK_WITH_AES_128_CBC_SHA"] = TLS_PSK_WITH_AES_128_CBC_SHA;
+ _ciphers["PSK_WITH_AES_256_CBC_SHA"] = TLS_PSK_WITH_AES_256_CBC_SHA;
+ _ciphers["DHE_PSK_WITH_RC4_128_SHA"] = TLS_DHE_PSK_WITH_RC4_128_SHA;
+ _ciphers["DHE_PSK_WITH_3DES_EDE_CBC_SHA"] = TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["DHE_PSK_WITH_AES_128_CBC_SHA"] = TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+ _ciphers["DHE_PSK_WITH_AES_256_CBC_SHA"] = TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+ _ciphers["RSA_PSK_WITH_RC4_128_SHA"] = TLS_RSA_PSK_WITH_RC4_128_SHA;
+ _ciphers["RSA_PSK_WITH_3DES_EDE_CBC_SHA"] = TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+ _ciphers["RSA_PSK_WITH_AES_128_CBC_SHA"] = TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+ _ciphers["RSA_PSK_WITH_AES_256_CBC_SHA"] = TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+
+ //
+ // RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption
+ //
+ _ciphers["PSK_WITH_NULL_SHA"] = TLS_PSK_WITH_NULL_SHA;
+ _ciphers["DHE_PSK_WITH_NULL_SHA"] = TLS_DHE_PSK_WITH_NULL_SHA;
+ _ciphers["RSA_PSK_WITH_NULL_SHA"] = TLS_RSA_PSK_WITH_NULL_SHA;
+
+ //
+ // Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites for TLS.
+ //
+ _ciphers["RSA_WITH_AES_128_GCM_SHA256"] = TLS_RSA_WITH_AES_128_GCM_SHA256;
+ _ciphers["RSA_WITH_AES_256_GCM_SHA384"] = TLS_RSA_WITH_AES_256_GCM_SHA384;
+ _ciphers["DHE_RSA_WITH_AES_128_GCM_SHA256"] = TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
+ _ciphers["DHE_RSA_WITH_AES_256_GCM_SHA384"] = TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
+ _ciphers["DH_RSA_WITH_AES_128_GCM_SHA256"] = TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
+ _ciphers["DH_RSA_WITH_AES_256_GCM_SHA384"] = TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
+ _ciphers["DHE_DSS_WITH_AES_128_GCM_SHA256"] = TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
+ _ciphers["DHE_DSS_WITH_AES_256_GCM_SHA384"] = TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
+ _ciphers["DH_DSS_WITH_AES_128_GCM_SHA256"] = TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
+ _ciphers["DH_DSS_WITH_AES_256_GCM_SHA384"] = TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
+ _ciphers["DH_anon_WITH_AES_128_GCM_SHA256"] = TLS_DH_anon_WITH_AES_128_GCM_SHA256;
+ _ciphers["DH_anon_WITH_AES_256_GCM_SHA384"] = TLS_DH_anon_WITH_AES_256_GCM_SHA384;
+
+ //
+ // RFC 5487 - PSK with SHA-256/384 and AES GCM
+ //
+ _ciphers["PSK_WITH_AES_128_GCM_SHA256"] = TLS_PSK_WITH_AES_128_GCM_SHA256;
+ _ciphers["PSK_WITH_AES_256_GCM_SHA384"] = TLS_PSK_WITH_AES_256_GCM_SHA384;
+ _ciphers["DHE_PSK_WITH_AES_128_GCM_SHA256"] = TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
+ _ciphers["DHE_PSK_WITH_AES_256_GCM_SHA384"] = TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
+ _ciphers["RSA_PSK_WITH_AES_128_GCM_SHA256"] = TLS_RSA_PSK_WITH_AES_128_GCM_SHA256;
+ _ciphers["RSA_PSK_WITH_AES_256_GCM_SHA384"] = TLS_RSA_PSK_WITH_AES_256_GCM_SHA384;
+
+ _ciphers["PSK_WITH_AES_128_CBC_SHA256"] = TLS_PSK_WITH_AES_128_CBC_SHA256;
+ _ciphers["PSK_WITH_AES_256_CBC_SHA384"] = TLS_PSK_WITH_AES_256_CBC_SHA384;
+ _ciphers["PSK_WITH_NULL_SHA256"] = TLS_PSK_WITH_NULL_SHA256;
+ _ciphers["PSK_WITH_NULL_SHA384"] = TLS_PSK_WITH_NULL_SHA384;
+
+ _ciphers["DHE_PSK_WITH_AES_128_CBC_SHA256"] = TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+ _ciphers["DHE_PSK_WITH_AES_256_CBC_SHA384"] = TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+ _ciphers["DHE_PSK_WITH_NULL_SHA256"] = TLS_DHE_PSK_WITH_NULL_SHA256;
+ _ciphers["DHE_PSK_WITH_NULL_SHA384"] = TLS_DHE_PSK_WITH_NULL_SHA384;
+
+ _ciphers["RSA_PSK_WITH_AES_128_CBC_SHA256"] = TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
+ _ciphers["RSA_PSK_WITH_AES_256_CBC_SHA384"] = TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
+ _ciphers["RSA_PSK_WITH_NULL_SHA256"] = TLS_RSA_PSK_WITH_NULL_SHA256;
+ _ciphers["RSA_PSK_WITH_NULL_SHA384"] = TLS_RSA_PSK_WITH_NULL_SHA384;
+
+ //
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384.
+ //
+ _ciphers["ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+ _ciphers["ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+ _ciphers["ECDH_ECDSA_WITH_AES_128_CBC_SHA256"] = TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+ _ciphers["ECDH_ECDSA_WITH_AES_256_CBC_SHA384"] = TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+ _ciphers["ECDHE_RSA_WITH_AES_128_CBC_SHA256"] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+ _ciphers["ECDHE_RSA_WITH_AES_256_CBC_SHA384"] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+ _ciphers["ECDH_RSA_WITH_AES_128_CBC_SHA256"] = TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+ _ciphers["ECDH_RSA_WITH_AES_256_CBC_SHA384"] = TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
+
+ //
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM)
+ //
+ _ciphers["ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"] = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
+ _ciphers["ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"] = TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+ _ciphers["ECDH_ECDSA_WITH_AES_128_GCM_SHA256"] = TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
+ _ciphers["ECDH_ECDSA_WITH_AES_256_GCM_SHA384"] = TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
+ _ciphers["ECDHE_RSA_WITH_AES_128_GCM_SHA256"] = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+ _ciphers["ECDHE_RSA_WITH_AES_256_GCM_SHA384"] = TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+ _ciphers["ECDH_RSA_WITH_AES_128_GCM_SHA256"] = TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
+ _ciphers["ECDH_RSA_WITH_AES_256_GCM_SHA384"] = TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
+
+ //
+ // RFC 5746 - Secure Renegotiation
+ //
+ _ciphers["EMPTY_RENEGOTIATION_INFO_SCSV"] = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
+
+ //
+ // Tags for SSL 2 cipher kinds that are not specified for SSL 3.
+ //
+ _ciphers["RSA_WITH_RC2_CBC_MD5"] = SSL_RSA_WITH_RC2_CBC_MD5;
+ _ciphers["RSA_WITH_IDEA_CBC_MD5"] = SSL_RSA_WITH_IDEA_CBC_MD5;
+ _ciphers["RSA_WITH_DES_CBC_MD5"] = SSL_RSA_WITH_DES_CBC_MD5;
+ _ciphers["RSA_WITH_3DES_EDE_CBC_MD5"] = SSL_RSA_WITH_3DES_EDE_CBC_MD5;
+ _ciphers["NO_SUCH_CIPHERSUITE"] = SSL_NO_SUCH_CIPHERSUITE;
+}
+
+SSLCipherSuite
+CiphersHelper::cipherForName(const string& name)
+{
+ map<string, SSLCipherSuite>::const_iterator i = _ciphers.find(name);
+ if(i == _ciphers.end() || i->second == SSL_NO_SUCH_CIPHERSUITE)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__, "IceSSL: no such cipher " + name);
+ throw ex;
+ }
+ return i->second;
+}
+
+//
+// Retrive the name of a cipher, SSLCipherSuite inlude duplicated values for TLS/SSL
+// protocol ciphers, for example SSL_RSA_WITH_RC4_128_MD5/TLS_RSA_WITH_RC4_128_MD5
+// are represeted by the same SSLCipherSuite value, the names return by this method
+// doesn't include a protocol prefix.
+//
+string
+CiphersHelper::cipherName(SSLCipherSuite cipher)
+{
+ switch(cipher)
+ {
+ case SSL_NULL_WITH_NULL_NULL:
+ return "NULL_WITH_NULL_NULL";
+ case SSL_RSA_WITH_NULL_MD5:
+ return "RSA_WITH_NULL_MD5";
+ case SSL_RSA_WITH_NULL_SHA:
+ return "RSA_WITH_NULL_SHA";
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ return "RSA_EXPORT_WITH_RC4_40_MD5";
+ case SSL_RSA_WITH_RC4_128_MD5:
+ return "RSA_WITH_RC4_128_MD5";
+ case SSL_RSA_WITH_RC4_128_SHA:
+ return "RSA_WITH_RC4_128_SHA";
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ return "RSA_EXPORT_WITH_RC2_CBC_40_MD5";
+ case SSL_RSA_WITH_IDEA_CBC_SHA:
+ return "RSA_WITH_IDEA_CBC_SHA";
+ case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "RSA_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_RSA_WITH_DES_CBC_SHA:
+ return "RSA_WITH_DES_CBC_SHA";
+ case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "RSA_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ return "DH_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DH_DSS_WITH_DES_CBC_SHA:
+ return "DH_DSS_WITH_DES_CBC_SHA";
+ case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "DH_DSS_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "DH_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DH_RSA_WITH_DES_CBC_SHA:
+ return "DH_RSA_WITH_DES_CBC_SHA";
+ case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "DH_RSA_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ return "DHE_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DHE_DSS_WITH_DES_CBC_SHA:
+ return "DHE_DSS_WITH_DES_CBC_SHA";
+ case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "DHE_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DHE_RSA_WITH_DES_CBC_SHA:
+ return "DHE_RSA_WITH_DES_CBC_SHA";
+ case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
+ return "DH_anon_EXPORT_WITH_RC4_40_MD5";
+ case SSL_DH_anon_WITH_RC4_128_MD5:
+ return "DH_anon_WITH_RC4_128_MD5";
+ case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
+ return "DH_anon_EXPORT_WITH_DES40_CBC_SHA";
+ case SSL_DH_anon_WITH_DES_CBC_SHA:
+ return "DH_anon_WITH_DES_CBC_SHA";
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "DH_anon_WITH_3DES_EDE_CBC_SHA";
+ case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
+ return "FORTEZZA_DMS_WITH_NULL_SHA";
+ case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:
+ return "FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA";
+
+ //
+ // TLS addenda using AES, per RFC 3268
+ //
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ return "RSA_WITH_AES_128_CBC_SHA";
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ return "DH_DSS_WITH_AES_128_CBC_SHA";
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ return "DH_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ return "DHE_DSS_WITH_AES_128_CBC_SHA";
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ return "DHE_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ return "DH_anon_WITH_AES_128_CBC_SHA";
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ return "RSA_WITH_AES_256_CBC_SHA";
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ return "DH_DSS_WITH_AES_256_CBC_SHA";
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ return "DH_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ return "DHE_DSS_WITH_AES_256_CBC_SHA";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ return "DHE_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ return "DH_anon_WITH_AES_256_CBC_SHA";
+
+ //
+ // ECDSA addenda, RFC 4492
+ //
+ case TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ return "ECDH_ECDSA_WITH_NULL_SHA";
+ case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ return "ECDH_ECDSA_WITH_RC4_128_SHA";
+ case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ return "ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ return "ECDH_ECDSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ return "ECDH_ECDSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ return "ECDHE_ECDSA_WITH_NULL_SHA";
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ return "ECDHE_ECDSA_WITH_RC4_128_SHA";
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ return "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ return "ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDH_RSA_WITH_NULL_SHA:
+ return "ECDH_RSA_WITH_NULL_SHA";
+ case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ return "ECDH_RSA_WITH_RC4_128_SHA";
+ case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ return "ECDH_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ return "ECDH_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDHE_RSA_WITH_NULL_SHA:
+ return "ECDHE_RSA_WITH_NULL_SHA";
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ return "ECDHE_RSA_WITH_RC4_128_SHA";
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ return "ECDHE_RSA_WITH_AES_128_CBC_SHA";
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ return "ECDHE_RSA_WITH_AES_256_CBC_SHA";
+ case TLS_ECDH_anon_WITH_NULL_SHA:
+ return "ECDH_anon_WITH_NULL_SHA";
+ case TLS_ECDH_anon_WITH_RC4_128_SHA:
+ return "ECDH_anon_WITH_RC4_128_SHA";
+ case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "ECDH_anon_WITH_3DES_EDE_CBC_SHA";
+ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ return "ECDH_anon_WITH_AES_128_CBC_SHA";
+ case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ return "ECDH_anon_WITH_AES_256_CBC_SHA";
+
+ //
+ // TLS 1.2 addenda, RFC 5246
+ //
+ //case TLS_NULL_WITH_NULL_NULL:
+ // return "NULL_WITH_NULL_NULL";
+
+ //
+ // Server provided RSA certificate for key exchange.
+ //
+ //case TLS_RSA_WITH_NULL_MD5:
+ // return "RSA_WITH_NULL_MD5";
+ //case TLS_RSA_WITH_NULL_SHA:
+ // return "RSA_WITH_NULL_SHA";
+ //case TLS_RSA_WITH_RC4_128_MD5:
+ // return "RSA_WITH_RC4_128_MD5";
+ //case TLS_RSA_WITH_RC4_128_SHA:
+ // return "RSA_WITH_RC4_128_SHA";
+ //case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ // return "RSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_RSA_WITH_NULL_SHA256:
+ return "RSA_WITH_NULL_SHA256";
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ return "RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ return "RSA_WITH_AES_256_CBC_SHA256";
+
+ //
+ // Server-authenticated (and optionally client-authenticated) Diffie-Hellman.
+ //
+ //case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ // return "DH_DSS_WITH_3DES_EDE_CBC_SHA";
+ //case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ // return "DH_RSA_WITH_3DES_EDE_CBC_SHA";
+ //case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ // return "DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+ //case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ // return "DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ return "DH_DSS_WITH_AES_128_CBC_SHA256";
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ return "DH_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ return "DHE_DSS_WITH_AES_128_CBC_SHA256";
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ return "DHE_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ return "DH_DSS_WITH_AES_256_CBC_SHA256";
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ return "DH_RSA_WITH_AES_256_CBC_SHA256";
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ return "DHE_DSS_WITH_AES_256_CBC_SHA256";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ return "DHE_RSA_WITH_AES_256_CBC_SHA256";
+
+ //
+ // Completely anonymous Diffie-Hellman
+ //
+ //case TLS_DH_anon_WITH_RC4_128_MD5:
+ // return "DH_anon_WITH_RC4_128_MD5";
+ //case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ // return "DH_anon_WITH_3DES_EDE_CBC_SHA";
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ return "DH_anon_WITH_AES_128_CBC_SHA256";
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ return "DH_anon_WITH_AES_256_CBC_SHA256";
+
+ //
+ // Addendum from RFC 4279, TLS PSK
+ //
+ case TLS_PSK_WITH_RC4_128_SHA:
+ return "PSK_WITH_RC4_128_SHA";
+ case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ return "PSK_WITH_3DES_EDE_CBC_SHA";
+ case TLS_PSK_WITH_AES_128_CBC_SHA:
+ return "PSK_WITH_AES_128_CBC_SHA";
+ case TLS_PSK_WITH_AES_256_CBC_SHA:
+ return "PSK_WITH_AES_256_CBC_SHA";
+ case TLS_DHE_PSK_WITH_RC4_128_SHA:
+ return "DHE_PSK_WITH_RC4_128_SHA";
+ case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ return "DHE_PSK_WITH_3DES_EDE_CBC_SHA";
+ case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ return "DHE_PSK_WITH_AES_128_CBC_SHA";
+ case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ return "DHE_PSK_WITH_AES_256_CBC_SHA";
+ case TLS_RSA_PSK_WITH_RC4_128_SHA:
+ return "RSA_PSK_WITH_RC4_128_SHA";
+ case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ return "RSA_PSK_WITH_3DES_EDE_CBC_SHA";
+ case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ return "RSA_PSK_WITH_AES_128_CBC_SHA";
+ case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ return "RSA_PSK_WITH_AES_256_CBC_SHA";
+
+ //
+ // RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption
+ //
+ case TLS_PSK_WITH_NULL_SHA:
+ return "PSK_WITH_NULL_SHA";
+ case TLS_DHE_PSK_WITH_NULL_SHA:
+ return "DHE_PSK_WITH_NULL_SHA";
+ case TLS_RSA_PSK_WITH_NULL_SHA:
+ return "RSA_PSK_WITH_NULL_SHA";
+
+ //
+ // Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites for TLS.
+ //
+ case TLS_RSA_WITH_AES_128_GCM_SHA256:
+ return "RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_RSA_WITH_AES_256_GCM_SHA384:
+ return "RSA_WITH_AES_256_GCM_SHA384";
+ case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ return "DHE_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ return "DHE_RSA_WITH_AES_256_GCM_SHA384";
+ case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ return "DH_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ return "DH_RSA_WITH_AES_256_GCM_SHA384";
+ case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ return "DHE_DSS_WITH_AES_128_GCM_SHA256";
+ case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ return "DHE_DSS_WITH_AES_256_GCM_SHA384";
+ case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ return "DH_DSS_WITH_AES_128_GCM_SHA256";
+ case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ return "DH_DSS_WITH_AES_256_GCM_SHA384";
+ case TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ return "DH_anon_WITH_AES_128_GCM_SHA256";
+ case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ return "DH_anon_WITH_AES_256_GCM_SHA384";
+
+ //
+ // RFC 5487 - PSK with SHA-256/384 and AES GCM
+ //
+ case TLS_PSK_WITH_AES_128_GCM_SHA256:
+ return "PSK_WITH_AES_128_GCM_SHA256";
+ case TLS_PSK_WITH_AES_256_GCM_SHA384:
+ return "PSK_WITH_AES_256_GCM_SHA384";
+ case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ return "DHE_PSK_WITH_AES_128_GCM_SHA256";
+ case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ return "DHE_PSK_WITH_AES_256_GCM_SHA384";
+ case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ return "RSA_PSK_WITH_AES_128_GCM_SHA256";
+ case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ return "RSA_PSK_WITH_AES_256_GCM_SHA384";
+
+ case TLS_PSK_WITH_AES_128_CBC_SHA256:
+ return "PSK_WITH_AES_128_CBC_SHA256";
+ case TLS_PSK_WITH_AES_256_CBC_SHA384:
+ return "PSK_WITH_AES_256_CBC_SHA384";
+ case TLS_PSK_WITH_NULL_SHA256:
+ return "WITH_NULL_SHA256";
+ case TLS_PSK_WITH_NULL_SHA384:
+ return "PSK_WITH_NULL_SHA384";
+
+ case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ return "DHE_PSK_WITH_AES_128_CBC_SHA256";
+ case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ return "DHE_PSK_WITH_AES_256_CBC_SHA384";
+ case TLS_DHE_PSK_WITH_NULL_SHA256:
+ return "DHE_PSK_WITH_NULL_SHA256";
+ case TLS_DHE_PSK_WITH_NULL_SHA384:
+ return "DHE_PSK_WITH_NULL_SHA384";
+
+ case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ return "RSA_PSK_WITH_AES_128_CBC_SHA256";
+ case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ return "RSA_PSK_WITH_AES_256_CBC_SHA384";
+ case TLS_RSA_PSK_WITH_NULL_SHA256:
+ return "RSA_PSK_WITH_NULL_SHA256";
+ case TLS_RSA_PSK_WITH_NULL_SHA384:
+ return "RSA_PSK_WITH_NULL_SHA384";
+
+ //
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384.
+ //
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ return "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ return "ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ return "ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ return "ECDHE_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ return "ECDHE_RSA_WITH_AES_256_CBC_SHA384";
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ return "ECDH_RSA_WITH_AES_128_CBC_SHA256";
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ return "ECDH_RSA_WITH_AES_256_CBC_SHA384";
+
+ //
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM)
+ //
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ return "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ return "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
+ case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ return "ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ return "ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ return "ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ return "ECDHE_RSA_WITH_AES_256_GCM_SHA384";
+ case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ return "ECDH_RSA_WITH_AES_128_GCM_SHA256";
+ case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ return "ECDH_RSA_WITH_AES_256_GCM_SHA384";
+
+ //
+ // RFC 5746 - Secure Renegotiation
+ //
+ case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
+ return "EMPTY_RENEGOTIATION_INFO_SCSV";
+
+ //
+ // Tags for SSL 2 cipher kinds that are not specified for SSL 3.
+ //
+ case SSL_RSA_WITH_RC2_CBC_MD5:
+ return "RSA_WITH_RC2_CBC_MD5";
+ case SSL_RSA_WITH_IDEA_CBC_MD5:
+ return "RSA_WITH_IDEA_CBC_MD5";
+ case SSL_RSA_WITH_DES_CBC_MD5:
+ return "RSA_WITH_DES_CBC_MD5";
+ case SSL_RSA_WITH_3DES_EDE_CBC_MD5:
+ return "RSA_WITH_3DES_EDE_CBC_MD5";
+ default:
+ return "";
+ }
+}
+
+SSLProtocol
+parseProtocol(const std::string& prot)
+{
+ if(prot == "ssl2" || prot == "sslv2")
+ {
+ return kSSLProtocol2;
+ }
+ else if(prot == "ssl3" || prot == "sslv3")
+ {
+ return kSSLProtocol3;
+ }
+ else if(prot == "tls" || prot == "tls1" || prot == "tlsv1" || prot == "tls1_0" || prot == "tlsv1_0")
+ {
+ return kTLSProtocol1;
+ }
+ else if(prot == "tls1_1" || prot == "tlsv1_1")
+ {
+ return kTLSProtocol11;
+ }
+ else if(prot == "tls1_2" || prot == "tlsv1_2")
+ {
+ return kTLSProtocol12;
+ }
+ else
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: unrecognized protocol `" + prot + "'";
+ throw ex;
+ }
+}
+
+}
+
+IceUtil::Shared* IceSSL::upCast(IceSSL::SecureTransportEngine* p) { return p; }
+
+IceSSL::SecureTransportEngine::SecureTransportEngine(const Ice::CommunicatorPtr& communicator) :
+ SSLEngine(communicator),
+ _initialized(false),
+ _ctx(0),
+ _certificateAuthorities(0),
+ _cert(0),
+ _key(0),
+ _identity(0),
+ _keychain(0),
+ _protocolVersionMax(kSSLProtocolUnknown),
+ _protocolVersionMin(kSSLProtocolUnknown),
+ _dhParams(0),
+ _dhParamsLength(0),
+ _ciphers(new ScopedArray<SSLCipherSuite>()),
+ _allCiphers(false),
+ _numCiphers(-1)
+{
+}
+
+bool
+IceSSL::SecureTransportEngine::initialized() const
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+ return _initialized;
+}
+//
+// Setup the engine.
+//
+void
+IceSSL::SecureTransportEngine::initialize()
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+ if(_initialized)
+ {
+ return;
+ }
+
+ SSLEngine::initialize();
+
+ const string propPrefix = "IceSSL.";
+ const PropertiesPtr properties = communicator()->getProperties();
+
+ //
+ // Check for a default directory. We look in this directory for
+ // files mentioned in the configuration.
+ //
+ string defaultDir = properties->getProperty(propPrefix + "DefaultDir");
+
+ //
+ // Open the application KeyChain or create it if the keychain doesn't exists
+ //
+ string keychainPath = properties->getProperty("IceSSL.Keychain");
+ string keychainPassword = properties->getProperty("IceSSL.KeychainPassword");
+
+ //
+ // KeyChain path is relative to the current working directory.
+ //
+ if(keychainPath.empty())
+ {
+ keychainPath = "login.keychain";
+ }
+ else
+ {
+ if(!IceUtilInternal::isAbsolutePath(keychainPath))
+ {
+ string cwd;
+ if(IceUtilInternal::getcwd(cwd) == 0)
+ {
+ keychainPath = string(cwd) + '/' + keychainPath;
+ }
+ }
+ }
+
+ bool usePassword = !keychainPassword.empty();
+ size_t size = keychainPassword.size();
+ const char* password = usePassword ? keychainPassword.c_str() : 0;
+
+ OSStatus err = SecKeychainOpen(keychainPath.c_str(), &_keychain);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to open keychain: `" << keychainPath << "'\n" << errorToString(err);
+ throw PluginInitializationException(__FILE__, __LINE__, os.str());
+ }
+
+ SecKeychainStatus status;
+ err = SecKeychainGetStatus(_keychain, &status);
+
+ if(err == noErr)
+ {
+ err = SecKeychainUnlock(_keychain, size, password, usePassword);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to unlock keychain: `" << keychainPath << "'\n" << errorToString(err);
+ throw PluginInitializationException(__FILE__, __LINE__, os.str());
+ }
+ }
+ else if(err == errSecNoSuchKeychain)
+ {
+ err = SecKeychainCreate(keychainPath.c_str(), size, password, keychainPassword.empty(), 0, &_keychain);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to create keychain: `" << keychainPath << "'\n" << errorToString(err);
+ throw PluginInitializationException(__FILE__, __LINE__, os.str());
+ }
+ }
+ else
+ {
+ ostringstream os;
+ os << "IceSSL: unable to open keychain: `" << keychainPath << "'\n" << errorToString(err);
+ throw PluginInitializationException(__FILE__, __LINE__, os.str());
+ }
+
+ int passwordRetryMax = properties->getPropertyAsIntWithDefault(propPrefix + "PasswordRetryMax", 3);
+ PasswordPromptPtr passwordPrompt = getPasswordPrompt();
+ //
+ // Load the CA certificates used to authenticate peers into
+ // _certificateAuthorities array.
+ //
+ {
+ try
+ {
+ string caFile = properties->getProperty(propPrefix + "CertAuthFile");
+ if(!caFile.empty())
+ {
+ if(!checkPath(caFile, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: CA certificate file not found:\n" + caFile;
+ throw ex;
+ }
+ _certificateAuthorities = loadCACertificates(caFile);
+ }
+ }
+ catch(const CertificateReadException& ce)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__, ce.reason);
+ throw ex;
+ }
+
+ string caDir = properties->getPropertyWithDefault(propPrefix + "CertAuthDir", defaultDir);
+ if(!caDir.empty())
+ {
+ CFMutableArrayRef certificateAuthorities;
+ if(_certificateAuthorities)
+ {
+ certificateAuthorities = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, _certificateAuthorities);
+ CFRelease(_certificateAuthorities);
+ }
+ else
+ {
+ certificateAuthorities = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ }
+
+ vector<string> files = dir(caDir);
+ for(vector<string>::const_iterator i = files.begin(); i != files.end(); ++i)
+ {
+ try
+ {
+ CFArrayRef tmp = loadCACertificates(caDir + "/" + *i);
+
+ CFArrayAppendArray(certificateAuthorities, tmp, CFRangeMake(0, CFArrayGetCount(tmp)));
+ CFRelease(tmp);
+ }
+ catch(const CertificateReadException&)
+ {
+ //
+ // Some files in CertAuthDir might not be certificates, we just ignore those files.
+ //
+ }
+ }
+ _certificateAuthorities = certificateAuthorities;
+ }
+ }
+
+ //
+ // Import the application certificate and private keys into the application
+ // keychain.
+ //
+ {
+ string certFile = properties->getProperty(propPrefix + "CertFile");
+ string keyFile = properties->getProperty(propPrefix + "KeyFile");
+ vector<string>::size_type numCerts = 0;
+
+ CFDataRef hash = 0;
+
+ if(!certFile.empty())
+ {
+ try
+ {
+ vector<string> files;
+ if(!IceUtilInternal::splitString(certFile, IceUtilInternal::pathsep, files) || files.size() > 2)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: invalid value for " + propPrefix + "CertFile:\n" + certFile;
+ throw ex;
+ }
+ numCerts = files.size();
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ {
+ string file = *p;
+ if(!checkPath(file, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: certificate file not found:\n" + file;
+ throw ex;
+ }
+
+ loadCertificate(&_cert, &hash, keyFile.empty() ? &_key : 0, _keychain, file,
+ properties->getProperty(propPrefix + "Password"), passwordPrompt,
+ passwordRetryMax);
+ break;
+ }
+ }
+ catch(const CertificateReadException& ce)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__, ce.reason);
+ throw ex;
+ }
+ }
+
+ if(!keyFile.empty())
+ {
+ try
+ {
+ vector<string> files;
+ if(!IceUtilInternal::splitString(keyFile, IceUtilInternal::pathsep, files) || files.size() > 2)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: invalid value for " + propPrefix + "KeyFile:\n" + keyFile;
+ throw ex;
+ }
+ if(files.size() != numCerts)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: " + propPrefix + "KeyFile does not agree with " + propPrefix + "CertFile";
+ throw ex;
+ }
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ {
+ string file = *p;
+ if(!checkPath(file, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: key file not found:\n" + file;
+ throw ex;
+ }
+ //
+ // The private key may be stored in an encrypted file, so handle
+ // password retries.
+ //
+ loadPrivateKey(&_key, keyLabel(_cert), hash, _keychain, file,
+ properties->getProperty(propPrefix + "Password"),
+ passwordPrompt, passwordRetryMax);
+ break;
+ }
+ }
+ catch(const CertificateReadException& ce)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__, ce.reason);
+ throw ex;
+ }
+ }
+
+ if(_cert)
+ {
+ err = SecIdentityCreateWithCertificate(_keychain, _cert, &_identity);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to create the certificate identity:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+
+ if(hash)
+ {
+ CFRelease(hash);
+ }
+ }
+
+ //
+ // DiffieHellmanParams in DER format.
+ //
+ {
+ string dhParams = properties->getProperty(propPrefix + "DHParams");
+ if(!dhParams.empty())
+ {
+ if(!checkPath(dhParams, defaultDir, false))
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceSSL: DH params file not found:\n" + dhParams;
+ throw ex;
+ }
+
+ ScopedArray<char> buffer;
+ _dhParamsLength = readFile(dhParams, buffer);
+ _dhParams.reset(new ScopedArray<char>(buffer));
+ }
+ }
+
+ //
+ // Establish the cipher list.
+ //
+ string ciphers = properties->getProperty(propPrefix + "Ciphers");
+ if(!ciphers.empty())
+ {
+ //
+ // Context used to get the cipher list
+ //
+ _ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
+ CiphersHelper::initialize();
+ parseCiphers(ciphers);
+ }
+
+ //
+ // Parse protocols
+ //
+ const string protocolVersionMax = properties->getProperty(propPrefix + "ProtocolVersionMax");
+ if(!protocolVersionMax.empty())
+ {
+ _protocolVersionMax = parseProtocol(protocolVersionMax);
+ }
+
+ const string protocolVersionMin = properties->getProperty(propPrefix + "ProtocolVersionMin");
+ if(!protocolVersionMin.empty())
+ {
+ _protocolVersionMin = parseProtocol(protocolVersionMin);
+ }
+ _initialized = true;
+}
+
+//
+// Destroy the engine.
+//
+void
+IceSSL::SecureTransportEngine::destroy()
+{
+ if(_certificateAuthorities)
+ {
+ CFRelease(_certificateAuthorities);
+ _certificateAuthorities = 0;
+ }
+
+ if(_identity)
+ {
+ CFRelease(_identity);
+ _identity = 0;
+ }
+
+ if(_cert)
+ {
+ CFRelease(_cert);
+ _cert = 0;
+ }
+
+ if(_key)
+ {
+ CFRelease(_key);
+ _key = 0;
+ }
+
+ if(_keychain)
+ {
+ CFRelease(_keychain);
+ _keychain = 0;
+ }
+
+ if(_ctx)
+ {
+ CFRelease(_ctx);
+ _ctx = 0;
+ }
+}
+
+ContextRef
+IceSSL::SecureTransportEngine::newContext(bool incoming)
+{
+ ContextRef ssl = SSLCreateContext(kCFAllocatorDefault, incoming ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
+ if(!ssl)
+ {
+ PluginInitializationException ex(__FILE__, __LINE__, "IceSSL: unable to create SSL context");
+ throw ex;
+ }
+
+ OSStatus err = noErr;
+ if(incoming)
+ {
+ switch(getVerifyPeer())
+ {
+ case 0:
+ {
+ SSLSetClientSideAuthenticate(ssl, kNeverAuthenticate);
+ break;
+ }
+ case 1:
+ {
+ SSLSetClientSideAuthenticate(ssl, kTryAuthenticate);
+ break;
+ }
+ case 2:
+ {
+ SSLSetClientSideAuthenticate(ssl, kAlwaysAuthenticate);
+ break;
+ }
+ default:
+ {
+ assert(false);
+ break;
+ }
+ }
+
+ if(_dhParamsLength > 0)
+ {
+ err = SSLSetDiffieHellmanParams(ssl, _dhParams->get(), _dhParamsLength);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to create the trust object:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+ }
+
+ if(_cert)
+ {
+ //
+ // Retrieve the certificate chain
+ //
+ SecPolicyRef policy = SecPolicyCreateSSL(true, 0);
+ SecTrustRef trust;
+ err = SecTrustCreateWithCertificates((CFArrayRef)_cert, policy, &trust);
+ if(err != noErr || !trust)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to create the trust object";
+ if(err != noErr)
+ {
+ os << '\n' << errorToString(err);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ err = SecTrustSetAnchorCertificates(trust, _certificateAuthorities);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to establish the anchor certificates\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ SecTrustResultType trustResult;
+ err = SecTrustEvaluate(trust, &trustResult);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to evaluate trust:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ int chainLength = SecTrustGetCertificateCount(trust);
+ CFMutableArrayRef chain = CFArrayCreateMutable(kCFAllocatorDefault, chainLength, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(chain, _identity);
+ for(int i = 1; i < chainLength; ++i)
+ {
+ CFArrayAppendValue(chain, SecTrustGetCertificateAtIndex(trust, i));
+ }
+ CFRelease(trust);
+
+ err = SSLSetCertificate(ssl, chain);
+
+ CFRelease(chain);
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to set the SSL context certificate identity:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+
+
+ if(_numCiphers != -1)
+ {
+ err = SSLSetEnabledCiphers(ssl, _ciphers->get(), _numCiphers);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: failed to set enabled ciphers:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+ err = SSLSetSessionOption(ssl, incoming ? kSSLSessionOptionBreakOnClientAuth : kSSLSessionOptionBreakOnServerAuth,
+ true);
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: failed to set SSL option:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ if(_protocolVersionMax != kSSLProtocolUnknown)
+ {
+ err = SSLSetProtocolVersionMax(ssl, _protocolVersionMax);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: failed to set SSL protocol version max:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+
+ if(_protocolVersionMin != kSSLProtocolUnknown)
+ {
+ err = SSLSetProtocolVersionMin(ssl, _protocolVersionMin);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: failed to set SSL protocol version min:\n" << errorToString(err);
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+
+ return ssl;
+}
+
+CFArrayRef
+IceSSL::SecureTransportEngine::getCertificateAuthorities() const
+{
+ return _certificateAuthorities;
+}
+
+string
+IceSSL::SecureTransportEngine::getCipherName(SSLCipherSuite cipher) const
+{
+ return CiphersHelper::cipherName(cipher);
+}
+
+void
+IceSSL::SecureTransportEngine::parseCiphers(const string& ciphers)
+{
+ vector<string> tokens;
+ vector<CipherExpression> cipherExpressions;
+
+ IceUtilInternal::splitString(ciphers, " \t", tokens);
+ for(vector<string>::const_iterator i = tokens.begin(); i != tokens.end(); ++i)
+ {
+ string token(*i);
+ if(token == "ALL")
+ {
+ if(i != tokens.begin())
+ {
+ ostringstream os;
+ os << "IceSSL: `ALL' must be first in cipher list `" << ciphers << "'";
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ _allCiphers = true;
+ }
+ else
+ {
+ CipherExpression ce;
+ if(token.find('!') == 0)
+ {
+ ce.negation = true;
+ if(token.size() > 1)
+ {
+ token = token.substr(1);
+ }
+ else
+ {
+ ostringstream os;
+ os << "IceSSL: invalid cipher expression `" << token << "'";
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+
+ if(token.find('(') == 0)
+ {
+ if(token.rfind(')') != token.size() - 1)
+ {
+ ostringstream os;
+ os << "IceSSL: invalid cipher expression `" << token << "'";
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ try
+ {
+ ce.re = new RegExp(token.substr(1, token.size() - 2));
+ }
+ catch(const Ice::SyscallException&)
+ {
+ ostringstream os;
+ os << "IceSSL: invalid cipher expression `" << token << "'";
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+ else
+ {
+ ce.cipher = token;
+ }
+
+ cipherExpressions.push_back(ce);
+ }
+ }
+ size_t numSupportedCiphers = 0;
+ SSLGetNumberSupportedCiphers(_ctx, &numSupportedCiphers);
+
+ ScopedArray<SSLCipherSuite> buffer(new SSLCipherSuite[numSupportedCiphers]);
+
+ OSStatus err;
+ if((err = SSLGetSupportedCiphers(_ctx, buffer.get(), &numSupportedCiphers)) != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: unable to get supported ciphers list (error = " << err << ")";
+ PluginInitializationException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ SSLCipherSuite* supported = buffer.get();
+ vector<SSLCipherSuite> allCiphers;
+ if(_allCiphers)
+ {
+ for(int i = 0; i < numSupportedCiphers; ++i)
+ {
+ allCiphers.push_back(supported[i]);
+ }
+ }
+
+ for(vector<CipherExpression>::const_iterator i = cipherExpressions.begin(); i != cipherExpressions.end(); ++i)
+ {
+ CipherExpression ce = *i;
+ if(ce.negation)
+ {
+ for(vector<SSLCipherSuite>::iterator j = allCiphers.begin(); j != allCiphers.end();)
+ {
+ SSLCipherSuite cipher = *j;
+ string name = CiphersHelper::cipherName(cipher);
+
+ if(ce.cipher.empty())
+ {
+ if(ce.re->match(name))
+ {
+ j = allCiphers.erase(j);
+ continue;
+ }
+ }
+ else
+ {
+ if(ce.cipher == name)
+ {
+ j = allCiphers.erase(j);
+ continue;
+ }
+ }
+ j++;
+ }
+ }
+ else
+ {
+ if(ce.cipher.empty())
+ {
+ for(int i = 0; i < numSupportedCiphers; ++i)
+ {
+ SSLCipherSuite cipher = supported[i];
+ string name = CiphersHelper::cipherName(cipher);
+ if(ce.re->match(name))
+ {
+ vector<SSLCipherSuite>::const_iterator k = find(allCiphers.begin(), allCiphers.end(), cipher);
+ if(k == allCiphers.end())
+ {
+ allCiphers.push_back(cipher);
+ }
+ }
+ }
+ }
+ else
+ {
+ SSLCipherSuite cipher = CiphersHelper::cipherForName(ce.cipher);
+ vector<SSLCipherSuite>::const_iterator k = find(allCiphers.begin(), allCiphers.end(), cipher);
+ if(k == allCiphers.end())
+ {
+ allCiphers.push_back(cipher);
+ }
+ }
+ }
+ }
+
+ if(!allCiphers.empty())
+ {
+ _ciphers.reset(new ScopedArray<SSLCipherSuite>(new SSLCipherSuite[allCiphers.size()]));
+ SSLCipherSuite* enabled = _ciphers->get();
+ for(vector<SSLCipherSuite>::const_iterator i = allCiphers.begin(); i != allCiphers.end(); ++i)
+ {
+ *(enabled++) = *i;
+ }
+ }
+ _numCiphers = allCiphers.size();
+}
+
+SecCertificateRef
+IceSSL::SecureTransportEngine::getCertificate() const
+{
+ return _cert;
+}
+
+SecKeychainRef
+IceSSL::SecureTransportEngine::getKeychain() const
+{
+ return _keychain;
+}
+
+#endif
diff --git a/cpp/src/IceSSL/SecureTransportTransceiverI.cpp b/cpp/src/IceSSL/SecureTransportTransceiverI.cpp
new file mode 100644
index 00000000000..38572c5ba65
--- /dev/null
+++ b/cpp/src/IceSSL/SecureTransportTransceiverI.cpp
@@ -0,0 +1,1055 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#include <IceSSL/SecureTransportTransceiverI.h>
+#include <IceUtil/FileUtil.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/MutexPtrLock.h>
+
+#include <IceSSL/ConnectionInfo.h>
+#include <IceSSL/Instance.h>
+#include <IceSSL/Util.h>
+#include <Ice/Communicator.h>
+#include <Ice/LoggerUtil.h>
+#include <Ice/Buffer.h>
+#include <Ice/LocalException.h>
+
+#ifdef ICE_USE_SECURE_TRANSPORT
+
+using namespace std;
+using namespace Ice;
+using namespace IceSSL;
+
+namespace
+{
+
+string
+trustResultDescription(SecTrustResultType result)
+{
+ switch(result)
+ {
+ case kSecTrustResultInvalid:
+ {
+ return "Invalid setting or result.";
+ }
+ case kSecTrustResultDeny:
+ {
+ return "The user specified that the certificate should not be trusted.";
+ }
+ case kSecTrustResultRecoverableTrustFailure:
+ {
+ return "Trust denied; retry after changing settings.";
+ }
+ case kSecTrustResultFatalTrustFailure:
+ {
+ return "Trust denied; no simple fix is available.";
+ }
+ case kSecTrustResultOtherError:
+ {
+ return "A failure other than that of trust evaluation.";
+ }
+ default:
+ {
+ assert(false);
+ return "";
+ }
+ }
+}
+
+string
+protocolName(SSLProtocol protocol)
+{
+ switch(protocol)
+ {
+ case kSSLProtocol2:
+ return "SSL 2.0";
+ case kSSLProtocol3:
+ return "SSL 3.0";
+ case kTLSProtocol1:
+ return "TLS 1.0";
+ case kTLSProtocol11:
+ return "TLS 1.1";
+ case kTLSProtocol12:
+ return "TLS 1.2";
+ default:
+ return "Unknown";
+ }
+}
+
+//
+// Socket write callback
+//
+OSStatus
+socketWrite(SSLConnectionRef connection, const void* data, size_t* length)
+{
+ const TransceiverI* transceiver = static_cast<const TransceiverI*>(connection);
+ assert(transceiver);
+ return transceiver->writeRaw(reinterpret_cast<const char*>(data), length);
+}
+
+//
+// Socket read callback
+//
+OSStatus
+socketRead(SSLConnectionRef connection, void* data, size_t* length)
+{
+ const TransceiverI* transceiver = static_cast<const TransceiverI*>(connection);
+ assert(transceiver);
+ return transceiver->readRaw(reinterpret_cast<char*>(data), length);
+}
+
+}
+
+IceInternal::NativeInfoPtr
+IceSSL::TransceiverI::getNativeInfo()
+{
+ return this;
+}
+
+IceInternal::SocketOperation
+IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::Buffer& writeBuffer, bool&)
+{
+ try
+ {
+ if(_state == StateNeedConnect)
+ {
+ _state = StateConnectPending;
+ return IceInternal::SocketOperationConnect;
+ }
+ else if(_state <= StateConnectPending)
+ {
+ IceInternal::doFinishConnect(_fd);
+ _desc = IceInternal::fdToString(_fd, _proxy, _addr, true);
+
+ if(_proxy)
+ {
+ //
+ // Prepare the read & write buffers in advance.
+ //
+ _proxy->beginWriteConnectRequest(_addr, writeBuffer);
+ _proxy->beginReadConnectRequestResponse(readBuffer);
+
+ //
+ // Write the proxy connection message using TCP.
+ //
+ if(writeRaw(writeBuffer))
+ {
+ //
+ // Write completed without blocking.
+ //
+ _proxy->endWriteConnectRequest(writeBuffer);
+
+ //
+ // Try to read the response using TCP.
+ //
+ if(readRaw(readBuffer))
+ {
+ //
+ // Read completed without blocking - fall through.
+ //
+ _proxy->endReadConnectRequestResponse(readBuffer);
+ }
+ else
+ {
+ //
+ // Return SocketOperationRead to indicate we need to complete the read.
+ //
+ _state = StateProxyConnectRequestPending; // Wait for proxy response
+ return IceInternal::SocketOperationRead;
+ }
+ }
+ else
+ {
+ //
+ // Return SocketOperationWrite to indicate we need to complete the write.
+ //
+ _state = StateProxyConnectRequest; // Send proxy connect request
+ return IceInternal::SocketOperationWrite;
+ }
+ }
+
+ _state = StateConnected;
+ }
+ else if(_state == StateProxyConnectRequest)
+ {
+ //
+ // Write completed.
+ //
+ _proxy->endWriteConnectRequest(writeBuffer);
+ _state = StateProxyConnectRequestPending; // Wait for proxy response
+ return IceInternal::SocketOperationRead;
+ }
+ else if(_state == StateProxyConnectRequestPending)
+ {
+ //
+ // Read completed.
+ //
+ _proxy->endReadConnectRequestResponse(readBuffer);
+ _state = StateConnected;
+ }
+
+ assert(_state == StateConnected);
+
+ OSStatus err = noErr;
+
+ if(!_ssl)
+ {
+ //
+ // Initialize SSL context
+ //
+ _ssl = _engine->newContext(_incoming);
+ if((err = SSLSetIOFuncs(_ssl, socketRead, socketWrite)) != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: cannot set SSL IO functions\n" << errorToString(err);
+ throw PluginInitializationException(__FILE__, __LINE__, os.str());
+ }
+
+ if((err = SSLSetConnection(_ssl, reinterpret_cast<SSLConnectionRef>(this))) != noErr)
+ {
+ ostringstream os;
+ os << "IceSSL: cannot set SSL connection\n" << errorToString(err);
+ throw PluginInitializationException(__FILE__, __LINE__, os.str());
+ }
+ }
+
+ SSLSessionState state;
+ SSLGetSessionState(_ssl, &state);
+
+ //
+ // SSL Handshake
+ //
+ while(state == kSSLHandshake || state == kSSLIdle)
+ {
+ err = SSLHandshake(_ssl);
+ if(err != noErr)
+ {
+ switch(err)
+ {
+ case errSSLWouldBlock:
+ {
+ assert(_flags & SSLWantRead || _flags & SSLWantWrite);
+ return _flags & SSLWantRead ? IceInternal::SocketOperationRead : IceInternal::SocketOperationWrite;
+ }
+ case errSSLPeerAuthCompleted:
+ {
+ assert(!_trust);
+ err = SSLCopyPeerTrust(_ssl, &_trust);
+ if(err != noErr)
+ {
+ break;
+ }
+
+ SecTrustResultType trustResult = kSecTrustResultOtherError;
+
+ if(_trust)
+ {
+ err = SecTrustSetAnchorCertificates(_trust, _engine->getCertificateAuthorities());
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "SSL handsake failure:\n" << errorToString(err);
+ throw SecurityException(__FILE__, __LINE__, os.str());
+ }
+
+ //
+ // Disable network fetch, we don't want this to block.
+ //
+ err = SecTrustSetNetworkFetchAllowed(_trust, false);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "SSL handsake failure:\n" << errorToString(err);
+ throw SecurityException(__FILE__, __LINE__, os.str());
+ }
+
+ //
+ // Evaluate the trust
+ //
+ err = SecTrustEvaluate(_trust, &trustResult);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "SSL handsake failure:\n" << errorToString(err);
+ throw SecurityException(__FILE__, __LINE__, os.str());;
+ }
+ }
+
+ switch(trustResult)
+ {
+ case kSecTrustResultUnspecified:
+ case kSecTrustResultProceed:
+ {
+ //
+ // Trust verify success.
+ //
+ break;
+ }
+ case kSecTrustResultInvalid:
+ //case kSecTrustResultConfirm: // Used in old OS X versions
+ case kSecTrustResultDeny:
+ case kSecTrustResultRecoverableTrustFailure:
+ case kSecTrustResultFatalTrustFailure:
+ case kSecTrustResultOtherError:
+ {
+ if(_engine->getVerifyPeer() == 0)
+ {
+ if(_instance->traceLevel() >= 1)
+ {
+ ostringstream os;
+ os << "IceSSL: ignoring certificate verification failure\n"
+ << trustResultDescription(trustResult);
+ _instance->logger()->trace(_instance->traceCategory(), os.str());
+ }
+ break;
+ }
+ else
+ {
+ ostringstream os;
+ os << "IceSSL: certificate verification failure\n"
+ << trustResultDescription(trustResult);
+ string msg = os.str();
+ if(_instance->traceLevel() >= 1)
+ {
+ _instance->logger()->trace(_instance->traceCategory(), msg);
+ }
+ throw ProtocolException(__FILE__, __LINE__, msg);
+ }
+ }
+ }
+ //
+ // Call SSLHandshake to resume the handsake.
+ //
+ continue;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ if(err == errSSLClosedGraceful || err == errSSLClosedAbort)
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = 0;
+ throw ex;
+ }
+ else
+ {
+ IceInternal::Address remoteAddr;
+ string desc = "<not available>";
+ if(IceInternal::fdToRemoteAddress(_fd, remoteAddr))
+ {
+ desc = IceInternal::addrToString(remoteAddr);
+ }
+ ostringstream os;
+ os << "SSL error occurred for new " << (_incoming ? "incoming" : "outgoing")
+ << " connection:\nremote address = " << desc << "\n"
+ << errorToString(err);
+ ProtocolException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ }
+ break;
+ }
+ _engine->verifyPeer(_fd, _host, getNativeConnectionInfo());
+ _state = StateHandshakeComplete;
+ }
+ catch(const Ice::LocalException& ex)
+ {
+ if(_instance->traceLevel() >= 2)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "failed to establish " << _instance->protocol() << " connection\n";
+ if(_incoming)
+ {
+ out << IceInternal::fdToString(_fd) << "\n" << ex;
+ }
+ else
+ {
+ out << IceInternal::fdToString(_fd, _proxy, _addr, false) << "\n" << ex;
+ }
+ }
+ throw;
+ }
+
+ if(_instance->traceLevel() >= 1)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ if(_incoming)
+ {
+ out << "accepted " << _instance->protocol() << " connection\n" << _desc;
+ }
+ else
+ {
+ out << _instance->protocol() << " connection established\n" << _desc;
+ }
+ }
+
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ traceConnection();
+ }
+
+ return IceInternal::SocketOperationNone;
+}
+
+IceInternal::SocketOperation
+IceSSL::TransceiverI::closing(bool initiator, const Ice::LocalException&)
+{
+ // If we are initiating the connection closure, wait for the peer
+ // to close the TCP/IP connection. Otherwise, close immediately.
+ return initiator ? IceInternal::SocketOperationRead : IceInternal::SocketOperationNone;
+}
+
+void
+IceSSL::TransceiverI::close()
+{
+ if(_state == StateHandshakeComplete && _instance->traceLevel() >= 1)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "closing " << _instance->protocol() << " connection\n" << toString();
+ }
+
+ if(_trust)
+ {
+ CFRelease(_trust);
+ _trust = 0;
+ }
+
+ if(_ssl)
+ {
+ SSLClose(_ssl);
+ CFRelease(_ssl);
+ _ssl = 0;
+ }
+
+ assert(_fd != INVALID_SOCKET);
+ try
+ {
+ IceInternal::closeSocket(_fd);
+ _fd = INVALID_SOCKET;
+ }
+ catch(const SocketException&)
+ {
+ _fd = INVALID_SOCKET;
+ throw;
+ }
+}
+
+IceInternal::SocketOperation
+IceSSL::TransceiverI::write(IceInternal::Buffer& buf)
+{
+ if(_state == StateProxyConnectRequest)
+ {
+ //
+ // We need to write the proxy message, but we have to use TCP and not SSL.
+ //
+ return writeRaw(buf) ? IceInternal::SocketOperationNone : IceInternal::SocketOperationWrite;
+ }
+
+ size_t processed = 0;
+
+ if(_buffered > 0)
+ {
+ //
+ // Required to flush SSL buffers
+ //
+ if(SSLWrite(_ssl, 0, 0, &processed) == errSSLWouldBlock)
+ {
+ return IceInternal::SocketOperationWrite;
+ }
+
+ buf.i += _buffered;
+ _buffered = 0;
+ }
+
+ if(buf.i == buf.b.end())
+ {
+ return IceInternal::SocketOperationNone;
+ }
+
+ //
+ // It's impossible for packetSize to be more than an Int.
+ //
+ size_t packetSize = static_cast<size_t>(buf.b.end() - buf.i);
+ packetSize = std::min(packetSize, _maxSendPacketSize);
+ while(buf.i != buf.b.end())
+ {
+ assert(_fd != INVALID_SOCKET);
+ OSStatus ret = SSLWrite(_ssl, reinterpret_cast<const void*>(buf.i), packetSize, &processed);
+ if(ret != noErr)
+ {
+ if(ret == errSSLWouldBlock)
+ {
+ _buffered = processed;
+ assert(_flags & SSLWantWrite);
+ return IceInternal::SocketOperationWrite;
+ }
+
+ if(ret == errSSLClosedGraceful)
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = 0;
+ throw ex;
+ }
+
+ //
+ // SSL protocol errors are defined in SecureTransport.h are in the range
+ // -9800 to -9849
+ //
+ if(ret <= -9800 && ret >= -9849)
+ {
+ ProtocolException ex(__FILE__, __LINE__);
+ ostringstream os;
+ os << "SSL protocol error during read:\n" << errorToString(ret);
+ ex.reason = os.str();
+ throw ex;
+ }
+
+ errno = ret;
+ if(IceInternal::connectionLost())
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ }
+
+ if(_instance->traceLevel() >= 3)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "sent " << processed << " of " << packetSize << " bytes via " << protocol() << "\n" << toString();
+ }
+
+ buf.i += processed;
+
+ if(packetSize > buf.b.end() - buf.i)
+ {
+ packetSize = static_cast<int>(buf.b.end() - buf.i);
+ }
+ }
+
+ return IceInternal::SocketOperationNone;
+}
+
+IceInternal::SocketOperation
+IceSSL::TransceiverI::read(IceInternal::Buffer& buf, bool&)
+{
+ if(_state == StateProxyConnectRequestPending)
+ {
+ //
+ // We need to read the proxy reply, but we have to use TCP and not SSL.
+ //
+ return readRaw(buf) ? IceInternal::SocketOperationNone : IceInternal::SocketOperationRead;
+ }
+
+ if(buf.i == buf.b.end())
+ {
+ return IceInternal::SocketOperationNone;
+ }
+ //
+ // It's impossible for packetSize to be more than an Int.
+ //
+ size_t packetSize = static_cast<int>(buf.b.end() - buf.i);
+ size_t processed = 0;
+
+ packetSize = std::min(packetSize, _maxReceivePacketSize);
+
+ while(buf.i != buf.b.end())
+ {
+ assert(_fd != INVALID_SOCKET);
+ OSStatus ret = SSLRead(_ssl, reinterpret_cast<void*>(buf.i), packetSize, &processed);
+ if(ret != noErr)
+ {
+ if(ret == errSSLWouldBlock)
+ {
+ buf.i += processed;
+ assert(_flags & SSLWantRead);
+ return IceInternal::SocketOperationRead;
+ }
+
+ if(ret == errSSLClosedGraceful || ret == errSSLPeerBadRecordMac || ret == errSSLPeerDecryptionFail)
+ {
+ //
+ // Forcefully closing a connection can result in SSLRead reporting
+ // "decryption failed or bad record mac". We trap that error and
+ // treat it as the loss of a connection.
+ //
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = 0;
+ throw ex;
+ }
+
+ //
+ // SSL protocol errors are defined in SecureTransport.h are in the range
+ // -9800 to -9849
+ //
+ if(ret <= -9800 && ret >= -9849)
+ {
+ ProtocolException ex(__FILE__, __LINE__);
+ ostringstream os;
+ os << "SSL protocol error during read:\n" << errorToString(ret);
+ ex.reason = os.str();
+ throw ex;
+ }
+
+ errno = ret;
+ if(IceInternal::connectionLost())
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ }
+
+ if(_instance->traceLevel() >= 3)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "received " << processed << " of " << packetSize << " bytes via " << protocol() << "\n"
+ << toString();
+ }
+ buf.i += processed;
+
+ if(packetSize > buf.b.end() - buf.i)
+ {
+ packetSize = static_cast<int>(buf.b.end() - buf.i);
+ }
+ }
+ return IceInternal::SocketOperationNone;
+}
+
+string
+IceSSL::TransceiverI::protocol() const
+{
+ return _instance->protocol();
+}
+
+string
+IceSSL::TransceiverI::toString() const
+{
+ return _desc;
+}
+
+Ice::ConnectionInfoPtr
+IceSSL::TransceiverI::getInfo() const
+{
+ return getNativeConnectionInfo();
+}
+
+void
+IceSSL::TransceiverI::checkSendSize(const IceInternal::Buffer& buf, size_t messageSizeMax)
+{
+ if(buf.b.size() > messageSizeMax)
+ {
+ IceInternal::Ex::throwMemoryLimitException(__FILE__, __LINE__, buf.b.size(), messageSizeMax);
+ }
+}
+
+SecTrustRef
+IceSSL::TransceiverI::trust() const
+{
+ return _trust;
+}
+
+ContextRef
+IceSSL::TransceiverI::context() const
+{
+ return _ssl;
+}
+
+IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, SOCKET fd, const IceInternal::NetworkProxyPtr& proxy,
+ const string& host, const IceInternal::Address& addr) :
+ IceInternal::NativeInfo(fd),
+ _instance(instance),
+ _engine(SecureTransportEnginePtr::dynamicCast(instance->engine())),
+ _proxy(proxy),
+ _host(host),
+ _addr(addr),
+ _incoming(false),
+ _ssl(0),
+ _trust(0),
+ _buffered(0),
+ _state(StateNeedConnect)
+{
+ assert(_engine);
+ IceInternal::setBlock(fd, false);
+ IceInternal::setTcpBufSize(fd, _instance->properties(), _instance->logger());
+
+ IceInternal::Address connectAddr = proxy ? proxy->getAddress() : addr;
+ if(IceInternal::doConnect(_fd, connectAddr))
+ {
+ _state = StateConnected;
+ _desc = IceInternal::fdToString(_fd, _proxy, _addr, true);
+ if(_instance->traceLevel() >= 1)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << _instance->protocol() << " connection established\n" << _desc;
+ }
+ }
+ else
+ {
+ _desc = IceInternal::fdToString(_fd, _proxy, _addr, true);
+ }
+
+ //
+ // Limit the size of packet pass to SSLWrite/SSLRead to avoid blocking and
+ // holding too much memory.
+ //
+ _maxSendPacketSize = std::min(512, IceInternal::getSendBufferSize(fd));
+ _maxReceivePacketSize = std::min(512, IceInternal::getRecvBufferSize(fd));
+}
+
+IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, SOCKET fd, const string& adapterName) :
+ IceInternal::NativeInfo(fd),
+ _instance(instance),
+ _engine(SecureTransportEnginePtr::dynamicCast(instance->engine())),
+ _addr(IceInternal::Address()),
+ _adapterName(adapterName),
+ _incoming(true),
+ _ssl(0),
+ _trust(0),
+ _buffered(0),
+ _state(StateConnected),
+ _desc(IceInternal::fdToString(fd))
+{
+ assert(_engine);
+ IceInternal::setBlock(fd, false);
+ IceInternal::setTcpBufSize(fd, _instance->properties(), _instance->logger());
+
+ //
+ // Limit the size of packet pass to SSLWrite/SSLRead to avoid blocking and
+ // holding too much memory.
+ //
+ _maxSendPacketSize = std::min(512, IceInternal::getSendBufferSize(fd));
+ _maxReceivePacketSize = std::min(512, IceInternal::getRecvBufferSize(fd));
+}
+
+IceSSL::TransceiverI::~TransceiverI()
+{
+ assert(_fd == INVALID_SOCKET);
+}
+
+NativeConnectionInfoPtr
+IceSSL::TransceiverI::getNativeConnectionInfo() const
+{
+ NativeConnectionInfoPtr info = new NativeConnectionInfo();
+ IceInternal::fdToAddressAndPort(_fd, info->localAddress, info->localPort, info->remoteAddress, info->remotePort);
+
+ if(_ssl)
+ {
+ for(int i = 0, count = SecTrustGetCertificateCount(_trust); i < count; ++i)
+ {
+ SecCertificateRef cert = SecTrustGetCertificateAtIndex(_trust, i);
+ CFRetain(cert);
+
+ CertificatePtr certificate = new Certificate(cert);
+ info->nativeCerts.push_back(certificate);
+ info->certs.push_back(certificate->encode());
+ }
+
+ SSLCipherSuite cipher;
+ SSLGetNegotiatedCipher(_ssl, &cipher);
+ info->cipher = _engine->getCipherName(cipher);
+ }
+
+ info->adapterName = _adapterName;
+ info->incoming = _incoming;
+ return info;
+}
+
+bool
+IceSSL::TransceiverI::writeRaw(IceInternal::Buffer& buf)
+{
+ //
+ // It's impossible for packetSize to be more than an Int.
+ //
+ int packetSize = static_cast<int>(buf.b.end() - buf.i);
+ while(buf.i != buf.b.end())
+ {
+ assert(_fd != INVALID_SOCKET);
+
+ ssize_t ret = ::send(_fd, reinterpret_cast<const char*>(&*buf.i), packetSize, 0);
+ if(ret == 0)
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = 0;
+ throw ex;
+ }
+
+ if(ret == SOCKET_ERROR)
+ {
+ if(IceInternal::interrupted())
+ {
+ continue;
+ }
+
+ if(IceInternal::noBuffers() && packetSize > 1024)
+ {
+ packetSize /= 2;
+ continue;
+ }
+
+ if(IceInternal::wouldBlock())
+ {
+ return false;
+ }
+
+ if(IceInternal::connectionLost())
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ }
+
+ if(_instance->traceLevel() >= 3)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "sent " << ret << " of " << packetSize << " bytes via " << protocol() << "\n" << toString();
+ }
+
+ buf.i += ret;
+
+ if(packetSize > buf.b.end() - buf.i)
+ {
+ packetSize = static_cast<int>(buf.b.end() - buf.i);
+ }
+ }
+
+ return true;
+}
+
+bool
+IceSSL::TransceiverI::readRaw(IceInternal::Buffer& buf)
+{
+ //
+ // It's impossible for packetSize to be more than an Int.
+ //
+ int packetSize = static_cast<int>(buf.b.end() - buf.i);
+ while(buf.i != buf.b.end())
+ {
+ assert(_fd != INVALID_SOCKET);
+ ssize_t ret = ::recv(_fd, reinterpret_cast<char*>(&*buf.i), packetSize, 0);
+
+ if(ret == 0)
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = 0;
+ throw ex;
+ }
+
+ if(ret == SOCKET_ERROR)
+ {
+ if(IceInternal::interrupted())
+ {
+ continue;
+ }
+
+ if(IceInternal::noBuffers() && packetSize > 1024)
+ {
+ packetSize /= 2;
+ continue;
+ }
+
+ if(IceInternal::wouldBlock())
+ {
+ return false;
+ }
+
+ if(IceInternal::connectionLost())
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = IceInternal::getSocketErrno();
+ throw ex;
+ }
+ }
+
+ if(_instance->traceLevel() >= 3)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "received " << ret << " of " << packetSize << " bytes via " << protocol() << "\n" << toString();
+ }
+
+ buf.i += ret;
+
+ packetSize = static_cast<int>(buf.b.end() - buf.i);
+ }
+
+ return true;
+}
+
+//
+// Trace connection
+//
+void
+IceSSL::TransceiverI::traceConnection()
+{
+ assert(_ssl);
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "SSL summary for " << (_incoming ? "incoming" : "outgoing") << " connection\n";
+
+ SSLProtocol protocol;
+ SSLGetNegotiatedProtocolVersion(_ssl, &protocol);
+ const string sslProtocolName = protocolName(protocol);
+
+ SSLCipherSuite cipher;
+ SSLGetNegotiatedCipher(_ssl, &cipher);
+ const string sslCipherName = _engine->getCipherName(cipher);
+
+ if(sslCipherName.empty())
+ {
+ out << "unknown cipher\n";
+ }
+ else
+ {
+ out << "cipher = " << sslCipherName << "\n";
+ out << "protocol = " << sslProtocolName << "\n";
+ }
+ out << IceInternal::fdToString(_fd);
+}
+
+OSStatus
+IceSSL::TransceiverI::writeRaw(const char* data, size_t* length) const
+{
+ _flags &= ~SSLWantWrite;
+
+ assert(_fd != INVALID_SOCKET);
+
+ char* i = const_cast<char*>(data);
+ int packetSize = *length;
+ char* end = i + packetSize;
+
+ while(i != end)
+ {
+ ssize_t ret = ::send(_fd, const_cast<const char*>(i), packetSize, 0);
+ if(ret == 0)
+ {
+ return errSSLClosedGraceful;
+ }
+
+ if(ret == SOCKET_ERROR)
+ {
+ if(IceInternal::interrupted())
+ {
+ continue;
+ }
+
+ if(IceInternal::noBuffers() && packetSize > 1024)
+ {
+ packetSize /= 2;
+ continue;
+ }
+
+ if(IceInternal::wouldBlock())
+ {
+ *length = static_cast<int>(i - data);
+ _flags |= SSLWantWrite;
+ return errSSLWouldBlock;
+ }
+ return errno;
+ }
+
+ i += ret;
+ if(_instance->traceLevel() >= 3)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "sent " << ret << " of " << packetSize << " bytes via " << protocol() << "\n" << toString();
+ }
+
+ if(packetSize > end - i)
+ {
+ packetSize = static_cast<int>(end - i);
+ }
+ }
+ *length = static_cast<int>(i - data);
+ return noErr;
+}
+
+OSStatus
+IceSSL::TransceiverI::readRaw(char* data, size_t* length) const
+{
+ _flags &= ~SSLWantRead;
+
+ assert(_fd != INVALID_SOCKET);
+
+ char* i = data;
+ int packetSize = *length;
+ char* end = i + packetSize;
+ while(i != end)
+ {
+ ssize_t ret = ::recv(_fd, i, packetSize, 0);
+ if(ret == 0)
+ {
+ return errSSLClosedGraceful;
+ }
+
+ if(ret == SOCKET_ERROR)
+ {
+ if(IceInternal::interrupted())
+ {
+ continue;
+ }
+
+ if(IceInternal::noBuffers() && packetSize > 1024)
+ {
+ packetSize /= 2;
+ continue;
+ }
+
+ if(IceInternal::wouldBlock())
+ {
+ *length = static_cast<int>(i - data);
+ _flags |= SSLWantRead;
+ return errSSLWouldBlock;
+ }
+ return errno;
+ }
+
+ i += ret;
+
+ if(_instance->traceLevel() >= 3)
+ {
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "received " << ret << " of " << packetSize << " bytes via " << protocol() << "\n" << toString();
+ }
+
+ packetSize = static_cast<int>(end - i);
+ }
+
+ *length = static_cast<int>(i - data);
+ return noErr;
+}
+
+#endif
diff --git a/cpp/src/IceSSL/SecureTransportTransceiverI.h b/cpp/src/IceSSL/SecureTransportTransceiverI.h
new file mode 100644
index 00000000000..c38c8d26b4c
--- /dev/null
+++ b/cpp/src/IceSSL/SecureTransportTransceiverI.h
@@ -0,0 +1,114 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2014 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.
+//
+// **********************************************************************
+
+#ifndef ICE_SSL_SECURE_TRANSPORT_TRANSCEIVER_I_H
+#define ICE_SSL_SECURE_TRANSPORT_TRANSCEIVER_I_H
+
+#include <IceSSL/Config.h>
+#include <IceSSL/InstanceF.h>
+#include <IceSSL/SSLEngineF.h>
+#include <IceSSL/Plugin.h>
+
+#include <Ice/Transceiver.h>
+#include <Ice/Network.h>
+
+#ifdef ICE_USE_SECURE_TRANSPORT
+
+#include <Security/Security.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace IceSSL
+{
+
+class ConnectorI;
+class AcceptorI;
+
+class TransceiverI : public IceInternal::Transceiver, public IceInternal::NativeInfo
+{
+ enum State
+ {
+ StateNeedConnect,
+ StateConnectPending,
+ StateProxyConnectRequest,
+ StateProxyConnectRequestPending,
+ StateConnected,
+ StateHandshakeComplete
+ };
+
+public:
+
+ virtual IceInternal::NativeInfoPtr getNativeInfo();
+
+ virtual IceInternal::SocketOperation initialize(IceInternal::Buffer&, IceInternal::Buffer&, bool&);
+ virtual IceInternal::SocketOperation closing(bool, const Ice::LocalException&);
+ virtual void close();
+ virtual IceInternal::SocketOperation write(IceInternal::Buffer&);
+ virtual IceInternal::SocketOperation read(IceInternal::Buffer&, bool&);
+
+ virtual std::string protocol() const;
+ virtual std::string toString() const;
+ virtual Ice::ConnectionInfoPtr getInfo() const;
+ virtual void checkSendSize(const IceInternal::Buffer&, size_t);
+
+ ContextRef context() const;
+ SecTrustRef trust() const;
+ OSStatus writeRaw(const char*, size_t*) const;
+ OSStatus readRaw(char*, size_t*) const;
+
+private:
+
+ TransceiverI(const InstancePtr&, SOCKET, const IceInternal::NetworkProxyPtr&, const std::string&,
+ const IceInternal::Address&);
+ TransceiverI(const InstancePtr&, SOCKET, const std::string&);
+ virtual ~TransceiverI();
+
+ virtual NativeConnectionInfoPtr getNativeConnectionInfo() const;
+
+ void traceConnection();
+
+ bool writeRaw(IceInternal::Buffer&);
+ bool readRaw(IceInternal::Buffer&);
+
+ friend class ConnectorI;
+ friend class AcceptorI;
+
+ const InstancePtr _instance;
+ const SecureTransportEnginePtr _engine;
+
+ const IceInternal::NetworkProxyPtr _proxy;
+ const std::string _host;
+ const IceInternal::Address _addr;
+
+ const std::string _adapterName;
+ const bool _incoming;
+
+ ContextRef _ssl;
+ SecTrustRef _trust;
+
+ size_t _buffered;
+ enum SSLWantFlags
+ {
+ SSLWantRead = 0x1,
+ SSLWantWrite = 0x2
+ };
+
+ mutable Ice::Byte _flags;
+
+ State _state;
+ std::string _desc;
+ size_t _maxSendPacketSize;
+ size_t _maxReceivePacketSize;
+};
+typedef IceUtil::Handle<TransceiverI> TransceiverIPtr;
+
+}
+
+#endif
+
+#endif
diff --git a/cpp/src/IceSSL/TransceiverI.cpp b/cpp/src/IceSSL/TransceiverI.cpp
index 1e07c42e9c3..d749cdf9651 100644
--- a/cpp/src/IceSSL/TransceiverI.cpp
+++ b/cpp/src/IceSSL/TransceiverI.cpp
@@ -7,10 +7,11 @@
//
// **********************************************************************
+#include <IceSSL/TransceiverI.h>
+
#include <IceUtil/Mutex.h>
#include <IceUtil/MutexPtrLock.h>
-#include <IceSSL/TransceiverI.h>
#include <IceSSL/ConnectionInfo.h>
#include <IceSSL/Instance.h>
#include <IceSSL/Util.h>
@@ -21,14 +22,11 @@
#include <IceUtil/DisableWarnings.h>
+#ifdef ICE_USE_OPENSSL
+
#include <openssl/err.h>
#include <openssl/bio.h>
-// Ignore OS X OpenSSL deprecation warnings
-#ifdef __APPLE__
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
using namespace std;
using namespace Ice;
using namespace IceSSL;
@@ -231,7 +229,7 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B
throw ex;
}
- _ssl = SSL_new(_instance->context());
+ _ssl = SSL_new(_engine->context());
if(!_ssl)
{
BIO_free(bio);
@@ -364,7 +362,7 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B
}
ostringstream ostr;
ostr << "SSL error occurred for new " << (_incoming ? "incoming" : "outgoing")
- << " connection:\nremote address = " << desc << "\n" << _instance->sslErrors();
+ << " connection:\nremote address = " << desc << "\n" << _engine->sslErrors();
ProtocolException ex(__FILE__, __LINE__);
ex.reason = ostr.str();
throw ex;
@@ -373,7 +371,7 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B
}
}
- _instance->verifyPeer(_ssl, _fd, _host, getNativeConnectionInfo());
+ _engine->verifyPeer(_ssl, _fd, _host, getNativeConnectionInfo());
_state = StateHandshakeComplete;
}
catch(const Ice::LocalException& ex)
@@ -409,7 +407,7 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B
if(_instance->securityTraceLevel() >= 1)
{
- _instance->traceConnection(_ssl, _incoming);
+ traceConnection();
}
return IceInternal::SocketOperationNone;
@@ -597,7 +595,7 @@ IceSSL::TransceiverI::write(IceInternal::Buffer& buf)
case SSL_ERROR_SSL:
{
ProtocolException ex(__FILE__, __LINE__);
- ex.reason = "SSL protocol error during write:\n" + _instance->sslErrors();
+ ex.reason = "SSL protocol error during write:\n" + _engine->sslErrors();
throw ex;
}
}
@@ -770,7 +768,7 @@ IceSSL::TransceiverI::read(IceInternal::Buffer& buf, bool&)
else
{
ProtocolException ex(__FILE__, __LINE__);
- ex.reason = "SSL protocol error during read:\n" + _instance->sslErrors();
+ ex.reason = "SSL protocol error during read:\n" + _engine->sslErrors();
throw ex;
}
}
@@ -1041,6 +1039,7 @@ IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, SOCKET fd, const
const string& host, const IceInternal::Address& addr) :
IceInternal::NativeInfo(fd),
_instance(instance),
+ _engine(OpenSSLEnginePtr::dynamicCast(instance->engine())),
_proxy(proxy),
_host(host),
_addr(addr),
@@ -1078,6 +1077,7 @@ IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, SOCKET fd, const
IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, SOCKET fd, const string& adapterName) :
IceInternal::NativeInfo(fd),
_instance(instance),
+ _engine(OpenSSLEnginePtr::dynamicCast(instance->engine())),
_addr(IceInternal::Address()),
_adapterName(adapterName),
_incoming(true),
@@ -1366,6 +1366,30 @@ IceSSL::TransceiverI::readAsync(char* buf, int packetSize)
#endif
+void
+IceSSL::TransceiverI::traceConnection()
+{
+ Trace out(_instance->logger(), _instance->traceCategory());
+ out << "SSL summary for " << (_incoming ? "incoming" : "outgoing") << " connection\n";
+
+ //
+ // The const_cast is necesary because Solaris still uses OpenSSL 0.9.7.
+ //
+ //const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
+ SSL_CIPHER *cipher = const_cast<SSL_CIPHER*>(SSL_get_current_cipher(_ssl));
+ if(!cipher)
+ {
+ out << "unknown cipher\n";
+ }
+ else
+ {
+ out << "cipher = " << SSL_CIPHER_get_name(cipher) << "\n";
+ out << "bits = " << SSL_CIPHER_get_bits(cipher, 0) << "\n";
+ out << "protocol = " << SSL_get_version(_ssl) << "\n";
+ }
+ out << IceInternal::fdToString(SSL_get_fd(_ssl));
+}
+
bool
IceSSL::TransceiverI::writeRaw(IceInternal::Buffer& buf)
{
@@ -1507,3 +1531,4 @@ IceSSL::TransceiverI::readRaw(IceInternal::Buffer& buf)
return true;
}
+#endif
diff --git a/cpp/src/IceSSL/TransceiverI.h b/cpp/src/IceSSL/TransceiverI.h
index 4025da7f108..b74da103485 100644
--- a/cpp/src/IceSSL/TransceiverI.h
+++ b/cpp/src/IceSSL/TransceiverI.h
@@ -10,12 +10,16 @@
#ifndef ICE_SSL_TRANSCEIVER_I_H
#define ICE_SSL_TRANSCEIVER_I_H
+#include <IceSSL/Config.h>
#include <IceSSL/InstanceF.h>
#include <IceSSL/Plugin.h>
+#include <IceSSL/SSLEngineF.h>
#include <Ice/Transceiver.h>
#include <Ice/Network.h>
+#ifdef ICE_USE_OPENSSL
+
typedef struct ssl_st SSL;
typedef struct bio_st BIO;
@@ -76,6 +80,7 @@ private:
int readAsync(char*, int);
#endif
+ void traceConnection();
bool writeRaw(IceInternal::Buffer&);
bool readRaw(IceInternal::Buffer&);
@@ -83,7 +88,8 @@ private:
friend class AcceptorI;
const InstancePtr _instance;
-
+ const OpenSSLEnginePtr _engine;
+
const IceInternal::NetworkProxyPtr _proxy;
const std::string _host;
const IceInternal::Address _addr;
@@ -114,3 +120,5 @@ typedef IceUtil::Handle<TransceiverI> TransceiverIPtr;
}
#endif
+
+#endif
diff --git a/cpp/src/IceSSL/Util.cpp b/cpp/src/IceSSL/Util.cpp
index a46db385398..518fd9f5d67 100644
--- a/cpp/src/IceSSL/Util.cpp
+++ b/cpp/src/IceSSL/Util.cpp
@@ -13,33 +13,31 @@
#endif
#include <IceSSL/Util.h>
+#include <IceUtil/ScopedArray.h>
#include <IceUtil/FileUtil.h>
+
#include <Ice/LocalException.h>
#include <Ice/Network.h>
#include <Ice/Object.h>
-#ifdef _WIN32
-# include <direct.h>
-# include <sys/types.h>
-#endif
-
-#include <openssl/err.h>
-
-#include <IceUtil/DisableWarnings.h>
-
-// Ignore OS X OpenSSL deprecation warnings
-#ifdef __APPLE__
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#ifdef ICE_USE_OPENSSL
+# ifdef _WIN32
+# include <direct.h>
+# include <sys/types.h>
+# endif
+# include <openssl/err.h>
#endif
using namespace std;
using namespace Ice;
+using namespace IceUtil;
using namespace IceSSL;
+#ifdef ICE_USE_OPENSSL
namespace
{
-#ifndef OPENSSL_NO_DH
+# ifndef OPENSSL_NO_DH
// The following arrays are predefined Diffie Hellman group parameters.
// These are known strong primes, distributed with the OpenSSL library
@@ -278,41 +276,7 @@ IceSSL::DHParams::get(int keyLength)
}
}
-#endif
-
-bool
-IceSSL::checkPath(string& path, const string& defaultDir, bool dir)
-{
- //
- // Check if file exists. If not, try prepending the default
- // directory and check again. If the path exists, the string
- // argument is modified and true is returned. Otherwise
- // false is returned.
- //
- IceUtilInternal::structstat st;
- int err = IceUtilInternal::stat(path, &st);
- if(err == 0)
- {
- return dir ? S_ISDIR(st.st_mode) != 0 : S_ISREG(st.st_mode) != 0;
- }
-
- if(!defaultDir.empty())
- {
-#ifdef _WIN32
- string s = defaultDir + "\\" + path;
-#else
- string s = defaultDir + "/" + path;
-#endif
- err = ::IceUtilInternal::stat(s.c_str(), &st);
- if(err == 0 && ((!dir && S_ISREG(st.st_mode)) || (dir && S_ISDIR(st.st_mode))))
- {
- path = s;
- return true;
- }
- }
-
- return false;
-}
+# endif
string
IceSSL::getSslErrors(bool verbose)
@@ -368,3 +332,583 @@ IceSSL::getSslErrors(bool verbose)
return ostr.str();
}
+
+#elif defined(ICE_USE_SECURE_TRANSPORT)
+
+string
+IceSSL::errorToString(CFErrorRef err)
+{
+ ostringstream os;
+ if(err)
+ {
+ CFStringRef s = CFErrorCopyDescription(err);
+ os << "(error: " << CFErrorGetCode(err) << " description: " << fromCFString(s) << ")";
+ CFRelease(s);
+ }
+ return os.str();
+}
+
+string
+IceSSL::errorToString(OSStatus status)
+{
+ ostringstream os;
+ os << "(error: " << status;
+ CFStringRef s = SecCopyErrorMessageString(status, 0);
+ if(s)
+ {
+ os << " description: " << fromCFString(s);
+ CFRelease(s);
+ }
+ os << ")";
+ return os.str();
+}
+
+std::string
+IceSSL::fromCFString(CFStringRef v)
+{
+ string s;
+ if(v)
+ {
+ CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(v), kCFStringEncodingUTF8);
+ IceUtil::ScopedArray<char> buffer(new char[size + 1]);
+ CFStringGetCString(v, buffer.get(), size + 1, kCFStringEncodingUTF8);
+ s.assign(buffer.get());
+ }
+ return s;
+}
+
+int
+IceSSL::readFile(const string& file, ScopedArray<char>& buffer)
+{
+ IceUtilInternal::ifstream is(file);
+
+ if(!is.good())
+ {
+ throw CertificateReadException(__FILE__, __LINE__, "error opening file " + file);
+ }
+
+ is.seekg (0, is.end);
+ streampos length = is.tellg();
+ is.seekg (0, is.beg);
+
+ buffer.reset(new char[length]);
+ is.read(buffer.get(), length);
+
+ if(!is.good())
+ {
+ throw CertificateReadException(__FILE__, __LINE__, "error reading file " + file);
+ }
+ return length;
+}
+
+namespace
+{
+
+//
+// Retrive the certificate subject key identifier, the caller must release the returned CFData
+// object.
+//
+CFDataRef
+getSubjectKeyIdentifier(SecCertificateRef cert)
+{
+ CFDataRef data = 0;
+ CFErrorRef err = 0;
+ CFArrayRef keys = CFArrayCreate(NULL, &kSecOIDSubjectKeyIdentifier , 1, &kCFTypeArrayCallBacks);
+ CFDictionaryRef values = SecCertificateCopyValues(cert, keys, &err);
+ CFRelease(keys);
+
+ if(err)
+ {
+ ostringstream os;
+ os << "Failed to copy certificate subject key identifier\n" << errorToString(err);
+ CFRelease(err);
+ CertificateReadException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ if(values)
+ {
+ CFDictionaryRef ski = (CFDictionaryRef)CFDictionaryGetValue(values, kSecOIDSubjectKeyIdentifier);
+ if(ski)
+ {
+ CFArrayRef propertyValues = (CFArrayRef)CFDictionaryGetValue(ski, kSecPropertyKeyValue);
+ for(int i = 0, length = CFArrayGetCount(propertyValues); i < length; ++i)
+ {
+ CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex(propertyValues, i);
+ CFStringRef label = (CFStringRef)CFDictionaryGetValue(dict, kSecPropertyKeyLabel);
+ if(CFEqual(label, CFSTR("Key Identifier")))
+ {
+ data = (CFDataRef)CFDictionaryGetValue(dict, kSecPropertyKeyValue);
+ CFRetain(data);
+ break;
+ }
+ }
+ }
+ CFRelease(values);
+ }
+ return data;
+}
+
+//
+// Check the certificate basic constraints to check if the certificate is marked as a CA.
+//
+bool
+isCA(SecCertificateRef cert)
+{
+ bool ca = false;
+ CFErrorRef err = 0;
+ CFArrayRef keys = CFArrayCreate(NULL, &kSecOIDBasicConstraints, 1, &kCFTypeArrayCallBacks);
+ CFDictionaryRef values = SecCertificateCopyValues(cert, keys, &err);
+ CFRelease(keys);
+
+ if(err)
+ {
+ ostringstream os;
+ os << "Failed to copy certificate basic constraints\n" << errorToString(err);
+ CFRelease(err);
+ CertificateReadException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ if(values)
+ {
+ CFDictionaryRef basicConstraints = (CFDictionaryRef)CFDictionaryGetValue(values, kSecOIDBasicConstraints);
+ if(basicConstraints)
+ {
+ CFArrayRef propertyValues = (CFArrayRef)CFDictionaryGetValue(basicConstraints, kSecPropertyKeyValue);
+ int size = CFArrayGetCount(propertyValues);
+ for(int i = 0; i < size; ++i)
+ {
+ CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex(propertyValues, i);
+ CFStringRef label = (CFStringRef)CFDictionaryGetValue(dict, kSecPropertyKeyLabel);
+ if(CFEqual(label, CFSTR("Certificate Authority")))
+ {
+ CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict, kSecPropertyKeyValue);
+ if(CFEqual(value, CFSTR("Yes")))
+ {
+ ca = true;
+ }
+ break;
+ }
+ }
+ CFRelease(values);
+ }
+ }
+ return ca;
+}
+
+//
+// Search the keychain for an existing item with the same hash and type,
+// the hash is the certificate subject key identifier. For private key
+// items the hash should match kSecAttrApplicationLabel attribute, for
+// certificate items it should match the kSecAttrSubjectKeyID attribute.
+//
+SecKeychainItemRef
+copyMatching(SecKeychainRef keychain, CFDataRef hash, CFTypeRef type)
+{
+ assert(keychain);
+ assert(hash);
+ assert(type == kSecClassKey || type == kSecClassCertificate);
+
+ const void* values[] = {keychain};
+ CFArrayRef searchList = CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks);
+
+ CFMutableDictionaryRef query =
+ CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ CFDictionarySetValue(query, kSecClass, type);
+ CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne);
+ CFDictionarySetValue(query, kSecMatchSearchList, searchList);
+ CFDictionarySetValue(query, type == kSecClassKey ? kSecAttrApplicationLabel : kSecAttrSubjectKeyID, hash);
+ CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
+
+ SecKeychainItemRef item = 0;
+ OSStatus err = SecItemCopyMatching(query, (CFTypeRef*)&item);
+
+ CFRelease(searchList);
+ CFRelease(query);
+
+ if(err != noErr && err != errSecItemNotFound)
+ {
+ ostringstream os;
+ os << "Error searching for keychain items\n" << errorToString(err);
+ CertificateReadException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+
+ return item;
+}
+
+//
+// Add an item to the keychain, if the keychain already has this item return the existing item,
+// otherwise return the new added item.
+//
+SecKeychainItemRef
+addToKeychain(SecKeychainRef keychain, SecKeychainItemRef item, CFDataRef hash, CFTypeRef type)
+{
+ assert(keychain);
+ assert(item);
+ assert(hash);
+
+ SecKeychainItemRef newItem = copyMatching(keychain, hash, type);
+ if(!newItem)
+ {
+ CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ CFDictionarySetValue(query, kSecUseKeychain, keychain);
+ CFDictionarySetValue(query, kSecClass, type);
+ CFDictionarySetValue(query, kSecValueRef, item);
+ CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
+
+ CFArrayRef added = 0;
+ OSStatus err = SecItemAdd(query, (CFTypeRef*)&added);
+ CFRelease(query);
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "Failure adding " << (type == kSecClassKey ? "key" : "certificate")
+ << " to keychain\n" << errorToString(err);
+ CertificateReadException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ newItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(added, 0);
+ CFRetain(newItem);
+ CFRelease(added);
+ }
+
+ assert(newItem);
+
+ return newItem;
+}
+
+//
+// Load keychain items (Certificates or Private Keys) from a file. On return items param contain
+// the list of items, the caller must release it.
+//
+void
+loadKeychainItems(CFArrayRef* items, CFTypeRef type, const string& file, const string& passphrase,
+ const PasswordPromptPtr& prompt, int passwordRetryMax)
+{
+ assert(type == kSecClassCertificate || type == kSecClassKey);
+ ScopedArray<char> buffer;
+ int length = readFile(file, buffer);
+ CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+ (const UInt8*)buffer.get(),
+ length,
+ kCFAllocatorNull);
+
+
+ SecExternalFormat format = kSecFormatUnknown;
+ SecExternalItemType itemType = type == kSecClassKey ? kSecItemTypePrivateKey : kSecItemTypeCertificate;
+
+ SecItemImportExportKeyParameters params;
+ memset(&params, 0, sizeof(params));
+ params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+ if(type == kSecClassKey)
+ {
+ params.flags |= kSecKeyNoAccessControl;
+
+ //
+ // If the application doesn't provide an password prompt configure
+ // the default OS X password prompt.
+ //
+ if(!prompt)
+ {
+ params.flags |= kSecKeySecurePassphrase;
+ ostringstream os;
+ os << "Enter the password for\n" << file;
+
+ params.alertPrompt = toCFString(os.str());
+ }
+ }
+
+ if(!passphrase.empty())
+ {
+ params.passphrase = toCFString(passphrase);
+ }
+ OSStatus err = SecItemImport(data, 0, &format, &itemType, 0, &params, 0, items);
+ if(params.passphrase)
+ {
+ CFRelease(params.passphrase);
+ }
+
+ if(prompt && err == errSecPassphraseRequired)
+ {
+ for(int i = 0; i < passwordRetryMax; ++i)
+ {
+ params.passphrase = toCFString(prompt->getPassword());
+ err = SecItemImport(data, 0, &format, &itemType, 0, &params, 0, items);
+ if(params.passphrase)
+ {
+ CFRelease(params.passphrase);
+ }
+
+ if(err != errSecPassphraseRequired && err != errSecInvalidData)
+ {
+ break;
+ }
+ }
+ }
+ if(params.alertPrompt)
+ {
+ CFRelease(params.alertPrompt);
+ }
+ CFRelease(data);
+
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "Error reading " << (type == kSecClassCertificate ? "certificate " : "private key ")
+ << "from file: `" << file << "'\n" << errorToString(err);
+ CertificateReadException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+}
+
+}
+
+//
+// Helper function to generate the private key label (display name) used
+// in the keychain.
+//
+string
+IceSSL::keyLabel(SecCertificateRef cert)
+{
+ CFStringRef commonName;
+ OSStatus err = SecCertificateCopyCommonName(cert, &commonName);
+ if(err != noErr)
+ {
+ ostringstream os;
+ os << "certificate error:\n" << errorToString(err);
+ CertificateReadException ex(__FILE__, __LINE__, os.str());
+ throw ex;
+ }
+ string label = fromCFString(commonName);
+ CFRelease(commonName);
+ return label.empty() ? "Imported Private Key" : (label + " - Private Key");
+}
+
+//
+// Imports a certificate private key and optionally add it to a keychain.
+//
+void
+IceSSL::loadPrivateKey(SecKeyRef* key, const string& label, CFDataRef hash, SecKeychainRef keychain,
+ const string& file, const string& passphrase, const PasswordPromptPtr& prompt,
+ int passwordRetryMax)
+{
+ assert(key);
+ CFArrayRef items = 0;
+ try
+ {
+ loadKeychainItems(&items, kSecClassKey, file, passphrase, prompt, passwordRetryMax);
+ if(items && CFArrayGetCount(items) > 0)
+ {
+ SecKeychainItemRef item = (SecKeychainItemRef)CFArrayGetValueAtIndex(items, 0);
+ assert(SecKeyGetTypeID() == CFGetTypeID(item));
+ CFRetain(item);
+ *key = (SecKeyRef)item;
+
+ CFRelease(items);
+ items = 0;
+
+ if(keychain)
+ {
+ SecKeychainItemRef newItem = addToKeychain(keychain, item, hash, kSecClassKey);
+ assert(newItem);
+ CFRelease(*key);
+ *key = (SecKeyRef)newItem;
+ if(hash)
+ {
+ //
+ // Create the association between the private key and the certificate,
+ // kSecKeyLabel attribute should match the subject key identifier.
+ //
+ SecKeychainAttribute attr;
+ attr.tag = kSecKeyLabel;
+ attr.data = (void*)CFDataGetBytePtr(hash);
+ attr.length = CFDataGetLength(hash);
+
+ SecKeychainAttributeList attrs;
+ attrs.attr = &attr;
+ attrs.count = 1;
+
+ SecKeychainItemModifyAttributesAndData(newItem, &attrs, 0, 0);
+ }
+
+ if(!label.empty())
+ {
+ //
+ // kSecKeyPrintName attribute correspond to the keychain display
+ // name.
+ //
+ SecKeychainAttribute att;
+ att.tag = kSecKeyPrintName;
+ att.data = (void*)label.c_str();
+ att.length = label.size();
+
+ SecKeychainAttributeList attrs;
+ attrs.attr = &att;
+ attrs.count = 1;
+
+ SecKeychainItemModifyAttributesAndData(newItem, &attrs, 0, 0);
+ }
+ }
+ }
+ }
+ catch(...)
+ {
+ if(hash)
+ {
+ CFRelease(hash);
+ hash = 0;
+ }
+
+ if(items)
+ {
+ CFRelease(items);
+ items = 0;
+ }
+
+ if(*key)
+ {
+ CFRelease(*key);
+ *key = 0;
+ }
+
+ throw;
+ }
+}
+
+//
+void
+IceSSL::loadCertificate(SecCertificateRef* cert, CFDataRef* hash, SecKeyRef* key, SecKeychainRef keychain,
+ const string& file, const string& passphrase, const PasswordPromptPtr& prompt,
+ int passwordRetryMax)
+{
+ assert(cert);
+ CFArrayRef items = 0;
+ try
+ {
+ loadKeychainItems(&items, kSecClassCertificate, file, passphrase, prompt, passwordRetryMax);
+ if(items && CFArrayGetCount(items) > 0)
+ {
+ SecKeychainItemRef item = (SecKeychainItemRef)CFArrayGetValueAtIndex(items, 0);
+ assert(SecCertificateGetTypeID() == CFGetTypeID(item));
+ CFRetain(item);
+ *cert = (SecCertificateRef)item;
+
+ CFRelease(items);
+ items = 0;
+
+ //
+ // Copy the public key hash, that is used when added the private key
+ // to create an association between the certificate and the corresponding
+ // private key.
+ //
+ if(hash)
+ {
+ *hash = getSubjectKeyIdentifier(*cert);
+
+ if(keychain)
+ {
+ SecKeychainItemRef newItem = addToKeychain(keychain, item, *hash, kSecClassCertificate);
+ assert(newItem);
+ CFRelease(*cert);
+ *cert = (SecCertificateRef)newItem;
+
+ }
+ }
+
+ if(key)
+ {
+ loadPrivateKey(key, keyLabel(*cert), hash ? *hash : 0, keychain, file, passphrase, prompt, passwordRetryMax);
+ }
+ }
+ }
+ catch(...)
+ {
+ if(*cert)
+ {
+ CFRelease(*cert);
+ *cert = 0;
+ }
+
+ if(*hash)
+ {
+ CFRelease(*hash);
+ *hash = 0;
+ }
+
+ if(items)
+ {
+ CFRelease(items);
+ items = 0;
+ }
+
+ if(key && *key)
+ {
+ CFRelease(*key);
+ *key = 0;
+ }
+
+ throw;
+ }
+}
+
+CFArrayRef
+IceSSL::loadCACertificates(const string& file, const string& passphrase, const PasswordPromptPtr& prompt,
+ int passwordRetryMax)
+{
+ CFArrayRef items = 0;
+ loadKeychainItems(&items, kSecClassCertificate, file, passphrase, prompt, passwordRetryMax);
+ CFMutableArrayRef certificateAuthorities = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ if(items)
+ {
+ for(CFIndex i = 0, size = CFArrayGetCount(items); i < size; ++i)
+ {
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(items, i);
+ if(isCA(cert))
+ {
+ CFArrayAppendValue(certificateAuthorities, cert);
+ }
+ }
+ CFRelease(items);
+ }
+ return certificateAuthorities;
+}
+
+#endif // End ICE_USE_OPENSSL
+
+bool
+IceSSL::checkPath(string& path, const string& defaultDir, bool dir)
+{
+ //
+ // Check if file exists. If not, try prepending the default
+ // directory and check again. If the path exists, the string
+ // argument is modified and true is returned. Otherwise
+ // false is returned.
+ //
+ IceUtilInternal::structstat st;
+ int err = IceUtilInternal::stat(path, &st);
+ if(err == 0)
+ {
+ return dir ? S_ISDIR(st.st_mode) != 0 : S_ISREG(st.st_mode) != 0;
+ }
+
+ if(!defaultDir.empty())
+ {
+ string s = defaultDir + IceUtilInternal::separator + path;
+ err = ::IceUtilInternal::stat(s.c_str(), &st);
+ if(err == 0 && ((!dir && S_ISREG(st.st_mode)) || (dir && S_ISDIR(st.st_mode))))
+ {
+ path = s;
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/cpp/src/IceSSL/Util.h b/cpp/src/IceSSL/Util.h
index a49aaf60927..0224f978a86 100644
--- a/cpp/src/IceSSL/Util.h
+++ b/cpp/src/IceSSL/Util.h
@@ -10,20 +10,29 @@
#ifndef ICE_SSL_UTIL_H
#define ICE_SSL_UTIL_H
+#include <IceSSL/Config.h>
#include <IceSSL/UtilF.h>
#include <Ice/Network.h>
#include <IceUtil/Mutex.h>
#include <IceUtil/Shared.h>
+#include <IceUtil/ScopedArray.h>
#include <IceSSL/Plugin.h>
#include <list>
-#include <openssl/ssl.h>
+#ifdef ICE_USE_OPENSSL
+# include <openssl/ssl.h>
+#else
+# include <Security/Security.h>
+# include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#ifdef ICE_USE_OPENSSL
namespace IceSSL
{
-#ifndef OPENSSL_NO_DH
+# ifndef OPENSSL_NO_DH
class DHParams : public IceUtil::Shared, public IceUtil::Mutex
{
public:
@@ -45,17 +54,72 @@ private:
DH* _dh2048;
DH* _dh4096;
};
-#endif
+# endif
//
-// Determine if a file or directory exists, with an optional default directory.
+// Accumulate the OpenSSL error stack into a string.
//
-bool checkPath(std::string&, const std::string&, bool);
+std::string getSslErrors(bool);
+
+}
+#elif defined(ICE_USE_SECURE_TRANSPORT)
+
+namespace IceSSL
+{
//
-// Accumulate the OpenSSL error stack into a string.
+// Helper functions to use by Secure Transport.
//
-std::string getSslErrors(bool);
+
+std::string fromCFString(CFStringRef);
+
+inline CFStringRef
+toCFString(const std::string& s)
+{
+ return CFStringCreateWithCString(NULL, s.c_str(), kCFStringEncodingUTF8);
+}
+
+std::string errorToString(CFErrorRef);
+
+std::string errorToString(OSStatus);
+
+//
+// Read a while file into memory buffer and return the number of bytes read.
+//
+int readFile(const std::string&, IceUtil::ScopedArray<char>&);
+
+
+std::string keyLabel(SecCertificateRef);
+
+//
+// Read a private key from an file and optionaly import into a keychain.
+//
+void loadPrivateKey(SecKeyRef*, const std::string&, CFDataRef, SecKeychainRef,
+ const std::string&, const std::string&, const PasswordPromptPtr&,
+ int);
+
+//
+// Read a certificate and key from an file and optionaly import then into a
+// keychain.
+//
+void loadCertificate(SecCertificateRef*, CFDataRef*, SecKeyRef*, SecKeychainRef,
+ const std::string&, const std::string& = "",
+ const PasswordPromptPtr& = 0, int = 0);
+
+CFArrayRef loadCACertificates(const std::string&, const std::string& = "", const PasswordPromptPtr& = 0,
+ int = 0);
+
+}
+
+#endif
+
+namespace IceSSL
+{
+
+//
+// Determine if a file or directory exists, with an optional default directory.
+//
+bool checkPath(std::string&, const std::string&, bool);
}
diff --git a/cpp/src/IceUtil/FileUtil.cpp b/cpp/src/IceUtil/FileUtil.cpp
index 89379f5f3b6..250abf105ea 100644
--- a/cpp/src/IceUtil/FileUtil.cpp
+++ b/cpp/src/IceUtil/FileUtil.cpp
@@ -23,6 +23,17 @@
using namespace std;
+namespace IceUtilInternal
+{
+#ifdef _WIN32
+const string pathsep = ";";
+const string separator = "\\";
+#else
+const string pathsep = ":";
+const string separator = "/";
+#endif
+}
+
//
// Determine if path is an absolute path
//
diff --git a/cpp/src/ca/iceca b/cpp/src/ca/iceca
index afb9b1d77a6..0d551890688 100755
--- a/cpp/src/ca/iceca
+++ b/cpp/src/ca/iceca
@@ -394,13 +394,13 @@ default_ca = ice\n\
\n\
[ ice ]\n\
default_days = 1825 # How long certs are valid.\n\
-default_md = md5 # The Message Digest type.\n\
+default_md = sha256 # The Message Digest type.\n\
preserve = no # Keep passed DN ordering?\n\
\n\
[ req ]\n\
default_bits = 2048\n\
default_keyfile = $ENV::ICE_CA_HOME/ca/db/ca_key.pem\n\
-default_md = md5\n\
+default_md = sha256\n\
prompt = no\n\
distinguished_name = dn\n\
x509_extensions = extensions\n\
@@ -440,7 +440,7 @@ serial = $dir/serial # The current serial number.\n\
certs = $dir # Where issued certs are kept.\n\
RANDFILE = $dir/.rand # Private random number file.\n\
default_days = 1825 # How long certs are valid.\n\
-default_md = md5 # The Message Digest type.\n\
+default_md = sha256 # The Message Digest type.\n\
preserve = yes # Keep passed DN ordering?\n\
\n\
policy = ca_policy\n\
@@ -471,7 +471,7 @@ authorityKeyIdentifier = keyid:always,issuer:always\n\
\n\
[ req ]\n\
default_bits = 1024\n\
-default_md = md5\n\
+default_md = sha256\n\
prompt = no\n\
distinguished_name = dn\n\
x509_extensions = extensions\n\
diff --git a/cpp/test/Ice/hash/Client.cpp b/cpp/test/Ice/hash/Client.cpp
index e9fc9f4b2c6..4dd5c152973 100644
--- a/cpp/test/Ice/hash/Client.cpp
+++ b/cpp/test/Ice/hash/Client.cpp
@@ -44,6 +44,8 @@ int main(int argc, char** argv)
// In Ice for WinRT IceSSL is part of Ice core.
//
id.properties->setProperty("Ice.Plugin.IceSSL", "IceSSL:createIceSSL");
+ id.properties->setProperty("IceSSL.Keychain", "client.keychain");
+ id.properties->setProperty("IceSSL.KeychainPassword", "password");
#endif
Ice::CommunicatorPtr communicator = Ice::initialize(id);
for(i = 0; proxyCollisions < maxCollisions &&
diff --git a/cpp/test/Ice/timeout/AllTests.cpp b/cpp/test/Ice/timeout/AllTests.cpp
index d53632860bd..f05e7697abe 100644
--- a/cpp/test/Ice/timeout/AllTests.cpp
+++ b/cpp/test/Ice/timeout/AllTests.cpp
@@ -247,7 +247,7 @@ allTests(const Ice::CommunicatorPtr& communicator)
initData.properties->setProperty("Ice.Override.Timeout", "250");
Ice::CommunicatorPtr comm = Ice::initialize(initData);
TimeoutPrx to = TimeoutPrx::checkedCast(comm->stringToProxy(sref));
- to->holdAdapter(500);
+ to->holdAdapter(1000);
try
{
ByteSeq seq(10000000);
diff --git a/cpp/test/Ice/timeout/Client.cpp b/cpp/test/Ice/timeout/Client.cpp
index d0df0c07416..130ad1f3280 100644
--- a/cpp/test/Ice/timeout/Client.cpp
+++ b/cpp/test/Ice/timeout/Client.cpp
@@ -50,7 +50,7 @@ main(int argc, char* argv[])
// We need to send messages large enough to cause the transport
// buffers to fill up.
//
- initData.properties->setProperty("Ice.MessageSizeMax", "10000");
+ initData.properties->setProperty("Ice.MessageSizeMax", "10000000");
communicator = Ice::initialize(argc, argv, initData);
status = run(argc, argv, communicator);
diff --git a/cpp/test/Ice/timeout/Server.cpp b/cpp/test/Ice/timeout/Server.cpp
index 3244621f13b..f9e7a363b41 100644
--- a/cpp/test/Ice/timeout/Server.cpp
+++ b/cpp/test/Ice/timeout/Server.cpp
@@ -43,6 +43,12 @@ main(int argc, char* argv[])
// This test kills connections, so we don't want warnings.
//
initData.properties->setProperty("Ice.Warn.Connections", "0");
+
+ //
+ // We need to send messages large enough to cause the transport
+ // buffers to fill up.
+ //
+ initData.properties->setProperty("Ice.MessageSizeMax", "10000000");
communicator = Ice::initialize(argc, argv, initData);
status = run(argc, argv, communicator);
diff --git a/cpp/test/IceGrid/session/Server.cpp b/cpp/test/IceGrid/session/Server.cpp
index d69e9de79b3..6d585f41762 100644
--- a/cpp/test/IceGrid/session/Server.cpp
+++ b/cpp/test/IceGrid/session/Server.cpp
@@ -44,10 +44,10 @@ public:
IceSSL::CertificatePtr cert = IceSSL::Certificate::decode(info.certs[0]);
test(cert->getIssuerDN() == IceSSL::DistinguishedName(
- "emailAddress=info@zeroc.com,CN=ZeroC Test CA,OU=Ice,O=ZeroC\\, Inc.,L=Palm Beach Gardens,"
- "ST=Florida,C=US"));
+ "emailAddress=info@zeroc.com,CN=ZeroC Test CA,OU=Ice,O=ZeroC\\, Inc.,L=Palm Beach Gardens,"
+ "ST=Florida,C=US"));
test(cert->getSubjectDN() == IceSSL::DistinguishedName(
- "CN=Client,emailAddress=info@zeroc.com,OU=Ice,O=ZeroC\\, Inc.,ST=Florida,C=US"));
+ "CN=Client,emailAddress=info@zeroc.com,OU=Ice,O=ZeroC\\, Inc.,ST=Florida,C=US"));
test(cert->checkValidity());
return true;
diff --git a/cpp/test/IceSSL/certs/dh_params1024.der b/cpp/test/IceSSL/certs/dh_params1024.der
new file mode 100644
index 00000000000..c389d364e4b
--- /dev/null
+++ b/cpp/test/IceSSL/certs/dh_params1024.der
Binary files differ
diff --git a/cpp/test/IceSSL/certs/dh_params512.der b/cpp/test/IceSSL/certs/dh_params512.der
new file mode 100644
index 00000000000..fce094731f9
--- /dev/null
+++ b/cpp/test/IceSSL/certs/dh_params512.der
Binary files differ
diff --git a/cpp/test/IceSSL/certs/makecerts b/cpp/test/IceSSL/certs/makecerts
index 496780f00bd..f7d188bf9c5 100755
--- a/cpp/test/IceSSL/certs/makecerts
+++ b/cpp/test/IceSSL/certs/makecerts
@@ -224,3 +224,14 @@ if ! [ -f dsaparam1024.pem ]; then
openssl ca -config client.cnf -batch -in $TMP/req.pem -out c_dsa_nopass_ca1_pub.pem \
-cert cacert1.pem -keyfile cakey1.pem
fi
+
+#
+# Generate DH parameters to use with OS X Secure Transport.
+#
+if ! [ -f dh_params512.der ]; then
+ openssl dhparam -outform DER -out dh_params512.der 512
+fi
+
+if ! [ -f dh_params1024.der ]; then
+ openssl dhparam -outform DER -out dh_params1024.der 1024
+fi
diff --git a/cpp/test/IceSSL/configuration/AllTests.cpp b/cpp/test/IceSSL/configuration/AllTests.cpp
index 97a84c62093..8b7dfa8af01 100644
--- a/cpp/test/IceSSL/configuration/AllTests.cpp
+++ b/cpp/test/IceSSL/configuration/AllTests.cpp
@@ -8,9 +8,11 @@
// **********************************************************************
#include <Ice/Ice.h>
+#include <IceUtil/FileUtil.h>
#include <IceSSL/Plugin.h>
#include <TestCommon.h>
#include <Test.h>
+#include <Util.h>
using namespace std;
using namespace Ice;
@@ -151,6 +153,13 @@ createClientProps(const Ice::PropertiesPtr& defaultProperties, const string& def
{
result->setProperty("Ice.Default.Host", defaultHost);
}
+#ifdef ICE_USE_SECURE_TRANSPORT
+ const string keychainName = "client.keychain";
+ const string keychainPassword = "password";
+ removeKeychain(keychainName, keychainPassword);
+ result->setProperty("IceSSL.Keychain", keychainName);
+ result->setProperty("IceSSL.KeychainPassword", keychainPassword);
+#endif
return result;
}
@@ -168,6 +177,10 @@ createServerProps(const Ice::PropertiesPtr& defaultProperties, const string& def
{
result["Ice.Default.Host"] = defaultHost;
}
+#ifdef ICE_USE_SECURE_TRANSPORT
+ result["IceSSL.Keychain"] = "server.keychain";
+ result["IceSSL.KeychainPassword"] = "password";
+#endif
return result;
}
@@ -214,7 +227,11 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
InitializationData initData;
initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
initData.properties->setProperty("Ice.InitPlugins", "0");
+#ifdef ICE_USE_OPENSSL
initData.properties->setProperty("IceSSL.Ciphers", "ADH");
+#else
+ initData.properties->setProperty("IceSSL.Ciphers", "DH_anon_WITH_AES_256_CBC_SHA");
+#endif
initData.properties->setProperty("IceSSL.VerifyPeer", "0");
CommunicatorPtr comm = initialize(initData);
PluginManagerPtr pm = comm->getPluginManager();
@@ -223,7 +240,11 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
test(obj);
Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(obj);
Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
+#ifdef ICE_USE_OPENSSL
d["IceSSL.Ciphers"] = "ADH";
+#else
+ d["IceSSL.Ciphers"] = "DH_anon_WITH_AES_256_CBC_SHA";
+#endif
d["IceSSL.VerifyPeer"] = "0";
Test::ServerPrx server = fact->createServer(d);
try
@@ -256,6 +277,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
CommunicatorPtr comm = initialize(initData);
Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
test(fact);
+
Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
d["IceSSL.CertAuthFile"] = "cacert1.pem";
d["IceSSL.CertFile"] = "s_rsa_nopass_ca1_pub.pem";
@@ -323,7 +345,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
{
// Expected.
}
-#ifdef _WIN32
+#if defined(_WIN32) || defined(ICE_USE_SECURE_TRANSPORT)
catch(const ConnectionLostException&)
{
// Expected.
@@ -378,9 +400,9 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
test(caCert->checkValidity());
test(!caCert->checkValidity(IceUtil::Time::seconds(0)));
- test(!serverCert->verify(serverCert->getPublicKey()));
- test(serverCert->verify(caCert->getPublicKey()));
- test(caCert->verify(caCert->getPublicKey()));
+ test(!serverCert->verify(serverCert));
+ test(serverCert->verify(caCert));
+ test(caCert->verify(caCert));
IceSSL::NativeConnectionInfoPtr info =
IceSSL::NativeConnectionInfoPtr::dynamicCast(server->ice_getConnection()->getInfo());
@@ -396,7 +418,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
test(info->nativeCerts[0]->checkValidity() && info->nativeCerts[1]->checkValidity());
test(!info->nativeCerts[0]->checkValidity(IceUtil::Time::seconds(0)) &&
!info->nativeCerts[1]->checkValidity(IceUtil::Time::seconds(0)));
- test(info->nativeCerts[0]->verify(info->nativeCerts[1]->getPublicKey()));
+ test(info->nativeCerts[0]->verify(info->nativeCerts[1]));
test(info->nativeCerts.size() == 2 &&
info->nativeCerts[0]->getSubjectDN() == serverCert->getSubjectDN() &&
info->nativeCerts[0]->getIssuerDN() == serverCert->getIssuerDN());
@@ -456,7 +478,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
{
// Expected.
}
-#ifdef _WIN32
+#if defined(_WIN32) || defined(ICE_USE_SECURE_TRANSPORT)
catch(const ConnectionLostException&)
{
// Expected.
@@ -501,7 +523,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
{
// Expected.
}
-#ifdef _WIN32
+#if defined(_WIN32) || defined(ICE_USE_SECURE_TRANSPORT)
catch(const ConnectionLostException&)
{
// Expected.
@@ -509,7 +531,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
#endif
catch(const LocalException&)
{
- test(false);
+ test(false);
}
fact->destroyServer(server);
@@ -650,7 +672,11 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
//
InitializationData initData;
initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
+#ifdef ICE_USE_OPENSSL
initData.properties->setProperty("IceSSL.Ciphers", "ADH");
+#else
+ initData.properties->setProperty("IceSSL.Ciphers", "(DH_anon*)");
+#endif
initData.properties->setProperty("IceSSL.VerifyPeer", "0");
CommunicatorPtr comm = initialize(initData);
IceSSL::PluginPtr plugin = IceSSL::PluginPtr::dynamicCast(comm->getPluginManager()->getPlugin("IceSSL"));
@@ -661,12 +687,17 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
test(fact);
Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
+#ifdef ICE_USE_OPENSSL
+ string cipherSub = "ADH-";
d["IceSSL.Ciphers"] = "ADH";
+#else
+ string cipherSub = "DH_anon";
+ d["IceSSL.Ciphers"] = "(DH_anon*)";
+#endif
d["IceSSL.VerifyPeer"] = "0";
Test::ServerPrx server = fact->createServer(d);
try
{
- string cipherSub = "ADH-";
server->checkCipher(cipherSub);
IceSSL::NativeConnectionInfoPtr info =
IceSSL::NativeConnectionInfoPtr::dynamicCast(server->ice_getConnection()->getInfo());
@@ -744,8 +775,10 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
}
cout << "ok" << endl;
+
cout << "testing protocols... " << flush;
{
+#ifndef ICE_USE_SECURE_TRANSPORT
//
// This should fail because the client and server have no protocol
// in common.
@@ -804,9 +837,72 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
}
fact->destroyServer(server);
comm->destroy();
+#else
+ //
+ // This should fail because the client and server have no protocol
+ // in common.
+ //
+ InitializationData initData;
+ initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
+ initData.properties->setProperty("IceSSL.Ciphers", "(DH_anon*)");
+ initData.properties->setProperty("IceSSL.VerifyPeer", "0");
+ initData.properties->setProperty("IceSSL.ProtocolVersionMax", "ssl3");
+ initData.properties->setProperty("IceSSL.ProtocolVersionMin", "ssl3");
+ CommunicatorPtr comm = initialize(initData);
+ Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
+ test(fact);
+ Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
+ d["IceSSL.Ciphers"] = "(DH_anon*)";
+ d["IceSSL.VerifyPeer"] = "0";
+ d["IceSSL.ProtocolVersionMax"] = "tls1_2";
+ d["IceSSL.ProtocolVersionMin"] = "tls1_2";
+ Test::ServerPrx server = fact->createServer(d);
+ try
+ {
+ server->ice_ping();
+ test(false);
+ }
+ catch(const ProtocolException&)
+ {
+ // Expected on some platforms.
+ }
+ catch(const ConnectionLostException&)
+ {
+ // Expected on some platforms.
+ }
+ catch(const LocalException&)
+ {
+ test(false);
+ }
+ fact->destroyServer(server);
+ comm->destroy();
+
+ //
+ // This should succeed.
+ //
+ comm = initialize(initData);
+ fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
+ test(fact);
+ d = createServerProps(defaultProperties, defaultDir, defaultHost);
+ d["IceSSL.Ciphers"] = "(DH_anon*)";
+ d["IceSSL.VerifyPeer"] = "0";
+ d["IceSSL.ProtocolVersionMax"] = "tls1";
+ d["IceSSL.ProtocolVersionMin"] = "ssl3";
+ server = fact->createServer(d);
+ try
+ {
+ server->ice_ping();
+ }
+ catch(const LocalException&)
+ {
+ test(false);
+ }
+ fact->destroyServer(server);
+ comm->destroy();
+#endif
}
cout << "ok" << endl;
-
+
cout << "testing expired certificates... " << flush;
{
//
@@ -840,7 +936,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
{
// Expected.
}
-#ifdef _WIN32
+#if defined(_WIN32) || defined(ICE_USE_SECURE_TRANSPORT)
catch(const ConnectionLostException&)
{
// Expected.
@@ -862,6 +958,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
IceSSL::Certificate::load(defaultDir + "/c_rsa_nopass_ca1_exp_pub.pem");
test(!cert->checkValidity());
}
+ initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
initData.properties->setProperty("IceSSL.CertAuthFile", "cacert1.pem");
initData.properties->setProperty("IceSSL.CertFile", "c_rsa_nopass_ca1_exp_pub.pem");
initData.properties->setProperty("IceSSL.KeyFile", "c_rsa_nopass_ca1_exp_priv.pem");
@@ -882,7 +979,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
{
// Expected.
}
-#ifdef _WIN32
+#if defined(_WIN32) || defined(ICE_USE_SECURE_TRANSPORT)
catch(const ConnectionLostException&)
{
// Expected.
@@ -985,6 +1082,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
try
{
pm->initializePlugins();
+ test(false);
}
catch(const PluginInitializationException&)
{
@@ -1008,7 +1106,11 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
//
InitializationData initData;
initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
+#ifdef ICE_USE_OPENSSL
initData.properties->setProperty("IceSSL.Ciphers", "ADH");
+#else
+ initData.properties->setProperty("IceSSL.Ciphers", "(DH_anon*)");
+#endif
CommunicatorPtr comm = initialize(initData);
Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
test(fact);
@@ -1016,12 +1118,17 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
d["IceSSL.CertAuthFile"] = "cacert1.pem";
d["IceSSL.CertFile"] = "s_rsa_nopass_ca1_pub.pem";
d["IceSSL.KeyFile"] = "s_rsa_nopass_ca1_priv.pem";
+#ifdef ICE_USE_OPENSSL
+ string cipherSub = "ADH-";
d["IceSSL.Ciphers"] = "RSA:ADH";
+#else
+ string cipherSub = "DH_";
+ d["IceSSL.Ciphers"] = "(RSA_*) (DH_anon*)";
+#endif
d["IceSSL.VerifyPeer"] = "1";
Test::ServerPrx server = fact->createServer(d);
try
{
- string cipherSub = "ADH-";
server->checkCipher(cipherSub);
IceSSL::NativeConnectionInfoPtr info =
IceSSL::NativeConnectionInfoPtr::dynamicCast(server->ice_getConnection()->getInfo());
@@ -1035,6 +1142,68 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
comm->destroy();
}
+#ifdef ICE_USE_SECURE_TRANSPORT
+ {
+ //
+ // Test IceSSL.DHParams
+ //
+ InitializationData initData;
+ initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
+ initData.properties->setProperty("IceSSL.Ciphers", "(DH_anon*)");
+ CommunicatorPtr comm = initialize(initData);
+ Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
+ test(fact);
+ Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
+ d["IceSSL.Ciphers"] = "(DH_anon*)";
+ d["IceSSL.DHParams"] = "dh_params512.der";
+ d["IceSSL.VerifyPeer"] = "0";
+ Test::ServerPrx server = fact->createServer(d);
+ try
+ {
+ server->checkCipher("DH_anon");
+ }
+ catch(const LocalException& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
+ fact->destroyServer(server);
+ comm->destroy();
+ }
+
+ {
+ //
+ // Test IceSSL.DHParams
+ //
+ InitializationData initData;
+ initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
+ initData.properties->setProperty("IceSSL.Ciphers", "(DH_anon*)");
+ CommunicatorPtr comm = initialize(initData);
+ Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
+ test(fact);
+ Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
+ d["IceSSL.Ciphers"] = "(DH_anon*)";
+ d["IceSSL.DHParams"] = "dh_params1024.der";
+ d["IceSSL.VerifyPeer"] = "0";
+ Test::ServerPrx server = fact->createServer(d);
+ try
+ {
+ server->checkCipher("DH_anon");
+ }
+ catch(const LocalException& ex)
+ {
+ cerr << ex << endl;
+ test(false);
+ }
+ fact->destroyServer(server);
+ comm->destroy();
+ }
+#endif
+
+//
+// No DSA support in Secure Transport.
+//
+#ifndef ICE_USE_SECURE_TRANSPORT
{
//
// Configure a server with RSA and DSA certificates.
@@ -1154,12 +1323,12 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
{
// Expected.
}
-#ifdef _WIN32
+# ifdef _WIN32
catch(const ConnectionLostException&)
{
// Expected.
}
-#endif
+# endif
catch(const LocalException& ex)
{
cerr << ex << endl;
@@ -1168,6 +1337,7 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
fact->destroyServer(server);
comm->destroy();
}
+#endif
cout << "ok" << endl;
cout << "testing IceSSL.TrustOnly... " << flush;
@@ -1643,14 +1813,22 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
InitializationData initData;
initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
CommunicatorPtr comm = initialize(initData);
+#ifdef ICE_USE_OPENSSL
initData.properties->setProperty("IceSSL.Ciphers", "ADH");
+#else
+ initData.properties->setProperty("IceSSL.Ciphers", "(DH_anon*)");
+#endif
initData.properties->setProperty("IceSSL.VerifyPeer", "0");
Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
test(fact);
Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
d["IceSSL.TrustOnly"] = "C=US, ST=Florida, O=ZeroC\\, Inc.,OU=Ice, emailAddress=info@zeroc.com, CN=Client";
+#ifdef ICE_USE_OPENSSL
d["IceSSL.Ciphers"] = "ADH";
+#else
+ d["IceSSL.Ciphers"] = "(DH_anon*)";
+#endif
d["IceSSL.VerifyPeer"] = "0";
Test::ServerPrx server = fact->createServer(d);
try
@@ -1671,14 +1849,22 @@ allTests(const CommunicatorPtr& communicator, const string& testDir)
InitializationData initData;
initData.properties = createClientProps(defaultProperties, defaultDir, defaultHost);
CommunicatorPtr comm = initialize(initData);
+#ifdef ICE_USE_OPENSSL
initData.properties->setProperty("IceSSL.Ciphers", "ADH");
+#else
+ initData.properties->setProperty("IceSSL.Ciphers", "(DH_anon*)");
+#endif
initData.properties->setProperty("IceSSL.VerifyPeer", "0");
Test::ServerFactoryPrx fact = Test::ServerFactoryPrx::checkedCast(comm->stringToProxy(factoryRef));
test(fact);
Test::Properties d = createServerProps(defaultProperties, defaultDir, defaultHost);
d["IceSSL.TrustOnly"] = "!C=US, ST=Florida, O=ZeroC\\, Inc.,OU=Ice, emailAddress=info@zeroc.com, CN=Client";
+#ifdef ICE_USE_OPENSSL
d["IceSSL.Ciphers"] = "ADH";
+#else
+ d["IceSSL.Ciphers"] = "(DH_anon*)";
+#endif
d["IceSSL.VerifyPeer"] = "0";
Test::ServerPrx server = fact->createServer(d);
try
diff --git a/cpp/test/IceSSL/configuration/Makefile b/cpp/test/IceSSL/configuration/Makefile
index ff8a2c9091d..b0c096e4731 100644
--- a/cpp/test/IceSSL/configuration/Makefile
+++ b/cpp/test/IceSSL/configuration/Makefile
@@ -33,12 +33,16 @@ include $(top_srcdir)/config/Make.rules
CPPFLAGS := -I. -I../../include $(CPPFLAGS)
+ifeq ($(UNAME),Darwin)
+LINK_WITH = -framework Security -framework CoreFoundation
+endif
+
$(CLIENT): $(COBJS)
rm -f $@
- $(call mktest,$@,$(COBJS),$(ICESSL_LIBS) $(LIBS))
+ $(call mktest,$@,$(COBJS),$(ICESSL_LIBS) $(LINK_WITH) $(LIBS))
$(SERVER): $(SOBJS)
rm -f $@
- $(call mktest,$@,$(SOBJS),$(ICESSL_LIBS) $(LIBS))
+ $(call mktest,$@,$(SOBJS),$(ICESSL_LIBS) $(LINK_WITH) $(LIBS))
include .depend
diff --git a/cpp/test/IceSSL/configuration/TestI.cpp b/cpp/test/IceSSL/configuration/TestI.cpp
index f24f506c159..151f141ad1e 100644
--- a/cpp/test/IceSSL/configuration/TestI.cpp
+++ b/cpp/test/IceSSL/configuration/TestI.cpp
@@ -12,6 +12,7 @@
#include <TestI.h>
#include <TestCommon.h>
#include <IceSSL/Plugin.h>
+#include <Util.h>
using namespace std;
using namespace Ice;
@@ -68,7 +69,11 @@ ServerI::checkCipher(const string& cipher, const Ice::Current& c)
void
ServerI::destroy()
{
+ string defaultDir = _communicator->getProperties()->getProperty("IceSSL.DefaultDir");
_communicator->destroy();
+#ifdef ICE_USE_SECURE_TRANSPORT
+ removeKeychain("server.keychain", "password");
+#endif
}
Test::ServerPrx
diff --git a/cpp/test/IceSSL/configuration/Util.h b/cpp/test/IceSSL/configuration/Util.h
new file mode 100644
index 00000000000..a34d17cc87c
--- /dev/null
+++ b/cpp/test/IceSSL/configuration/Util.h
@@ -0,0 +1,37 @@
+
+#include <IceSSL/IceSSL.h>
+
+#ifdef ICE_USE_SECURE_TRANSPORT
+
+#include <IceUtil/FileUtil.h>
+#include <Security/Security.h>
+
+void
+removeKeychain(const std::string& keychainPath, const std::string& password)
+{
+ //
+ // KeyChain path is relative to the current working directory.
+ //
+ std::string path = keychainPath;
+ if(!IceUtilInternal::isAbsolutePath(keychainPath))
+ {
+ std::string cwd;
+ if(IceUtilInternal::getcwd(cwd) == 0)
+ {
+ path = std::string(cwd) + '/' + path;
+ }
+ }
+
+ SecKeychainRef keychain;
+ OSStatus err = SecKeychainOpen(path.c_str(), &keychain);
+ if(err == noErr)
+ {
+ err = SecKeychainUnlock(keychain, password.size(), password.c_str(), true);
+ if(err == noErr)
+ {
+ err = SecKeychainDelete(keychain);
+ }
+ CFRelease(keychain);
+ }
+}
+#endif \ No newline at end of file
diff --git a/cs/src/Ice/PropertyNames.cs b/cs/src/Ice/PropertyNames.cs
index 9d5f5b7d85b..10c2ccdd18a 100644
--- a/cs/src/Ice/PropertyNames.cs
+++ b/cs/src/Ice/PropertyNames.cs
@@ -6,7 +6,7 @@
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
-// Generated by makeprops.py from file ./config/PropertyNames.xml, Wed Jun 4 19:01:29 2014
+// Generated by makeprops.py from file ../config/PropertyNames.xml, Thu Jun 5 21:19:31 2014
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
@@ -111,8 +111,7 @@ namespace IceInternal
new Property(@"^Ice\.IPv6$", false, null),
new Property(@"^Ice\.EventLog\.Source$", false, null),
new Property(@"^Ice\.FactoryAssemblies$", false, null),
- new Property(@"^Ice\.GC$", false, null),
- new Property(@"^Ice\.GC\.Interval$", true, @"Ice.GC"),
+ new Property(@"^Ice\.CollectObjects$", false, null),
new Property(@"^Ice\.ImplicitContext$", false, null),
new Property(@"^Ice\.InitPlugins$", false, null),
new Property(@"^Ice\.LogFile$", false, null),
@@ -157,7 +156,6 @@ namespace IceInternal
new Property(@"^Ice\.ThreadPool\.Server\.ThreadPriority$", false, null),
new Property(@"^Ice\.ThreadPriority$", false, null),
new Property(@"^Ice\.Trace\.Admin\.Properties$", false, null),
- new Property(@"^Ice\.Trace\.GC$", true, null),
new Property(@"^Ice\.Trace\.Locator$", false, null),
new Property(@"^Ice\.Trace\.Network$", false, null),
new Property(@"^Ice\.Trace\.Protocol$", false, null),
@@ -816,12 +814,15 @@ namespace IceInternal
new Property(@"^IceSSL\.Ciphers$", false, null),
new Property(@"^IceSSL\.DefaultDir$", false, null),
new Property(@"^IceSSL\.DH\.[^\s]+$", false, null),
+ new Property(@"^IceSSL\.DHParams$", false, null),
new Property(@"^IceSSL\.EntropyDaemon$", false, null),
new Property(@"^IceSSL\.FindCert\.[^\s]+$", false, null),
new Property(@"^IceSSL\.ImportCert\.[^\s]+$", false, null),
new Property(@"^IceSSL\.InitOpenSSL$", false, null),
new Property(@"^IceSSL\.KeyFile$", false, null),
new Property(@"^IceSSL\.KeySet$", false, null),
+ new Property(@"^IceSSL\.Keychain$", false, null),
+ new Property(@"^IceSSL\.KeychainPassword$", false, null),
new Property(@"^IceSSL\.Keystore$", false, null),
new Property(@"^IceSSL\.KeystorePassword$", false, null),
new Property(@"^IceSSL\.KeystoreType$", false, null),
@@ -830,6 +831,8 @@ namespace IceInternal
new Property(@"^IceSSL\.PasswordRetryMax$", false, null),
new Property(@"^IceSSL\.PersistKeySet$", false, null),
new Property(@"^IceSSL\.Protocols$", false, null),
+ new Property(@"^IceSSL\.ProtocolVersionMax$", false, null),
+ new Property(@"^IceSSL\.ProtocolVersionMin$", false, null),
new Property(@"^IceSSL\.Random$", false, null),
new Property(@"^IceSSL\.Trace\.Security$", false, null),
new Property(@"^IceSSL\.TrustOnly$", false, null),
diff --git a/java/src/IceInternal/PropertyNames.java b/java/src/IceInternal/PropertyNames.java
index 9859bfcac97..51aaf7ee700 100644
--- a/java/src/IceInternal/PropertyNames.java
+++ b/java/src/IceInternal/PropertyNames.java
@@ -6,7 +6,7 @@
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
-// Generated by makeprops.py from file ./config/PropertyNames.xml, Wed Jun 4 19:01:29 2014
+// Generated by makeprops.py from file ../config/PropertyNames.xml, Thu Jun 5 21:19:31 2014
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
@@ -111,8 +111,7 @@ public final class PropertyNames
new Property("Ice\\.IPv6", false, null),
new Property("Ice\\.EventLog\\.Source", false, null),
new Property("Ice\\.FactoryAssemblies", false, null),
- new Property("Ice\\.GC", false, null),
- new Property("Ice\\.GC\\.Interval", true, "Ice.GC"),
+ new Property("Ice\\.CollectObjects", false, null),
new Property("Ice\\.ImplicitContext", false, null),
new Property("Ice\\.InitPlugins", false, null),
new Property("Ice\\.LogFile", false, null),
@@ -157,7 +156,6 @@ public final class PropertyNames
new Property("Ice\\.ThreadPool\\.Server\\.ThreadPriority", false, null),
new Property("Ice\\.ThreadPriority", false, null),
new Property("Ice\\.Trace\\.Admin\\.Properties", false, null),
- new Property("Ice\\.Trace\\.GC", true, null),
new Property("Ice\\.Trace\\.Locator", false, null),
new Property("Ice\\.Trace\\.Network", false, null),
new Property("Ice\\.Trace\\.Protocol", false, null),
@@ -816,12 +814,15 @@ public final class PropertyNames
new Property("IceSSL\\.Ciphers", false, null),
new Property("IceSSL\\.DefaultDir", false, null),
new Property("IceSSL\\.DH\\.[^\\s]+", false, null),
+ new Property("IceSSL\\.DHParams", false, null),
new Property("IceSSL\\.EntropyDaemon", false, null),
new Property("IceSSL\\.FindCert\\.[^\\s]+", false, null),
new Property("IceSSL\\.ImportCert\\.[^\\s]+", false, null),
new Property("IceSSL\\.InitOpenSSL", false, null),
new Property("IceSSL\\.KeyFile", false, null),
new Property("IceSSL\\.KeySet", false, null),
+ new Property("IceSSL\\.Keychain", false, null),
+ new Property("IceSSL\\.KeychainPassword", false, null),
new Property("IceSSL\\.Keystore", false, null),
new Property("IceSSL\\.KeystorePassword", false, null),
new Property("IceSSL\\.KeystoreType", false, null),
@@ -830,6 +831,8 @@ public final class PropertyNames
new Property("IceSSL\\.PasswordRetryMax", false, null),
new Property("IceSSL\\.PersistKeySet", false, null),
new Property("IceSSL\\.Protocols", false, null),
+ new Property("IceSSL\\.ProtocolVersionMax", false, null),
+ new Property("IceSSL\\.ProtocolVersionMin", false, null),
new Property("IceSSL\\.Random", false, null),
new Property("IceSSL\\.Trace\\.Security", false, null),
new Property("IceSSL\\.TrustOnly", false, null),
diff --git a/js/src/Ice/PropertyNames.js b/js/src/Ice/PropertyNames.js
index 6dd789a3b42..2584cb90ea1 100644
--- a/js/src/Ice/PropertyNames.js
+++ b/js/src/Ice/PropertyNames.js
@@ -6,7 +6,7 @@
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
-// Generated by makeprops.py from file ./config/PropertyNames.xml, Wed Jun 4 19:01:29 2014
+// Generated by makeprops.py from file ../config/PropertyNames.xml, Thu Jun 5 21:19:31 2014
// IMPORTANT: Do not edit this file -- any edits made here will be lost!
@@ -114,8 +114,7 @@
new Property("/^Ice\.IPv6/", false, null),
new Property("/^Ice\.EventLog\.Source/", false, null),
new Property("/^Ice\.FactoryAssemblies/", false, null),
- new Property("/^Ice\.GC/", false, null),
- new Property("/^Ice\.GC\.Interval/", true, "Ice.GC"),
+ new Property("/^Ice\.CollectObjects/", false, null),
new Property("/^Ice\.ImplicitContext/", false, null),
new Property("/^Ice\.InitPlugins/", false, null),
new Property("/^Ice\.LogFile/", false, null),
@@ -160,7 +159,6 @@
new Property("/^Ice\.ThreadPool\.Server\.ThreadPriority/", false, null),
new Property("/^Ice\.ThreadPriority/", false, null),
new Property("/^Ice\.Trace\.Admin\.Properties/", false, null),
- new Property("/^Ice\.Trace\.GC/", true, null),
new Property("/^Ice\.Trace\.Locator/", false, null),
new Property("/^Ice\.Trace\.Network/", false, null),
new Property("/^Ice\.Trace\.Protocol/", false, null),
diff --git a/py/demo/Glacier2/callback/config.client b/py/demo/Glacier2/callback/config.client
index 58e513140d6..57e516d4668 100644
--- a/py/demo/Glacier2/callback/config.client
+++ b/py/demo/Glacier2/callback/config.client
@@ -56,3 +56,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
diff --git a/py/demo/Glacier2/callback/config.glacier2 b/py/demo/Glacier2/callback/config.glacier2
index cd9075b4e8a..aa737517f5c 100644
--- a/py/demo/Glacier2/callback/config.glacier2
+++ b/py/demo/Glacier2/callback/config.glacier2
@@ -126,3 +126,6 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=glacier2.keychain
+IceSSL.KeychainPassword=password
+
diff --git a/py/demo/Ice/callback/config.client b/py/demo/Ice/callback/config.client
index 5adf6dba22d..585386d09c1 100644
--- a/py/demo/Ice/callback/config.client
+++ b/py/demo/Ice/callback/config.client
@@ -50,3 +50,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password \ No newline at end of file
diff --git a/py/demo/Ice/callback/config.server b/py/demo/Ice/callback/config.server
index ad65f43d4d8..98b8830645a 100644
--- a/py/demo/Ice/callback/config.server
+++ b/py/demo/Ice/callback/config.server
@@ -44,3 +44,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password \ No newline at end of file
diff --git a/py/demo/Ice/hello/config.client b/py/demo/Ice/hello/config.client
index 45f24989be0..5c412eddd05 100644
--- a/py/demo/Ice/hello/config.client
+++ b/py/demo/Ice/hello/config.client
@@ -53,6 +53,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/py/demo/Ice/hello/config.server b/py/demo/Ice/hello/config.server
index 01ed3ded598..1607ee2367c 100644
--- a/py/demo/Ice/hello/config.server
+++ b/py/demo/Ice/hello/config.server
@@ -49,6 +49,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
#
# For secure web sockets we need to disable VerifyPeer.
diff --git a/py/demo/Ice/latency/config.client b/py/demo/Ice/latency/config.client
index f88fdf8f932..9d45b40b231 100644
--- a/py/demo/Ice/latency/config.client
+++ b/py/demo/Ice/latency/config.client
@@ -29,6 +29,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/py/demo/Ice/latency/config.server b/py/demo/Ice/latency/config.server
index 745da939068..b5b63fa5fa0 100644
--- a/py/demo/Ice/latency/config.server
+++ b/py/demo/Ice/latency/config.server
@@ -22,6 +22,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
#
# For secure web sockets we need to disable VerifyPeer.
diff --git a/py/demo/Ice/properties/config.client b/py/demo/Ice/properties/config.client
index 8b079dfc267..db41ebb2459 100644
--- a/py/demo/Ice/properties/config.client
+++ b/py/demo/Ice/properties/config.client
@@ -49,3 +49,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password \ No newline at end of file
diff --git a/py/demo/Ice/properties/config.server b/py/demo/Ice/properties/config.server
index 3fae2c52d4d..2969290fd56 100644
--- a/py/demo/Ice/properties/config.server
+++ b/py/demo/Ice/properties/config.server
@@ -59,3 +59,5 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
diff --git a/py/demo/Ice/throughput/config.client b/py/demo/Ice/throughput/config.client
index 0ec65d10bbe..121898e30eb 100644
--- a/py/demo/Ice/throughput/config.client
+++ b/py/demo/Ice/throughput/config.client
@@ -29,6 +29,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/py/demo/Ice/throughput/config.server b/py/demo/Ice/throughput/config.server
index 8a57efbe27b..1e1182633ac 100644
--- a/py/demo/Ice/throughput/config.server
+++ b/py/demo/Ice/throughput/config.server
@@ -23,6 +23,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=s_rsa1024_pub.pem
IceSSL.KeyFile=s_rsa1024_priv.pem
+IceSSL.Keychain=server.keychain
+IceSSL.KeychainPassword=password
#
# For secure web sockets we need to disable VerifyPeer.
diff --git a/py/test/Ice/timeout/AllTests.py b/py/test/Ice/timeout/AllTests.py
index 74fde1c929b..b5df795245a 100644
--- a/py/test/Ice/timeout/AllTests.py
+++ b/py/test/Ice/timeout/AllTests.py
@@ -92,7 +92,7 @@ def allTests(communicator, collocated):
else:
seq = bytes([0 for x in range(0, 10000000)])
to = Test.TimeoutPrx.uncheckedCast(obj.ice_timeout(250))
- to.holdAdapter(500)
+ to.holdAdapter(1000)
try:
to.sendData(seq)
test(False)
@@ -208,9 +208,9 @@ def allTests(communicator, collocated):
#
initData = Ice.InitializationData()
initData.properties = communicator.getProperties().clone()
- initData.properties.setProperty("Ice.Override.ConnectTimeout", "250")
+ initData.properties.setProperty("Ice.Override.ConnectTimeout", "500")
comm = Ice.initialize(initData)
- timeout.holdAdapter(500)
+ timeout.holdAdapter(750)
to = Test.TimeoutPrx.uncheckedCast(comm.stringToProxy(sref))
try:
to.op()
@@ -221,8 +221,8 @@ def allTests(communicator, collocated):
# Calling ice_timeout() should have no effect on the connect timeout.
#
timeout.op() # Ensure adapter is active.
- timeout.holdAdapter(500)
- to = Test.TimeoutPrx.uncheckedCast(to.ice_timeout(750))
+ timeout.holdAdapter(750)
+ to = Test.TimeoutPrx.uncheckedCast(to.ice_timeout(1000))
try:
to.op()
test(False)
@@ -232,8 +232,8 @@ def allTests(communicator, collocated):
# Verify that timeout set via ice_timeout() is still used for requests.
#
to.op() # Force connection.
- timeout.holdAdapter(500);
- to = Test.TimeoutPrx.uncheckedCast(to.ice_timeout(250));
+ timeout.holdAdapter(750);
+ to = Test.TimeoutPrx.uncheckedCast(to.ice_timeout(500));
try:
to.sendData(seq)
test(False)
diff --git a/py/test/Ice/timeout/Client.py b/py/test/Ice/timeout/Client.py
index 71113828f45..1114f12c75c 100755
--- a/py/test/Ice/timeout/Client.py
+++ b/py/test/Ice/timeout/Client.py
@@ -40,7 +40,7 @@ try:
# We need to send messages large enough to cause the transport
# buffers to fill up.
#
- initData.properties.setProperty("Ice.MessageSizeMax", "10000");
+ initData.properties.setProperty("Ice.MessageSizeMax", "10000000");
#
# For this test, we want to disable retries.
diff --git a/rb/demo/Ice/hello/config.client b/rb/demo/Ice/hello/config.client
index c71a06aa5a0..b573693537b 100644
--- a/rb/demo/Ice/hello/config.client
+++ b/rb/demo/Ice/hello/config.client
@@ -43,6 +43,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/rb/demo/Ice/latency/config.client b/rb/demo/Ice/latency/config.client
index bbe9ec81b88..c140ea09eab 100644
--- a/rb/demo/Ice/latency/config.client
+++ b/rb/demo/Ice/latency/config.client
@@ -17,6 +17,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/rb/demo/Ice/throughput/config.client b/rb/demo/Ice/throughput/config.client
index b32876fb71f..6e969c7cf54 100644
--- a/rb/demo/Ice/throughput/config.client
+++ b/rb/demo/Ice/throughput/config.client
@@ -17,6 +17,8 @@ IceSSL.DefaultDir=../../../../certs
IceSSL.CertAuthFile=cacert.pem
IceSSL.CertFile=c_rsa1024_pub.pem
IceSSL.KeyFile=c_rsa1024_priv.pem
+IceSSL.Keychain=client.keychain
+IceSSL.KeychainPassword=password
#
# IceMX configuration.
diff --git a/rb/test/Ice/timeout/AllTests.rb b/rb/test/Ice/timeout/AllTests.rb
index 401e7362bb8..db9288c7769 100644
--- a/rb/test/Ice/timeout/AllTests.rb
+++ b/rb/test/Ice/timeout/AllTests.rb
@@ -152,9 +152,9 @@ def allTests(communicator)
#
initData = Ice::InitializationData.new
initData.properties = communicator.getProperties().clone()
- initData.properties.setProperty("Ice.Override.ConnectTimeout", "250")
+ initData.properties.setProperty("Ice.Override.ConnectTimeout", "500")
comm = Ice.initialize(initData)
- timeout.holdAdapter(500)
+ timeout.holdAdapter(1000)
to = Test::TimeoutPrx::uncheckedCast(comm.stringToProxy(sref))
begin
to.op()
@@ -167,8 +167,8 @@ def allTests(communicator)
# Calling ice_timeout() should have no effect on the connect timeout.
#
timeout.op() # Ensure adapter is active.
- timeout.holdAdapter(500)
- to = Test::TimeoutPrx::uncheckedCast(to.ice_timeout(750))
+ timeout.holdAdapter(750)
+ to = Test::TimeoutPrx::uncheckedCast(to.ice_timeout(1000))
begin
to.op()
test(false)
@@ -180,8 +180,8 @@ def allTests(communicator)
# Verify that timeout set via ice_timeout() is still used for requests.
#
to.op() # Force connection.
- timeout.holdAdapter(500);
- to = Test::TimeoutPrx::uncheckedCast(to.ice_timeout(250))
+ timeout.holdAdapter(750)
+ to = Test::TimeoutPrx::uncheckedCast(to.ice_timeout(500))
begin
to.sendData(seq)
test(false)
diff --git a/scripts/TestUtil.py b/scripts/TestUtil.py
index 04323018352..860d78cf23d 100755
--- a/scripts/TestUtil.py
+++ b/scripts/TestUtil.py
@@ -707,6 +707,12 @@ sslConfigTree = {
"--IceSSL.CheckCertName=0"
},
}
+
+if isDarwin():
+ sslConfigTree["cpp"]["client"] += " --IceSSL.Keychain=client.keychain --IceSSL.KeychainPassword=password"
+ sslConfigTree["cpp"]["server"] += " --IceSSL.Keychain=server.keychain --IceSSL.KeychainPassword=password"
+ sslConfigTree["cpp"]["colloc"] += " --IceSSL.Keychain=colloc.keychain --IceSSL.KeychainPassword=password"
+
sslConfigTree["py"] = sslConfigTree["cpp"]
sslConfigTree["rb"] = sslConfigTree["cpp"]
sslConfigTree["php"] = sslConfigTree["cpp"]