blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved. 00003 * Copyright (C) 2004 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. 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. OR THE CONTRIBUTORS 00023 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00029 * POSSIBILITY OF SUCH DAMAGE. 00030 *******************************************************************************/ 00031 00037 #include "blocxx/BLOCXX_config.h" 00038 #ifdef BLOCXX_HAVE_OPENSSL 00039 #include "blocxx/SSLCtxMgr.hpp" 00040 #include "blocxx/GetPass.hpp" 00041 #include "blocxx/Format.hpp" 00042 #include "blocxx/FileSystem.hpp" 00043 #include "blocxx/ThreadImpl.hpp" 00044 #include "blocxx/Mutex.hpp" 00045 #include "blocxx/GlobalMutex.hpp" 00046 #include "blocxx/MutexLock.hpp" 00047 #include "blocxx/Assertion.hpp" 00048 #include "blocxx/MD5.hpp" 00049 #include "blocxx/Array.hpp" 00050 #include "blocxx/SecureRand.hpp" 00051 #include "blocxx/SignalScope.hpp" 00052 #include "blocxx/LazyGlobal.hpp" 00053 00054 #include <openssl/rand.h> 00055 #include <openssl/err.h> 00056 #include <cstring> 00057 #include <csignal> 00058 #include <cerrno> 00059 #ifndef BLOCXX_WIN32 00060 #include <sys/time.h> 00061 #include <sys/resource.h> 00062 #endif 00063 #include <fcntl.h> 00064 00065 #ifdef BLOCXX_HAVE_SYS_TYPES_H 00066 #include <sys/types.h> 00067 #endif 00068 00069 #ifdef BLOCXX_HAVE_SYS_STAT_H 00070 #include <sys/stat.h> 00071 #endif 00072 00073 #ifdef BLOCXX_HAVE_UNISTD_H 00074 #include <unistd.h> 00075 #endif 00076 00077 #ifdef BLOCXX_DEBUG 00078 #include <iostream> 00079 #endif 00080 00081 #include <fstream> 00082 00083 // This struct has to be in the global namespace 00084 extern "C" 00085 { 00086 struct CRYPTO_dynlock_value 00087 { 00088 BLOCXX_NAMESPACE::Mutex mutex; 00089 }; 00090 } 00091 00092 namespace BLOCXX_NAMESPACE 00093 { 00094 00095 namespace 00096 { 00097 00098 BLOCXX_NAMESPACE::Mutex* mutex_buf = 0; 00099 00100 extern "C" 00101 { 00102 00103 static struct CRYPTO_dynlock_value * dyn_create_function(const char *,int) 00104 { 00105 return new CRYPTO_dynlock_value; 00106 } 00107 00108 // these need to still be static, since they get exported because of extern "C" 00109 static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, 00110 const char *, int) 00111 { 00112 if (mode & CRYPTO_LOCK) 00113 { 00114 l->mutex.acquire(); 00115 } 00116 else 00117 { 00118 l->mutex.release(); 00119 } 00120 } 00121 00122 static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, 00123 const char *, int) 00124 { 00125 delete l; 00126 } 00127 00128 static unsigned long id_function() 00129 { 00130 return static_cast<unsigned long>(BLOCXX_NAMESPACE::ThreadImpl::thread_t_ToUInt64(BLOCXX_NAMESPACE::ThreadImpl::currentThread())); 00131 } 00132 00133 static void locking_function(int mode, int n, const char*, int) 00134 { 00135 if (mode & CRYPTO_LOCK) 00136 { 00137 mutex_buf[n].acquire(); 00138 } 00139 else 00140 { 00141 mutex_buf[n].release(); 00142 } 00143 } 00144 } // end extern "C" 00145 00146 class X509Freer 00147 { 00148 public: 00149 X509Freer(X509* x509) 00150 : m_x509(x509) 00151 { 00152 } 00153 ~X509Freer() 00154 { 00155 if (m_x509 != 0) 00156 { 00157 X509_free(m_x509); 00158 } 00159 } 00160 private: 00161 X509* m_x509; 00162 }; 00163 00164 enum SSLLibraryInit_t { 00165 BLOCXX_SSL_LIBRARY_NOT_INITIALIZED, 00166 BLOCXX_SSL_LIBRARY_INITIALIZED, 00167 BLOCXX_SSL_LIBRARY_INITIALIZATION_DISABLED 00168 }; 00169 SSLLibraryInit_t m_initState = BLOCXX_SSL_LIBRARY_NOT_INITIALIZED; 00170 GlobalMutex m_initStateGuard = BLOCXX_GLOBAL_MUTEX_INIT(); 00171 00172 00173 enum SSLLocks_t { 00174 BLOCXX_SSL_LOCKS_NOT_USED, 00175 BLOCXX_SSL_LOCKS_USED, 00176 BLOCXX_SSL_LOCKS_DISABLED 00177 }; 00178 SSLLocks_t m_locksState = BLOCXX_SSL_LOCKS_NOT_USED; 00179 GlobalMutex m_locksStateGuard = BLOCXX_GLOBAL_MUTEX_INIT(); 00180 00182 struct SSLGlobalWork 00183 { 00184 SSLGlobalWork() 00185 { 00186 MutexLock initLock(m_initStateGuard); 00187 if (m_initState == BLOCXX_SSL_LIBRARY_NOT_INITIALIZED) 00188 { 00189 m_initState = BLOCXX_SSL_LIBRARY_INITIALIZED; 00190 00191 SSL_library_init(); 00192 SSL_load_error_strings(); 00193 } 00194 initLock.release(); 00195 00196 MutexLock locksLock(m_locksStateGuard); 00197 if (m_locksState == BLOCXX_SSL_LOCKS_NOT_USED) 00198 { 00199 m_locksState = BLOCXX_SSL_LOCKS_USED; 00200 00201 if (!mutex_buf) 00202 { 00203 mutex_buf = new Mutex[CRYPTO_num_locks()]; 00204 } 00205 00206 CRYPTO_set_id_callback(id_function); 00207 CRYPTO_set_locking_callback(locking_function); 00208 00209 // The following three CRYPTO_... functions are the OpenSSL functions 00210 // for registering the callbacks we implemented above 00211 CRYPTO_set_dynlock_create_callback(dyn_create_function); 00212 CRYPTO_set_dynlock_lock_callback(dyn_lock_function); 00213 CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); 00214 } 00215 } 00216 00217 ~SSLGlobalWork() 00218 { 00219 if (SSLCtxMgr::isClient() || SSLCtxMgr::isServer()) 00220 { 00221 Secure::rand_save_state(); 00222 } 00223 SSLCtxMgr::uninit(); 00224 00225 MutexLock locksLock(m_locksStateGuard); 00226 if (m_locksState == BLOCXX_SSL_LOCKS_USED) 00227 { 00228 CRYPTO_set_id_callback(NULL); 00229 CRYPTO_set_locking_callback(NULL); 00230 CRYPTO_set_dynlock_create_callback(NULL); 00231 CRYPTO_set_dynlock_lock_callback(NULL); 00232 CRYPTO_set_dynlock_destroy_callback(NULL); 00233 delete[] mutex_buf; 00234 mutex_buf = 0; 00235 m_locksState = BLOCXX_SSL_LOCKS_NOT_USED; 00236 } 00237 } 00238 }; 00239 00240 struct SSLGlobalWorkFactory 00241 { 00242 static SSLGlobalWork* create(int /*dummy*/) 00243 { 00244 return new SSLGlobalWork(); 00245 } 00246 }; 00247 00248 LazyGlobal<SSLGlobalWork, int, SSLGlobalWorkFactory> g_SSLGlobalWork = BLOCXX_LAZY_GLOBAL_INIT(0); 00249 00250 00251 } // end unnamed namespace 00252 00253 SSL_CTX* SSLCtxMgr::m_ctxClient = 0; 00254 SSL_CTX* SSLCtxMgr::m_ctxServer = 0; 00255 certVerifyFuncPtr_t SSLCtxMgr::m_clientCertVerifyCB = 0; 00256 certVerifyFuncPtr_t SSLCtxMgr::m_serverCertVerifyCB = 0; 00257 00259 // static 00260 String 00261 SSLCtxMgr::getOpenSSLErrorDescription() 00262 { 00263 BIO* bio = BIO_new(BIO_s_mem()); 00264 if (!bio) 00265 { 00266 return String(); 00267 } 00268 ERR_print_errors(bio); 00269 char* p = 0; 00270 long len = BIO_get_mem_data(bio, &p); 00271 String rval(p, len); 00272 int freerv = BIO_free(bio); 00273 BLOCXX_ASSERT(freerv == 1); 00274 return rval; 00275 } 00276 00278 // static 00279 void SSLCtxMgr::disableSSLInit() 00280 { 00281 MutexLock lock(m_initStateGuard); 00282 if (m_initState == BLOCXX_SSL_LIBRARY_INITIALIZED) 00283 { 00284 BLOCXX_THROW(SSLException, "SSLCtxMgr::disableSSLInit(): init() cannot be disabled as it has already been called"); 00285 } 00286 m_initState = BLOCXX_SSL_LIBRARY_INITIALIZATION_DISABLED; 00287 } 00288 00290 // static 00291 void SSLCtxMgr::disableLocks() 00292 { 00293 MutexLock lock(m_locksStateGuard); 00294 if (m_locksState == BLOCXX_SSL_LOCKS_USED) 00295 { 00296 BLOCXX_THROW(SSLException, "SSLCtxMgr::disableSSLLocks(): locks cannot be disabled as they are already in use"); 00297 } 00298 m_locksState = BLOCXX_SSL_LOCKS_DISABLED; 00299 } 00300 00302 // static 00303 Bool SSLCtxMgr::getSSLInitDisabled() 00304 { 00305 MutexLock lock(m_initStateGuard); 00306 return m_initState == BLOCXX_SSL_LIBRARY_INITIALIZATION_DISABLED; 00307 } 00308 00310 // static 00311 Bool SSLCtxMgr::getSSLLocksDisabled() 00312 { 00313 MutexLock lock(m_locksStateGuard); 00314 return m_locksState == BLOCXX_SSL_LOCKS_DISABLED; 00315 } 00316 00318 SSL_CTX* 00319 SSLCtxMgr::initCtx(const String& certfile, const String& keyfile, EVP_PKEY* pkey) 00320 { 00321 g_SSLGlobalWork.get(); // trigger initialization of lazy global stuff 00322 00323 ERR_clear_error(); 00324 SSL_CTX* ctx = SSL_CTX_new(SSLv23_method()); 00325 if (ctx == 0) 00326 { 00327 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initCtx(): SSL_CTX_new returned 0: %1", getOpenSSLErrorDescription()).c_str()); 00328 } 00329 SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb); 00330 if (!certfile.empty()) 00331 { 00332 if (SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str()) != 1) 00333 { 00334 SSL_CTX_free(ctx); 00335 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initCtx(): Couldn't read certificate from file: %1: %2", 00336 certfile, getOpenSSLErrorDescription()).c_str()); 00337 } 00338 if (pkey) 00339 { 00340 int rv = SSL_CTX_use_PrivateKey(ctx, pkey); 00341 if (rv != 1) 00342 { 00343 SSL_CTX_free(ctx); 00344 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initCtx(): Unable to set private key: %1", 00345 getOpenSSLErrorDescription()).c_str()); 00346 } 00347 } 00348 else if (SSL_CTX_use_PrivateKey_file(ctx, keyfile.empty()?certfile.c_str():keyfile.c_str(), SSL_FILETYPE_PEM) != 1) 00349 { 00350 SSL_CTX_free(ctx); 00351 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initCtx(): Couldn't read key from file: %1: %2", 00352 keyfile.empty()?certfile:keyfile, getOpenSSLErrorDescription()).c_str()); 00353 } 00354 } 00355 00356 Secure::rand_init(); 00357 00358 return ctx; 00359 } 00360 00362 void 00363 SSLCtxMgr::loadDHParams(SSL_CTX* ctx, const String& file) 00364 { 00365 BLOCXX_ASSERT(ctx != 0); 00366 ERR_clear_error(); 00367 BIO* bio = BIO_new_file(file.c_str(), "r"); 00368 if (bio == NULL) 00369 { 00370 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): Couldn't open DH file %1: %2", file, getOpenSSLErrorDescription()).c_str()); 00371 } 00372 DH* ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); 00373 BIO_free(bio); 00374 if (ret == 0) 00375 { 00376 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): PEM_read_bio_DHparams failed: %1", getOpenSSLErrorDescription()).c_str()); 00377 } 00378 if (SSL_CTX_set_tmp_dh(ctx, ret) != 1) 00379 { 00380 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): Couldn't set DH parameters because SSL_CTX_set_tmp_dh failed: %1", getOpenSSLErrorDescription()).c_str()); 00381 } 00382 } 00384 void 00385 SSLCtxMgr::generateEphRSAKey(SSL_CTX* ctx) 00386 { 00387 BLOCXX_ASSERT(ctx != 0); 00388 ERR_clear_error(); 00389 RSA* rsa = RSA_generate_key(512, RSA_F4, NULL, NULL); 00390 if (rsa == 0) 00391 { 00392 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::generateEphRSAKey(): RSA_generate_key failed: %1", getOpenSSLErrorDescription()).c_str()); 00393 } 00394 if (SSL_CTX_set_tmp_rsa(ctx, rsa) != 1) 00395 { 00396 RSA_free(rsa); 00397 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::generateEphRSAKey(): SSL_CTX_set_tmp_rsa failed. Couldn't set RSA key: %1", getOpenSSLErrorDescription()).c_str()); 00398 } 00399 RSA_free(rsa); 00400 } 00402 void 00403 SSLCtxMgr::initClient(const String& certfile, const String& keyfile) 00404 { 00405 if (m_ctxClient) 00406 { 00407 uninitClient(); 00408 } 00409 m_ctxClient = initCtx(certfile,keyfile); 00410 } 00412 void 00413 SSLCtxMgr::initServer(const String& certfile, const String& keyfile) 00414 { 00415 if (certfile.empty()) 00416 { 00417 BLOCXX_THROW(SSLException, "SSLCtxMgr::initCtx(): no certificate file specified"); 00418 } 00419 if (m_ctxServer) 00420 { 00421 uninitServer(); 00422 } 00423 m_ctxServer = initCtx(certfile,keyfile); 00424 //loadDHParams(m_ctx, dhfile); 00425 generateEphRSAKey(m_ctxServer); 00426 String sessID("SSL_SESSION_"); 00427 sessID += String(Secure::rand_range<UInt16>(0, 10000)); 00428 int sessIDLen = 00429 (SSL_MAX_SSL_SESSION_ID_LENGTH < (sessID.length())) ? 00430 SSL_MAX_SSL_SESSION_ID_LENGTH : (sessID.length()); 00431 ERR_clear_error(); 00432 if (SSL_CTX_set_session_id_context(m_ctxServer, reinterpret_cast<const unsigned char*>(sessID.c_str()), sessIDLen) != 1) 00433 { 00434 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initServer(): SSL_CTX_set_session_id_context failed: %1", getOpenSSLErrorDescription()).c_str()); 00435 } 00436 SSL_CTX_set_verify(m_ctxServer, SSL_VERIFY_PEER /*| SSL_VERIFY_FAIL_IF_NO_PEER_CERT*/, NULL); 00437 } 00439 // STATIC 00440 int 00441 SSLCtxMgr::pem_passwd_cb(char* buf, int size, int /*rwflag*/, 00442 void* /*userData*/) 00443 { 00444 String passwd = GetPass::getPass("Enter the password for the SSL certificate: "); 00445 00446 strncpy(buf, passwd.c_str(), size); 00447 buf[size - 1] = '\0'; 00448 00449 return passwd.length(); 00450 } 00452 // STATIC 00453 bool 00454 SSLCtxMgr::checkClientCert(SSL* ssl, const String& hostName) 00455 { 00456 return checkCert(ssl, hostName, m_clientCertVerifyCB); 00457 } 00459 // STATIC 00460 bool 00461 SSLCtxMgr::checkServerCert(SSL* ssl, const String& hostName) 00462 { 00463 return checkCert(ssl, hostName, m_serverCertVerifyCB); 00464 } 00466 // STATIC 00467 bool 00468 SSLCtxMgr::checkCert(SSL* ssl, const String& hostName, 00469 certVerifyFuncPtr_t certVerifyCB) 00470 { 00471 BLOCXX_ASSERT(ssl != 0); 00472 00473 /* TODO this isn't working. 00474 if (SSL_get_verify_result(ssl)!=X509_V_OK) 00475 { 00476 cout << "SSL_get_verify_results failed." << endl; 00477 return false; 00478 } 00479 */ 00480 /*Check the cert chain. The chain length 00481 is automatically checked by OpenSSL when we 00482 set the verify depth in the ctx */ 00483 /*Check the common name*/ 00484 if (certVerifyCB) 00485 { 00486 X509 *peer = SSL_get_peer_certificate(ssl); 00487 X509Freer x509freer(peer); 00488 if (peer == 0) 00489 { 00490 return false; 00491 } 00492 if (certVerifyCB(peer, hostName) == 0) 00493 { 00494 return false; 00495 } 00496 else 00497 { 00498 return true; 00499 } 00500 } 00501 return true; 00502 } 00504 // STATIC 00505 int 00506 SSLCtxMgr::sslRead(SSL* ssl, char* buf, int len) 00507 { 00508 int cc = SSL_ERROR_WANT_READ; 00509 int r = -1; 00510 int retries = 0; 00511 while (cc == SSL_ERROR_WANT_READ && retries < BLOCXX_SSL_RETRY_LIMIT) 00512 { 00513 r = SSL_read(ssl, buf, len); 00514 cc = SSL_get_error(ssl, r); 00515 retries++; 00516 } 00517 00518 switch (cc) 00519 { 00520 case SSL_ERROR_NONE: 00521 return r; 00522 case SSL_ERROR_ZERO_RETURN: 00523 return -1; 00524 default: 00525 return -1; 00526 } 00527 } 00529 // STATIC 00530 int 00531 SSLCtxMgr::sslWrite(SSL* ssl, const char* buf, int len) 00532 { 00533 int r = 0; 00534 int cc; 00535 int retries; 00536 int myLen = len; 00537 int offset = 0; 00538 #ifndef BLOCXX_WIN32 00539 // block SIGPIPE so we don't kill the process if the socket is closed. 00540 SignalScope ss(SIGPIPE, SIG_IGN); 00541 #endif 00542 while (myLen > 0) 00543 { 00544 cc = SSL_ERROR_WANT_WRITE; 00545 retries = 0; 00546 while(cc == SSL_ERROR_WANT_WRITE && retries < BLOCXX_SSL_RETRY_LIMIT) 00547 { 00548 r = SSL_write(ssl, buf + offset, myLen); 00549 cc = SSL_get_error(ssl, r); 00550 retries++; 00551 } 00552 00553 if (cc == SSL_ERROR_NONE) 00554 { 00555 myLen -= r; 00556 offset += r; 00557 } 00558 else 00559 { 00560 return -1; 00561 } 00562 } 00563 return len; 00564 } 00566 void 00567 SSLCtxMgr::uninit() 00568 { 00569 uninitClient(); 00570 uninitServer(); 00571 00572 MutexLock initLock(m_initStateGuard); 00573 if (m_initState == BLOCXX_SSL_LIBRARY_INITIALIZED) 00574 { 00575 // free up memory allocated in SSL_library_init() 00576 EVP_cleanup(); 00577 // free up memory allocated in SSL_load_error_strings() 00578 ERR_free_strings(); 00579 00580 m_initState = BLOCXX_SSL_LIBRARY_NOT_INITIALIZED; 00581 } 00582 } 00584 void 00585 SSLCtxMgr::uninitClient() 00586 { 00587 if (m_ctxClient) 00588 { 00589 SSL_CTX_free(m_ctxClient); 00590 m_ctxClient = NULL; 00591 } 00592 } 00594 void 00595 SSLCtxMgr::uninitServer() 00596 { 00597 if (m_ctxServer) 00598 { 00599 SSL_CTX_free(m_ctxServer); 00600 m_ctxServer = NULL; 00601 } 00602 } 00603 00604 namespace 00605 { 00606 00608 extern "C" 00609 { 00610 static int verify_callback(int ok, X509_STORE_CTX *store) 00611 { 00612 int index = SSL_get_ex_data_X509_STORE_CTX_idx(); 00613 if (index < 0) 00614 { 00615 return 0; 00616 } 00617 SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store, index)); 00618 if (ssl == 0) 00619 { 00620 return 0; 00621 } 00622 OWSSLContext* owctx = static_cast<OWSSLContext*>(SSL_get_ex_data(ssl, SSLServerCtx::SSL_DATA_INDEX)); 00623 BLOCXX_ASSERT(owctx); 00624 if (owctx == 0) 00625 { 00626 return 0; 00627 } 00628 00639 if (!ok) 00640 { 00641 owctx->peerCertPassedVerify = OWSSLContext::VERIFY_FAIL; 00642 } 00643 else 00644 { 00645 // if the cert failed on a previous call, we don't want to change 00646 // the status. 00647 if (owctx->peerCertPassedVerify != OWSSLContext::VERIFY_FAIL) 00648 { 00649 owctx->peerCertPassedVerify = OWSSLContext::VERIFY_PASS; 00650 } 00651 } 00652 00653 #ifdef BLOCXX_DEBUG 00654 if (!ok) 00655 { 00656 char data[256]; 00657 X509 *cert = X509_STORE_CTX_get_current_cert(store); 00658 int depth = X509_STORE_CTX_get_error_depth(store); 00659 int err = X509_STORE_CTX_get_error(store); 00660 00661 fprintf(stderr, "-Error with certificate at depth: %i\n", depth); 00662 X509_NAME_oneline(X509_get_issuer_name(cert), data, 256); 00663 fprintf(stderr, " issuer = %s\n", data); 00664 X509_NAME_oneline(X509_get_subject_name(cert), data, 256); 00665 fprintf(stderr, " subject = %s\n", data); 00666 fprintf(stderr, " err %i:%s\n", err, X509_verify_cert_error_string(err)); 00667 } 00668 #endif 00669 00670 return 1; 00671 } 00672 } // end extern "C" 00673 00674 } // end unnamed namespace 00675 00677 SSLCtxBase::SSLCtxBase(const SSLOpts& opts) 00678 : m_ctx(0) 00679 { 00680 m_ctx = SSLCtxMgr::initCtx(opts.certfile, opts.keyfile, opts.pkey); 00681 00682 SSLCtxMgr::generateEphRSAKey(m_ctx); // TODO what the heck is this? 00683 String sessID("SSL_SESSION_"); 00684 sessID += String(Secure::rand_range<UInt16>(0, 10000)); 00685 int sessIDLen = 00686 (SSL_MAX_SSL_SESSION_ID_LENGTH < (sessID.length())) ? 00687 SSL_MAX_SSL_SESSION_ID_LENGTH : (sessID.length()); 00688 ERR_clear_error(); 00689 if (SSL_CTX_set_session_id_context(m_ctx, reinterpret_cast<const unsigned char*>(sessID.c_str()), sessIDLen) != 1) 00690 { 00691 SSL_CTX_free(m_ctx); 00692 BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initServer(): SSL_CTX_set_session_id_context failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str()); 00693 } 00694 00695 if (opts.verifyMode != SSLOpts::MODE_DISABLED && !opts.trustStore.empty()) 00696 { 00697 if (!FileSystem::exists(opts.trustStore)) 00698 { 00699 SSL_CTX_free(m_ctx); 00700 BLOCXX_THROW(SSLException, Format("Error loading truststore %1", 00701 opts.trustStore).c_str()); 00702 } 00703 if (SSL_CTX_load_verify_locations(m_ctx,0,opts.trustStore.c_str()) != 1) 00704 { 00705 SSL_CTX_free(m_ctx); 00706 BLOCXX_THROW(SSLException, Format("Error loading truststore %1: %2", opts.trustStore, SSLCtxMgr::getOpenSSLErrorDescription()).c_str()); 00707 } 00708 } 00709 /* TODO remove. 00710 if (SSL_CTX_set_default_verify_paths(m_ctx) != 1) 00711 { 00712 BLOCXX_THROW(SSLException, "Error loading default CA store(s)"); 00713 } 00714 */ 00715 switch (opts.verifyMode) 00716 { 00717 case SSLOpts::MODE_DISABLED: 00718 SSL_CTX_set_verify(m_ctx, SSL_VERIFY_NONE, 0); 00719 break; 00720 case SSLOpts::MODE_REQUIRED: 00721 SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0); 00722 break; 00723 case SSLOpts::MODE_OPTIONAL: 00724 case SSLOpts::MODE_AUTOUPDATE: 00725 SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER, verify_callback); 00726 break; 00727 default: 00728 BLOCXX_ASSERTMSG(false, "Bad option, shouldn't happen"); 00729 break; 00730 } 00731 00732 SSL_CTX_set_verify_depth(m_ctx, 4); 00733 00734 } 00735 00737 SSLCtxBase::~SSLCtxBase() 00738 { 00739 if (m_ctx) 00740 { 00741 SSL_CTX_free(m_ctx); 00742 } 00743 ERR_clear_error(); 00744 ERR_remove_state(0); 00745 } 00746 00748 SSL_CTX* 00749 SSLCtxBase::getSSLCtx() const 00750 { 00751 return m_ctx; 00752 } 00753 00754 SSLOpts::SSLOpts() 00755 : verifyMode(MODE_DISABLED) 00756 , pkey(0) 00757 { 00758 } 00759 00760 SSLOpts::~SSLOpts() 00761 { 00762 if (pkey != 0) 00763 { 00764 EVP_PKEY_free(pkey); 00765 pkey = 0; 00766 } 00767 } 00768 00769 00770 00772 SSLServerCtx::SSLServerCtx(const SSLOpts& opts) 00773 : SSLCtxBase(opts) 00774 { 00775 } 00777 SSLClientCtx::SSLClientCtx(const SSLOpts& opts) 00778 : SSLCtxBase(opts) 00779 { 00780 } 00781 00782 static GlobalMutex m_mapGuard = BLOCXX_GLOBAL_MUTEX_INIT(); 00783 00785 SSLTrustStore::SSLTrustStore(const String& storeLocation) 00786 : m_store(storeLocation) 00787 { 00788 m_mapfile = m_store + "/map"; 00789 if (FileSystem::exists(m_mapfile)) 00790 { 00791 MutexLock mlock(m_mapGuard); 00792 readMap(); 00793 } 00794 } 00795 00797 bool 00798 SSLTrustStore::getUser(const String& certhash, String& user, String& uid) 00799 { 00800 MutexLock mlock(m_mapGuard); 00801 Map<String, UserInfo>::const_iterator iter = m_map.find(certhash); 00802 if (iter == m_map.end()) 00803 { 00804 return false; 00805 } 00806 user = iter->second.user; 00807 uid = iter->second.uid; 00808 return true; 00809 } 00810 00812 void 00813 SSLTrustStore::addCertificate(X509* cert, const String& user, const String& uid) 00814 { 00815 static const int numtries = 1000; 00816 BLOCXX_ASSERT(cert); 00817 OStringStream ss; 00818 unsigned long hash = X509_subject_name_hash(cert); 00819 ss << std::hex << hash; 00820 String filename = m_store + "/" + ss.toString() + "."; 00821 int i = 0; 00822 for (i = 0; i < numtries; ++i) 00823 { 00824 String temp = filename + String(i); 00825 if (FileSystem::exists(temp)) 00826 { 00827 continue; 00828 } 00829 filename = temp; 00830 break; 00831 } 00832 if (i == numtries) 00833 { 00834 BLOCXX_THROW(SSLException, "Unable to find a valid filename to store cert"); 00835 } 00836 FILE* fp = fopen(filename.c_str(), "w"); 00837 if (!fp) 00838 { 00839 BLOCXX_THROW_ERRNO_MSG(SSLException, Format("Unable to open new cert file for writing: %1", filename).c_str()); 00840 } 00841 00842 ERR_clear_error(); 00843 // Undocumented function in OpenSSL. We assume it returns 1 on success 00844 // like most OpenSSL funcs. 00845 if (PEM_write_X509(fp, cert) != 1) 00846 { 00847 fclose(fp); 00848 BLOCXX_THROW(SSLException, Format("SSL error while writing certificate to %1: %2", filename, SSLCtxMgr::getOpenSSLErrorDescription()).c_str()); 00849 } 00850 fclose(fp); 00851 00852 String digest = getCertMD5Fingerprint(cert); 00853 MutexLock mlock(m_mapGuard); 00854 UserInfo info; 00855 info.user = user; 00856 info.uid = uid; 00857 m_map[digest] = info; 00858 writeMap(); 00859 } 00860 00862 String 00863 SSLTrustStore::getCertMD5Fingerprint(X509* cert) 00864 { 00865 unsigned char digest[16]; 00866 unsigned int len = 16; 00867 X509_digest(cert, EVP_md5(), digest, &len); 00868 return MD5::convertBinToHex(digest); 00869 } 00870 00872 void 00873 SSLTrustStore::writeMap() 00874 { 00875 std::ofstream f(m_mapfile.c_str(), std::ios::out); 00876 if (!f) 00877 { 00878 BLOCXX_THROW_ERRNO_MSG(SSLException, Format("SSL error opening map file: %1", m_mapfile).c_str()); 00879 } 00880 for (Map<String, UserInfo>::const_iterator iter = m_map.begin(); 00881 iter != m_map.end(); ++iter) 00882 { 00883 f << iter->first << " " << iter->second.user 00884 << " " << iter->second.uid << "\n"; 00885 } 00886 f.close(); 00887 } 00888 00890 void 00891 SSLTrustStore::readMap() 00892 { 00893 std::ifstream f(m_mapfile.c_str(), std::ios::in); 00894 if (!f) 00895 { 00896 BLOCXX_THROW_ERRNO_MSG(SSLException, Format("SSL error opening map file: %1", m_mapfile).c_str()); 00897 } 00898 int lineno = 0; 00899 while (f) 00900 { 00901 String line = String::getLine(f); 00902 if (!f) 00903 { 00904 break; 00905 } 00906 ++lineno; 00907 StringArray toks = line.tokenize(); 00908 if (toks.size() != 3 && toks.size() != 2) 00909 { 00910 BLOCXX_THROW(SSLException, Format("Error processing user map %1 at line %2", m_mapfile, lineno).c_str()); 00911 } 00912 UserInfo info; 00913 info.user = toks[1]; 00914 if (toks.size() == 3) 00915 { 00916 info.uid = toks[2]; 00917 } 00918 m_map.insert(std::make_pair(toks[0], info)); 00919 } 00920 #ifdef BLOCXX_DEBUG 00921 std::cerr << "cert<>user map initizialized with " << m_map.size() << " users" << std::endl; 00922 #endif 00923 f.close(); 00924 } 00925 00927 00928 OWSSLContext::OWSSLContext() 00929 : peerCertPassedVerify(VERIFY_NONE) 00930 { 00931 } 00933 OWSSLContext::~OWSSLContext() 00934 { 00935 } 00936 00937 00938 } // end namespace BLOCXX_NAMESPACE 00939 00940 #endif // #ifdef BLOCXX_HAVE_OPENSSL 00941