OW_SSLSocketImpl.cpp

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

Generated on Thu Feb 9 08:48:15 2006 for openwbem by  doxygen 1.4.6