blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2006, 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 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Vintela, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 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 // do nothing, since we're probably cleaning up. If we had a logger we should log the reason why this failed.... 00087 } 00088 // we're not going to reuse the SSL context, so we do a 00089 // unidirectional shutdown, and don't need to call it twice 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 } // End of unnamed namespace 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); // cleanup memory SSL may have allocated 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); // cleanup memory SSL may have allocated 00189 BLOCXX_THROW(SSLException, "SSL failed to authenticate client"); 00190 } 00191 } 00192 00193 // TODO Get rid of this one later. 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); // cleanup memory SSL may have allocated 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); // cleanup memory SSL may have allocated 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); // cleanup memory SSL may have allocated 00248 } 00249 catch (...) 00250 { 00251 // no exceptions allowed out of destructors. 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 // SSL buffer can contain the data therefore select 00358 // does not work without checking SSL_pending() first. 00359 bool 00360 SSLSocketImpl::waitForInput(const Timeout& timeout) 00361 { 00362 // SSL buffer contains data -> read them 00363 if (SSL_pending(m_ssl)) 00364 { 00365 return false; 00366 } 00367 return SocketBaseImpl::waitForInput(timeout); 00368 } 00370 00371 } // end namespace BLOCXX_NAMESPACE 00372 00374 #endif // #ifdef BLOCXX_HAVE_OPENSSL 00375