summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/SslConnectionOpenSSLClient.cpp
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2002-04-24 21:13:00 +0000
committerMark Spruiell <mes@zeroc.com>2002-04-24 21:13:00 +0000
commit5409c1ecef0f226dedc77721c0d2fc8dfe9e85de (patch)
tree97ba75bc47a143726d6d8382be3a462e51716700 /cpp/src/IceSSL/SslConnectionOpenSSLClient.cpp
parentcleaning up sample impls (diff)
downloadice-5409c1ecef0f226dedc77721c0d2fc8dfe9e85de.tar.bz2
ice-5409c1ecef0f226dedc77721c0d2fc8dfe9e85de.tar.xz
ice-5409c1ecef0f226dedc77721c0d2fc8dfe9e85de.zip
merging from plugins branch
Diffstat (limited to 'cpp/src/IceSSL/SslConnectionOpenSSLClient.cpp')
-rw-r--r--cpp/src/IceSSL/SslConnectionOpenSSLClient.cpp389
1 files changed, 389 insertions, 0 deletions
diff --git a/cpp/src/IceSSL/SslConnectionOpenSSLClient.cpp b/cpp/src/IceSSL/SslConnectionOpenSSLClient.cpp
new file mode 100644
index 00000000000..0920aa798d3
--- /dev/null
+++ b/cpp/src/IceSSL/SslConnectionOpenSSLClient.cpp
@@ -0,0 +1,389 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+#include <Ice/Network.h>
+#include <Ice/TraceLevels.h>
+#include <Ice/Logger.h>
+#include <Ice/LocalException.h>
+#include <IceSSL/OpenSSLUtils.h>
+#include <IceSSL/OpenSSL.h>
+#include <IceSSL/Exception.h>
+#include <IceSSL/OpenSSLJanitors.h>
+#include <IceSSL/SslConnectionOpenSSLClient.h>
+
+#include <sstream>
+
+using namespace std;
+using namespace Ice;
+using namespace IceInternal;
+
+////////////////////////////////////////////////
+////////// SslConnectionOpenSSLClient //////////
+////////////////////////////////////////////////
+
+//
+// Public Methods
+//
+
+// Note: I would use a using directive of the form:
+// using IceSSL::CertificateVerifierPtr;
+// but unfortunately, it appears that this is not properly picked up.
+//
+
+IceSSL::OpenSSL::ClientConnection::ClientConnection(const TraceLevelsPtr& traceLevels,
+ const LoggerPtr& logger,
+ const IceSSL::CertificateVerifierPtr& certificateVerifier,
+ SSL* connection,
+ const PluginBaseIPtr& plugin) :
+ Connection(traceLevels, logger, certificateVerifier, connection, plugin)
+{
+ assert(_sslConnection != 0);
+
+ // Set the Connect Connection state for this connection.
+ SSL_set_connect_state(_sslConnection);
+}
+
+IceSSL::OpenSSL::ClientConnection::~ClientConnection()
+{
+}
+
+void
+IceSSL::OpenSSL::ClientConnection::shutdown()
+{
+ Connection::shutdown();
+}
+
+int
+IceSSL::OpenSSL::ClientConnection::init(int timeout)
+{
+ assert(_sslConnection != 0);
+
+ int retCode = SSL_is_init_finished(_sslConnection);
+
+ while (!retCode)
+ {
+ int i = 0;
+
+ _readTimeout = timeout > _handshakeReadTimeout ? timeout : _handshakeReadTimeout;
+
+ if (_initWantRead)
+ {
+ i = readSelect(_readTimeout);
+ }
+ else if (_initWantWrite)
+ {
+ i = writeSelect(timeout);
+ }
+
+ if (_initWantRead && i == 0)
+ {
+ return 0;
+ }
+
+ if (_initWantWrite && i == 0)
+ {
+ return 0;
+ }
+
+ _initWantRead = 0;
+ _initWantWrite = 0;
+
+ int result = connect();
+
+ switch (getLastError())
+ {
+ case SSL_ERROR_WANT_READ:
+ {
+ _initWantRead = 1;
+ break;
+ }
+
+ case SSL_ERROR_WANT_WRITE:
+ {
+ _initWantWrite = 1;
+ break;
+ }
+
+
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ {
+ // Retry connect.
+ break;
+ }
+
+ case SSL_ERROR_SYSCALL:
+ {
+ // This is a SOCKET_ERROR, but we don't use
+ // this define here as OpenSSL doesn't refer
+ // to it as a SOCKET_ERROR (but that's what it is
+ // if you look at their code).
+ if(result == -1)
+ {
+ // IO Error in underlying BIO
+
+ if (interrupted())
+ {
+ break;
+ }
+
+ if (wouldBlock())
+ {
+ readSelect(_readTimeout);
+ break;
+ }
+
+ if (connectionLost())
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+ else // result == 0
+ {
+ //
+ // The OpenSSL docs say that a result code of 0 indicates
+ // a graceful shutdown. In order to cause a retry in the
+ // Ice core, we raise ConnectFailedException. However,
+ // errno isn't set in this situation, so we always use
+ // ECONNREFUSED.
+ //
+ ConnectFailedException ex(__FILE__, __LINE__);
+ ex.error = ECONNREFUSED;
+ throw ex;
+ }
+ }
+
+ case SSL_ERROR_SSL:
+ {
+ int verifyError = SSL_get_verify_result(_sslConnection);
+
+ if (verifyError != X509_V_OK && verifyError != 1)
+ {
+ CertificateVerificationException certVerEx(__FILE__, __LINE__);
+
+ certVerEx._message = "ssl certificate verification error";
+
+ string errors = sslGetErrors();
+
+ if (!errors.empty())
+ {
+ certVerEx._message += "\n";
+ certVerEx._message += errors;
+ }
+
+ throw certVerEx;
+ }
+ else
+ {
+ ProtocolException protocolEx(__FILE__, __LINE__);
+
+ protocolEx._message = "encountered a violation of the ssl protocol during handshake\n";
+ protocolEx._message += sslGetErrors();
+
+ throw protocolEx;
+ }
+ }
+ }
+
+ retCode = SSL_is_init_finished(_sslConnection);
+
+ if (retCode > 0)
+ {
+ // Init finished, look at the connection information.
+ showConnectionInfo();
+ }
+ }
+
+ return retCode;
+}
+
+int
+IceSSL::OpenSSL::ClientConnection::write(Buffer& buf, int timeout)
+{
+ int totalBytesWritten = 0;
+ int bytesWritten = 0;
+
+ int packetSize = buf.b.end() - buf.i;
+
+#ifdef _WIN32
+ //
+ // Limit packet size to avoid performance problems on WIN32.
+ // (blatantly ripped off from Marc Laukien)
+ //
+ if (packetSize > 64 * 1024)
+ {
+ packetSize = 64 * 1024;
+ }
+#endif
+
+ // We keep reading until we're done
+ while (buf.i != buf.b.end())
+ {
+ // Ensure we're initialized.
+ if (initialize(timeout) <= 0)
+ {
+ // Retry the initialize call
+ continue;
+ }
+
+ // initialize() must have returned > 0, so we're okay to try a write.
+
+ // Perform a select on the socket.
+ if (!writeSelect(timeout))
+ {
+ // We're done here.
+ break;
+ }
+
+ bytesWritten = sslWrite((char *)buf.i, packetSize);
+
+ switch (getLastError())
+ {
+ case SSL_ERROR_NONE:
+ {
+ if (bytesWritten > 0)
+ {
+ if (_traceLevels->network >= 3)
+ {
+ ostringstream s;
+ s << "sent " << bytesWritten << " of " << packetSize;
+ s << " bytes via ssl\n" << fdToString(SSL_get_fd(_sslConnection));
+ _logger->trace(_traceLevels->networkCat, s.str());
+ }
+
+ totalBytesWritten += bytesWritten;
+
+ buf.i += bytesWritten;
+
+ if (packetSize > buf.b.end() - buf.i)
+ {
+ packetSize = buf.b.end() - buf.i;
+ }
+ }
+ continue;
+ }
+
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ {
+ // Perform another read. The read should take care of this.
+ continue;
+ }
+
+ case SSL_ERROR_SYSCALL:
+ {
+ // NOTE: The OpenSSL demo client only raises and error condition if there were
+ // actually bytes written. This is considered to be an error status
+ // requiring shutdown.
+ // If nothing was written, the demo client stops writing - we continue.
+ // This is potentially something wierd to watch out for.
+ if (bytesWritten == -1)
+ {
+ // IO Error in underlying BIO
+
+ if (interrupted())
+ {
+ break;
+ }
+
+ if (wouldBlock())
+ {
+ break;
+ }
+
+ if (connectionLost())
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+ else if (bytesWritten > 0)
+ {
+ ProtocolException protocolEx(__FILE__, __LINE__);
+
+ // Protocol Error: Unexpected EOF
+ protocolEx._message = "encountered an EOF that violates the ssl protocol\n";
+ protocolEx._message += sslGetErrors();
+
+ throw protocolEx;
+ }
+ else // bytesWritten == 0
+ {
+ // Didn't write anything, continue, should be fine.
+ break;
+ }
+ }
+
+ case SSL_ERROR_SSL:
+ {
+ ProtocolException protocolEx(__FILE__, __LINE__);
+
+ protocolEx._message = "encountered a violation of the ssl protocol\n";
+ protocolEx._message += sslGetErrors();
+
+ throw protocolEx;
+ }
+
+ case SSL_ERROR_ZERO_RETURN:
+ {
+ ConnectionLostException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+ }
+
+ return totalBytesWritten;
+}
+
+//
+// Protected Methods
+//
+
+void
+IceSSL::OpenSSL::ClientConnection::showConnectionInfo()
+{
+ // Only in extreme cases do we enable this, partially because it doesn't use the Logger.
+ if ((_traceLevels->security >= IceSSL::SECURITY_PROTOCOL_DEBUG) && 0)
+ {
+ BIOJanitor bioJanitor(BIO_new_fp(stdout, BIO_NOCLOSE));
+ BIO* bio = bioJanitor.get();
+
+ showCertificateChain(bio);
+
+ showPeerCertificate(bio,"Client");
+
+ showClientCAList(bio, "Client");
+
+ showSharedCiphers(bio);
+
+ showSelectedCipherInfo(bio);
+
+ showHandshakeStats(bio);
+
+ showSessionInfo(bio);
+ }
+}