00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00043 #include "blocxx/BLOCXX_config.h"
00044
00045 #ifdef BLOCXX_HAVE_OPENSSL
00046
00047 #include "blocxx/SSLSocketImpl.hpp"
00048 #include "blocxx/Format.hpp"
00049 #include "blocxx/Assertion.hpp"
00050 #include "blocxx/Timeout.hpp"
00051 #include <openssl/err.h>
00052 #include "blocxx/Format.hpp"
00053 #include "blocxx/SocketUtils.hpp"
00054
00055
00056 namespace BLOCXX_NAMESPACE
00057 {
00059 SSLSocketImpl::SSLSocketImpl(SSLClientCtxRef sslCtx)
00060 : SocketBaseImpl()
00061 , m_ssl(0)
00062 , m_sslCtx(sslCtx)
00063 {
00064 }
00065
00066 namespace
00067 {
00068
00069 void sslWaitForIO(SocketBaseImpl& s, int type)
00070 {
00071 if(type == SSL_ERROR_WANT_READ)
00072 {
00073 s.waitForInput(Timeout::infinite);
00074 }
00075 else
00076 {
00077 s.waitForOutput(Timeout::infinite);
00078 }
00079 }
00080
00081 void shutdownSSL(SSL* ssl)
00082 {
00083 BLOCXX_ASSERT(ssl != 0);
00084 if (SSL_shutdown(ssl) == -1)
00085 {
00086
00087 }
00088
00089
00090 }
00091
00092 void connectWithSSL(SSL* ssl, SocketBaseImpl& s)
00093 {
00094 BLOCXX_ASSERT(ssl != 0);
00095 int retries = 0;
00096 ERR_clear_error();
00097 int cc = SSL_connect(ssl);
00098 cc = SSL_get_error(ssl, cc);
00099 while((cc == SSL_ERROR_WANT_READ
00100 || cc == SSL_ERROR_WANT_WRITE)
00101 && retries < BLOCXX_SSL_RETRY_LIMIT)
00102 {
00103 sslWaitForIO(s, cc);
00104 ERR_clear_error();
00105 cc = SSL_connect(ssl);
00106 cc = SSL_get_error(ssl, cc);
00107 retries++;
00108 }
00109
00110 if (cc != SSL_ERROR_NONE)
00111 {
00112 BLOCXX_THROW(SSLException, Format("SSL connect error: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00113 }
00114 }
00115
00116 int acceptSSL(SSL* ssl, SocketBaseImpl& s, String& errorDescription)
00117 {
00118 BLOCXX_ASSERT(ssl != 0);
00119 int retries = 0;
00120 int cc = SSL_ERROR_WANT_READ;
00121 while((cc == SSL_ERROR_WANT_READ || cc == SSL_ERROR_WANT_WRITE)
00122 && retries < BLOCXX_SSL_RETRY_LIMIT)
00123 {
00124 sslWaitForIO(s, cc);
00125 ERR_clear_error();
00126 cc = SSL_accept(ssl);
00127 cc = SSL_get_error(ssl, cc);
00128 retries++;
00129 }
00130 if (cc == SSL_ERROR_NONE)
00131 {
00132 return 0;
00133 }
00134 else
00135 {
00136 errorDescription = SSLCtxMgr::getOpenSSLErrorDescription();
00137 return -1;
00138 }
00139 }
00140
00141 }
00142
00144 SSLSocketImpl::SSLSocketImpl()
00145 : SocketBaseImpl()
00146 , m_ssl(0)
00147 , m_sbio(0)
00148 {
00149 }
00151 SSLSocketImpl::SSLSocketImpl(SocketHandle_t fd,
00152 SocketAddress::AddressType addrType, const SSLServerCtxRef& sslCtx)
00153 : SocketBaseImpl(fd, addrType)
00154 {
00155 BLOCXX_ASSERT(sslCtx);
00156 ERR_clear_error();
00157 m_ssl = SSL_new(sslCtx->getSSLCtx());
00158 if (!m_ssl)
00159 {
00160 BLOCXX_THROW(SSLException, Format("SSL_new failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00161 }
00162
00163 if (SSL_set_ex_data(m_ssl, SSLServerCtx::SSL_DATA_INDEX, &m_owctx) == 0)
00164 {
00165 BLOCXX_THROW(SSLException, Format("SSL_set_ex_data failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00166 }
00167
00168 BIO* bio = BIO_new_socket(fd, BIO_NOCLOSE);
00169 if (!bio)
00170 {
00171 SSL_free(m_ssl);
00172 BLOCXX_THROW(SSLException, Format("BIO_new_socket failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00173 }
00174
00175 SSL_set_bio(m_ssl, bio, bio);
00176 String errorDescription;
00177 if (acceptSSL(m_ssl, *this, errorDescription) != 0)
00178 {
00179 shutdownSSL(m_ssl);
00180 SSL_free(m_ssl);
00181 ERR_remove_state(0);
00182 BLOCXX_THROW(SSLException, Format("SSLSocketImpl ctor: SSL accept error while connecting to %1: %2", m_peerAddress.toString(), errorDescription).c_str());
00183 }
00184 if (!SSLCtxMgr::checkClientCert(m_ssl, m_peerAddress.getName()))
00185 {
00186 shutdownSSL(m_ssl);
00187 SSL_free(m_ssl);
00188 ERR_remove_state(0);
00189 BLOCXX_THROW(SSLException, "SSL failed to authenticate client");
00190 }
00191 }
00192
00193
00195 SSLSocketImpl::SSLSocketImpl(SocketHandle_t fd,
00196 SocketAddress::AddressType addrType)
00197 : SocketBaseImpl(fd, addrType)
00198 {
00199 ERR_clear_error();
00200 m_ssl = SSL_new(SSLCtxMgr::getSSLCtxServer());
00201 if (!m_ssl)
00202 {
00203 BLOCXX_THROW(SSLException, Format("SSL_new failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00204 }
00205
00206 m_sbio = BIO_new_socket(fd, BIO_NOCLOSE);
00207 if (!m_sbio)
00208 {
00209 SSL_free(m_ssl);
00210 BLOCXX_THROW(SSLException, Format("BIO_new_socket failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00211 }
00212
00213 SSL_set_bio(m_ssl, m_sbio, m_sbio);
00214 String errorDescription;
00215 if (acceptSSL(m_ssl, *this, errorDescription) != 0)
00216 {
00217 shutdownSSL(m_ssl);
00218 SSL_free(m_ssl);
00219 ERR_remove_state(0);
00220 BLOCXX_THROW(SSLException, Format("SSLSocketImpl ctor: SSL accept error while connecting to %1: %2", m_peerAddress.toString(), errorDescription).c_str());
00221 }
00222 if (!SSLCtxMgr::checkClientCert(m_ssl, m_peerAddress.getName()))
00223 {
00224 shutdownSSL(m_ssl);
00225 SSL_free(m_ssl);
00226 ERR_remove_state(0);
00227 BLOCXX_THROW(SSLException, "SSL failed to authenticate client");
00228 }
00229 }
00231 SSLSocketImpl::SSLSocketImpl(const SocketAddress& addr)
00232 : SocketBaseImpl(addr)
00233 {
00234 connectSSL();
00235 }
00237 SSLSocketImpl::~SSLSocketImpl()
00238 {
00239 try
00240 {
00241 disconnect();
00242 if (m_ssl)
00243 {
00244 SSL_free(m_ssl);
00245 m_ssl = 0;
00246 }
00247 ERR_remove_state(0);
00248 }
00249 catch (...)
00250 {
00251
00252 }
00253 }
00255 Select_t
00256 SSLSocketImpl::getSelectObj() const
00257 {
00258 #if defined(BLOCXX_WIN32)
00259 Select_t st;
00260 st.event = m_event;
00261 st.sockfd = m_sockfd;
00262 st.isSocket = true;
00263 st.networkevents = FD_READ | FD_WRITE;
00264 st.doreset = true;
00265 return st;
00266 #else
00267 return m_sockfd;
00268 #endif
00269 }
00271 void
00272 SSLSocketImpl::connect(const SocketAddress& addr)
00273 {
00274 SocketBaseImpl::connect(addr);
00275 connectSSL();
00276 }
00278 void
00279 SSLSocketImpl::connectSSL()
00280 {
00281 m_isConnected = false;
00282 BLOCXX_ASSERT(m_sslCtx);
00283 if (m_ssl)
00284 {
00285 SSL_free(m_ssl);
00286 m_ssl = 0;
00287 }
00288 ERR_clear_error();
00289 m_ssl = SSL_new(m_sslCtx->getSSLCtx());
00290
00291 if (!m_ssl)
00292 {
00293 BLOCXX_THROW(SSLException, Format("SSL_new failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00294 }
00295 m_sbio = BIO_new_socket(m_sockfd, BIO_NOCLOSE);
00296 if (!m_sbio)
00297 {
00298 SSL_free(m_ssl);
00299 BLOCXX_THROW(SSLException, Format("BIO_new_socket failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00300 }
00301 SSL_set_bio(m_ssl, m_sbio, m_sbio);
00302
00303 connectWithSSL(m_ssl, *this);
00304
00305 if (!SSLCtxMgr::checkServerCert(m_ssl, m_peerAddress.getName()))
00306 {
00307 BLOCXX_THROW(SSLException, "Failed to validate peer certificate");
00308 }
00309 m_isConnected = true;
00310 }
00312 void
00313 SSLSocketImpl::disconnect()
00314 {
00315 #if defined(BLOCXX_WIN32)
00316 if (m_sockfd != INVALID_SOCKET && m_isConnected)
00317 #else
00318 if (m_sockfd != -1 && m_isConnected)
00319 #endif
00320 {
00321 if (m_ssl)
00322 {
00323 shutdownSSL(m_ssl);
00324 }
00325 }
00326 SocketBaseImpl::disconnect();
00327 }
00329 int
00330 SSLSocketImpl::writeAux(const void* dataOut, int dataOutLen)
00331 {
00332 return SSLCtxMgr::sslWrite(m_ssl, static_cast<const char*>(dataOut),
00333 dataOutLen);
00334 }
00336 int
00337 SSLSocketImpl::readAux(void* dataIn, int dataInLen)
00338 {
00339 return SSLCtxMgr::sslRead(m_ssl, static_cast<char*>(dataIn),
00340 dataInLen);
00341 }
00343 SSL*
00344 SSLSocketImpl::getSSL() const
00345 {
00346 return m_ssl;
00347 }
00348
00350 bool
00351 SSLSocketImpl::peerCertVerified() const
00352 {
00353 return (m_owctx.peerCertPassedVerify == OWSSLContext::VERIFY_PASS);
00354 }
00355
00357
00358
00359 bool
00360 SSLSocketImpl::waitForInput(const Timeout& timeout)
00361 {
00362
00363 if (SSL_pending(m_ssl))
00364 {
00365 return false;
00366 }
00367 return SocketBaseImpl::waitForInput(timeout);
00368 }
00370
00371 }
00372
00374 #endif // #ifdef BLOCXX_HAVE_OPENSSL
00375