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
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
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
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 }
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
00210
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 )
00243 {
00244 return new SSLGlobalWork();
00245 }
00246 };
00247
00248 LazyGlobal<SSLGlobalWork, int, SSLGlobalWorkFactory> g_SSLGlobalWork = BLOCXX_LAZY_GLOBAL_INIT(0);
00249
00250
00251 }
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
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
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
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
00303 Bool SSLCtxMgr::getSSLInitDisabled()
00304 {
00305 MutexLock lock(m_initStateGuard);
00306 return m_initState == BLOCXX_SSL_LIBRARY_INITIALIZATION_DISABLED;
00307 }
00308
00310
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();
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
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 , NULL);
00437 }
00439
00440 int
00441 SSLCtxMgr::pem_passwd_cb(char* buf, int size, int ,
00442 void* )
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
00453 bool
00454 SSLCtxMgr::checkClientCert(SSL* ssl, const String& hostName)
00455 {
00456 return checkCert(ssl, hostName, m_clientCertVerifyCB);
00457 }
00459
00460 bool
00461 SSLCtxMgr::checkServerCert(SSL* ssl, const String& hostName)
00462 {
00463 return checkCert(ssl, hostName, m_serverCertVerifyCB);
00464 }
00466
00467 bool
00468 SSLCtxMgr::checkCert(SSL* ssl, const String& hostName,
00469 certVerifyFuncPtr_t certVerifyCB)
00470 {
00471 BLOCXX_ASSERT(ssl != 0);
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
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
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
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
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
00576 EVP_cleanup();
00577
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
00646
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 }
00673
00674 }
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);
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
00710
00711
00712
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
00844
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 }
00939
00940 #endif // #ifdef BLOCXX_HAVE_OPENSSL
00941