SSLSocketImpl.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2004 Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2005 Novell, Inc. All rights reserved.
00004 *
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 *
00008 *  - Redistributions of source code must retain the above copyright notice,
00009 *    this list of conditions and the following disclaimer.
00010 *
00011 *  - Redistributions in binary form must reproduce the above copyright notice,
00012 *    this list of conditions and the following disclaimer in the documentation
00013 *    and/or other materials provided with the distribution.
00014 *
00015 *  - Neither the name of Vintela, Inc., Novell, Inc., nor the names of its
00016 *    contributors may be used to endorse or promote products derived from this
00017 *    software without specific prior written permission.
00018 *
00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc., Novell, Inc., OR THE 
00023 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00024 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00025 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00026 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00027 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00028 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00029 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 *******************************************************************************/
00031 
00041 #include "BLOCXX_config.h"
00042 #include "blocxx/SSLSocketImpl.hpp"
00043 #include "blocxx/Format.hpp"
00044 #include "blocxx/Assertion.hpp"
00045 #ifdef BLOCXX_HAVE_OPENSSL
00046 #include <openssl/err.h>
00047 #include <blocxx/Format.hpp>
00048 #include <blocxx/SocketUtils.hpp>
00049 
00050 
00051 namespace BLOCXX_NAMESPACE
00052 {
00054 SSLSocketImpl::SSLSocketImpl(SSLClientCtxRef sslCtx) 
00055    : SocketBaseImpl()
00056    , m_ssl(0)
00057    , m_sslCtx(sslCtx)
00058 {
00059 }
00060 
00061 namespace
00062 {
00063 
00064 void sslWaitForIO(SocketBaseImpl& s, int type)
00065 {
00066    if(type == SSL_ERROR_WANT_READ)
00067    {
00068       s.waitForInput();
00069    }
00070    else
00071    {
00072       s.waitForOutput();
00073    }
00074 }
00075 
00076 void shutdownSSL(SSL* ssl)
00077 {
00078    BLOCXX_ASSERT(ssl != 0);
00079    if (SSL_shutdown(ssl) == -1)
00080    {
00081       // do nothing, since we're probably cleaning up.  If we had a logger we should log the reason why this failed....
00082    }
00083    // we're not going to reuse the SSL context, so we do a 
00084    // unidirectional shutdown, and don't need to call it twice
00085 }
00086 
00087 void connectWithSSL(SSL* ssl, SocketBaseImpl& s)
00088 {
00089    BLOCXX_ASSERT(ssl != 0);
00090    int retries = 0;
00091    ERR_clear_error();
00092    int cc = SSL_connect(ssl);
00093    cc = SSL_get_error(ssl, cc);
00094    while((cc == SSL_ERROR_WANT_READ 
00095       || cc == SSL_ERROR_WANT_WRITE)
00096       && retries < BLOCXX_SSL_RETRY_LIMIT)
00097    {
00098       sslWaitForIO(s, cc);
00099       ERR_clear_error();
00100       cc = SSL_connect(ssl);
00101       cc = SSL_get_error(ssl, cc);
00102       retries++;
00103    }
00104 
00105    if (cc != SSL_ERROR_NONE)
00106    {
00107       BLOCXX_THROW(SSLException, Format("SSL connect error: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00108    }
00109 }
00110 
00111 int acceptSSL(SSL* ssl, SocketBaseImpl& s, String& errorDescription)
00112 {
00113    BLOCXX_ASSERT(ssl != 0);
00114    int retries = 0;
00115    int cc = SSL_ERROR_WANT_READ;
00116    while((cc == SSL_ERROR_WANT_READ || cc == SSL_ERROR_WANT_WRITE)
00117       && retries < BLOCXX_SSL_RETRY_LIMIT)
00118    {
00119       sslWaitForIO(s, cc);
00120       ERR_clear_error();
00121       cc = SSL_accept(ssl);
00122       cc = SSL_get_error(ssl, cc);
00123       retries++;
00124    }
00125    if (cc == SSL_ERROR_NONE)
00126    {
00127       return 0;
00128    }
00129    else
00130    {
00131       errorDescription = SSLCtxMgr::getOpenSSLErrorDescription();
00132       return -1;
00133    }
00134 }
00135 
00136 }  // End of unnamed namespace
00137 
00139 SSLSocketImpl::SSLSocketImpl(SocketHandle_t fd, 
00140    SocketAddress::AddressType addrType, const SSLServerCtxRef& sslCtx) 
00141    : SocketBaseImpl(fd, addrType)
00142 {
00143    BLOCXX_ASSERT(sslCtx);
00144    ERR_clear_error();
00145    m_ssl = SSL_new(sslCtx->getSSLCtx());
00146    if (!m_ssl)
00147    {
00148       BLOCXX_THROW(SSLException, Format("SSL_new failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00149    }
00150 
00151    if (SSL_set_ex_data(m_ssl, SSLServerCtx::SSL_DATA_INDEX, &m_owctx) == 0)
00152    {
00153       BLOCXX_THROW(SSLException, Format("SSL_set_ex_data failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00154    }
00155 
00156    BIO* bio = BIO_new_socket(fd, BIO_NOCLOSE);
00157    if (!bio)
00158    {
00159       SSL_free(m_ssl);
00160       BLOCXX_THROW(SSLException, Format("BIO_new_socket failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00161    }
00162       
00163    SSL_set_bio(m_ssl, bio, bio);
00164    String errorDescription;
00165    if (acceptSSL(m_ssl, *this, errorDescription) != 0)
00166    {
00167       shutdownSSL(m_ssl);
00168       SSL_free(m_ssl);
00169       ERR_remove_state(0); // cleanup memory SSL may have allocated
00170       BLOCXX_THROW(SSLException, Format("SSLSocketImpl ctor: SSL accept error while connecting to %1: %2", m_peerAddress.toString(), errorDescription).c_str());
00171    }
00172    if (!SSLCtxMgr::checkClientCert(m_ssl, m_peerAddress.getName()))
00173    {
00174       shutdownSSL(m_ssl);
00175       SSL_free(m_ssl);
00176       ERR_remove_state(0); // cleanup memory SSL may have allocated
00177       BLOCXX_THROW(SSLException, "SSL failed to authenticate client");
00178    }
00179 }
00180 
00181 // TODO Get rid of this one later. 
00183 SSLSocketImpl::SSLSocketImpl(SocketHandle_t fd, 
00184    SocketAddress::AddressType addrType) 
00185    : SocketBaseImpl(fd, addrType)
00186 {
00187    ERR_clear_error();
00188    m_ssl = SSL_new(SSLCtxMgr::getSSLCtxServer());
00189    if (!m_ssl)
00190    {
00191       BLOCXX_THROW(SSLException, Format("SSL_new failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00192    }
00193 
00194    m_sbio = BIO_new_socket(fd, BIO_NOCLOSE);
00195    if (!m_sbio)
00196    {
00197       SSL_free(m_ssl);
00198       BLOCXX_THROW(SSLException, Format("BIO_new_socket failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00199    }
00200       
00201    SSL_set_bio(m_ssl, m_sbio, m_sbio);
00202    String errorDescription;
00203    if (acceptSSL(m_ssl, *this, errorDescription) != 0)
00204    {
00205       shutdownSSL(m_ssl);
00206       SSL_free(m_ssl);
00207       ERR_remove_state(0); // cleanup memory SSL may have allocated
00208       BLOCXX_THROW(SSLException, Format("SSLSocketImpl ctor: SSL accept error while connecting to %1: %2", m_peerAddress.toString(), errorDescription).c_str());
00209    }
00210    if (!SSLCtxMgr::checkClientCert(m_ssl, m_peerAddress.getName()))
00211    {
00212       shutdownSSL(m_ssl);
00213       SSL_free(m_ssl);
00214       ERR_remove_state(0); // cleanup memory SSL may have allocated
00215       BLOCXX_THROW(SSLException, "SSL failed to authenticate client");
00216    }
00217 }
00219 SSLSocketImpl::SSLSocketImpl(const SocketAddress& addr) 
00220    : SocketBaseImpl(addr)
00221 {
00222    connectSSL();
00223 }
00225 SSLSocketImpl::~SSLSocketImpl()
00226 {
00227    try
00228    {
00229       disconnect(); 
00230       if (m_ssl)
00231       {
00232          SSL_free(m_ssl);
00233          m_ssl = 0; 
00234       }
00235       ERR_remove_state(0); // cleanup memory SSL may have allocated
00236    }
00237    catch (...)
00238    {
00239       // no exceptions allowed out of destructors.
00240    }
00241 }
00243 Select_t
00244 SSLSocketImpl::getSelectObj() const
00245 {
00246 #if defined(BLOCXX_WIN32)
00247    Select_t st;
00248    st.event = m_event;
00249    st.sockfd = m_sockfd;
00250    st.networkevents = FD_READ | FD_WRITE;
00251    st.doreset = true;
00252    return st;
00253 #else
00254    return m_sockfd;
00255 #endif
00256 }
00258 void 
00259 SSLSocketImpl::connect(const SocketAddress& addr)
00260 {
00261    SocketBaseImpl::connect(addr);
00262    connectSSL();
00263 }
00265 void 
00266 SSLSocketImpl::connectSSL()
00267 {
00268    m_isConnected = false;
00269    BLOCXX_ASSERT(m_sslCtx); 
00270    if (m_ssl)
00271    {
00272       SSL_free(m_ssl); 
00273       m_ssl = 0;
00274    }
00275    ERR_clear_error();
00276    m_ssl = SSL_new(m_sslCtx->getSSLCtx()); 
00277    
00278    if (!m_ssl)
00279    {
00280       BLOCXX_THROW(SSLException, Format("SSL_new failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00281    }
00282    m_sbio = BIO_new_socket(m_sockfd, BIO_NOCLOSE);
00283    if (!m_sbio)
00284    {
00285       SSL_free(m_ssl);
00286       BLOCXX_THROW(SSLException, Format("BIO_new_socket failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00287    }
00288    SSL_set_bio(m_ssl, m_sbio, m_sbio);
00289 
00290    connectWithSSL(m_ssl, *this);
00291 
00292    if (!SSLCtxMgr::checkServerCert(m_ssl, m_peerAddress.getName()))
00293    {
00294       BLOCXX_THROW(SSLException, "Failed to validate peer certificate");
00295    }
00296    m_isConnected = true;
00297 }
00299 void
00300 SSLSocketImpl::disconnect()
00301 {
00302 #if defined(BLOCXX_WIN32)
00303    if (m_sockfd != INVALID_SOCKET && m_isConnected)
00304 #else
00305    if (m_sockfd != -1 && m_isConnected)
00306 #endif
00307    {
00308       if (m_ssl)
00309       {
00310          shutdownSSL(m_ssl);
00311       }
00312    }
00313    SocketBaseImpl::disconnect();
00314 }
00316 int 
00317 SSLSocketImpl::writeAux(const void* dataOut, int dataOutLen)
00318 {
00319    return SSLCtxMgr::sslWrite(m_ssl, static_cast<const char*>(dataOut), 
00320          dataOutLen);
00321 }
00323 int 
00324 SSLSocketImpl::readAux(void* dataIn, int dataInLen)
00325 {
00326    return SSLCtxMgr::sslRead(m_ssl, static_cast<char*>(dataIn), 
00327          dataInLen);
00328 }
00330 SSL*
00331 SSLSocketImpl::getSSL() const
00332 {
00333    return m_ssl; 
00334 }
00335 
00337 bool
00338 SSLSocketImpl::peerCertVerified() const
00339 {
00340     return (m_owctx.peerCertPassedVerify == OWSSLContext::VERIFY_PASS); 
00341 }
00342 
00344 // SSL buffer can contain the data therefore select
00345 // does not work without checking SSL_pending() first.
00346 bool
00347 SSLSocketImpl::waitForInput(int timeOutSecs)
00348 {
00349    // SSL buffer contains data -> read them
00350    if (SSL_pending(m_ssl))
00351    {
00352       return false;
00353    }
00354    return SocketBaseImpl::waitForInput(timeOutSecs);
00355 }
00357 
00358 } // end namespace BLOCXX_NAMESPACE
00359 
00361 #endif // #ifdef BLOCXX_HAVE_OPENSSL
00362 

Generated on Fri Jun 16 15:39:09 2006 for blocxx by  doxygen 1.4.6