Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

SSLCtxMgr.cpp

Go to the documentation of this file.
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., 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 
00037 #include "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/MutexLock.hpp"
00046 #include "blocxx/Assertion.hpp"
00047 #include "blocxx/MD5.hpp"
00048 #include "blocxx/Array.hpp"
00049 #include "blocxx/CryptographicRandomNumber.hpp"
00050 
00051 #include <openssl/rand.h>
00052 #include <openssl/err.h>
00053 #include <cstring>
00054 #include <csignal>
00055 #include <cerrno>
00056 #ifndef BLOCXX_WIN32
00057 #include <sys/time.h>
00058 #include <sys/resource.h>
00059 #endif
00060 #include <fcntl.h>
00061 
00062 #ifdef BLOCXX_HAVE_SYS_TYPES_H
00063 #include <sys/types.h>
00064 #endif
00065 
00066 #ifdef BLOCXX_HAVE_SYS_STAT_H
00067 #include <sys/stat.h>
00068 #endif
00069 
00070 #ifdef BLOCXX_HAVE_UNISTD_H
00071 #include <unistd.h>
00072 #endif
00073 
00074 #ifdef BLOCXX_DEBUG
00075 #include <iostream>
00076 #endif
00077 
00078 #include <fstream>
00079 
00080 // This struct has to be in the global namespace
00081 extern "C"
00082 {
00083 struct CRYPTO_dynlock_value
00084 {
00085    BLOCXX_NAMESPACE::Mutex mutex;
00086 };
00087 }
00088 
00089 namespace BLOCXX_NAMESPACE
00090 {
00091 
00092 namespace
00093 {
00094 
00095 BLOCXX_NAMESPACE::Mutex* mutex_buf = 0;
00096 
00097 extern "C"
00098 {
00099 
00100 static struct CRYPTO_dynlock_value * dyn_create_function(const char *,int)
00101 {
00102    return new CRYPTO_dynlock_value;
00103 }
00104 
00105 // these need to still be static, since they get exported because of extern "C"
00106 static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l,
00107               const char *, int)
00108 {
00109    if (mode & CRYPTO_LOCK)
00110    {
00111       l->mutex.acquire();
00112    }
00113    else
00114    {
00115       l->mutex.release();
00116    }
00117 }
00118 
00119 static void dyn_destroy_function(struct CRYPTO_dynlock_value *l,
00120              const char *, int)
00121 {
00122    delete l;
00123 }
00124 
00125 static unsigned long id_function()
00126 {
00127    return static_cast<unsigned long>(BLOCXX_NAMESPACE::ThreadImpl::thread_t_ToUInt64(BLOCXX_NAMESPACE::ThreadImpl::currentThread()));
00128 }
00129 
00130 static void locking_function(int mode, int n, const char*, int)
00131 {
00132    if (mode & CRYPTO_LOCK)
00133    {
00134       mutex_buf[n].acquire();
00135    }
00136    else
00137    {
00138       mutex_buf[n].release();
00139    }
00140 }
00141 } // end extern "C"
00142 
00143 class X509Freer
00144 {
00145 public:
00146    X509Freer(X509* x509)
00147       : m_x509(x509)
00148    {
00149    }
00150    ~X509Freer()
00151    {
00152       if (m_x509 != 0)
00153       {
00154          X509_free(m_x509);
00155       }
00156    }
00157 private:
00158    X509* m_x509;
00159 };
00160 
00161 } // end unnamed namespace
00162 
00163 SSL_CTX* SSLCtxMgr::m_ctxClient = 0;
00164 SSL_CTX* SSLCtxMgr::m_ctxServer = 0;
00165 certVerifyFuncPtr_t SSLCtxMgr::m_clientCertVerifyCB = 0;
00166 certVerifyFuncPtr_t SSLCtxMgr::m_serverCertVerifyCB = 0;
00167 
00169 // static
00170 String
00171 SSLCtxMgr::getOpenSSLErrorDescription()
00172 {
00173    BIO* bio = BIO_new(BIO_s_mem());
00174    if (!bio)
00175    {
00176       return String();
00177    }
00178    ERR_print_errors(bio);
00179    char* p = 0;
00180    long len = BIO_get_mem_data(bio, &p);
00181    String rval(p, len);
00182    int freerv = BIO_free(bio);
00183    BLOCXX_ASSERT(freerv == 1);
00184    return rval;
00185 }
00186 
00188 SSL_CTX*
00189 SSLCtxMgr::initCtx(const String& keyfile)
00190 {
00191    ERR_clear_error();
00192    SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
00193    if (ctx == 0)
00194    {
00195       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initCtx(): SSL_CTX_new returned 0: %1", getOpenSSLErrorDescription()).c_str());
00196    }
00197    SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
00198    if (!keyfile.empty())
00199    {
00200       if (SSL_CTX_use_certificate_chain_file(ctx, keyfile.c_str()) != 1)
00201       {
00202          SSL_CTX_free(ctx);
00203          BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initCtx(): Couldn't read certificate file: %1: %2",
00204             keyfile, getOpenSSLErrorDescription()).c_str());
00205       }
00206       if (SSL_CTX_use_PrivateKey_file(ctx, keyfile.c_str(), SSL_FILETYPE_PEM) != 1)
00207       {
00208          SSL_CTX_free(ctx);
00209          BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initCtx(): Couldn't read key file: %1", getOpenSSLErrorDescription()).c_str());
00210       }
00211    }
00212 
00213    CryptographicRandomNumber::initRandomness();
00214 
00215    return ctx;
00216 }
00218 namespace
00219 {
00220 
00221 class SSLGlobalWork
00222 {
00223 public:
00224    SSLGlobalWork()
00225    {
00226       if (!mutex_buf)
00227       {
00228          mutex_buf = new Mutex[CRYPTO_num_locks()];
00229       }
00230       SSL_library_init();
00231       SSL_load_error_strings();
00232 
00233       CRYPTO_set_id_callback(id_function);
00234       CRYPTO_set_locking_callback(locking_function);
00235 
00236        // The following three CRYPTO_... functions are the OpenSSL functions
00237       // for registering the callbacks we implemented above
00238       CRYPTO_set_dynlock_create_callback(dyn_create_function);
00239       CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
00240       CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
00241    }
00242 
00243    ~SSLGlobalWork()
00244    {
00245       if (SSLCtxMgr::isClient() || SSLCtxMgr::isServer())
00246       {
00247          CryptographicRandomNumber::saveRandomState();
00248       }
00249       SSLCtxMgr::uninit();
00250       delete[] mutex_buf;
00251       mutex_buf = 0;
00252    }
00253 private:
00254 };
00255 
00256 SSLGlobalWork g_sslGLobalWork;
00257 
00258 } // end unnamed namespace
00259 
00261 void
00262 SSLCtxMgr::loadDHParams(SSL_CTX* ctx, const String& file)
00263 {
00264    BLOCXX_ASSERT(ctx != 0);
00265    ERR_clear_error();
00266    BIO* bio = BIO_new_file(file.c_str(), "r");
00267    if (bio == NULL)
00268    {
00269       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): Couldn't open DH file %1: %2", file, getOpenSSLErrorDescription()).c_str());
00270    }
00271    DH* ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
00272    BIO_free(bio);
00273    if (ret == 0)
00274    {
00275       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): PEM_read_bio_DHparams failed: %1", getOpenSSLErrorDescription()).c_str());
00276    }
00277    if (SSL_CTX_set_tmp_dh(ctx, ret) != 1)
00278    {
00279       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): Couldn't set DH parameters because SSL_CTX_set_tmp_dh failed: %1", getOpenSSLErrorDescription()).c_str());
00280    }
00281 }
00283 void
00284 SSLCtxMgr::generateEphRSAKey(SSL_CTX* ctx)
00285 {
00286    BLOCXX_ASSERT(ctx != 0);
00287    ERR_clear_error();
00288    RSA* rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
00289    if (rsa == 0)
00290    {
00291       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::generateEphRSAKey(): RSA_generate_key failed: %1", getOpenSSLErrorDescription()).c_str());
00292    }
00293    if (SSL_CTX_set_tmp_rsa(ctx, rsa) != 1)
00294    {
00295       RSA_free(rsa);
00296       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::generateEphRSAKey(): SSL_CTX_set_tmp_rsa failed. Couldn't set RSA key: %1", getOpenSSLErrorDescription()).c_str());
00297    }
00298    RSA_free(rsa);
00299 }
00301 void
00302 SSLCtxMgr::initClient(const String& keyfile)
00303 {
00304    if (m_ctxClient)
00305    {
00306       uninitClient();
00307    }
00308    m_ctxClient = initCtx(keyfile);
00309 }
00311 void
00312 SSLCtxMgr::initServer(const String& keyfile)
00313 {
00314    if (m_ctxServer)
00315    {
00316       uninitServer();
00317    }
00318    m_ctxServer = initCtx(keyfile);
00319    //loadDHParams(m_ctx, dhfile);
00320    generateEphRSAKey(m_ctxServer);
00321    String sessID("SSL_SESSION_");
00322    CryptographicRandomNumber rn(0, 10000);
00323    sessID += String(static_cast<UInt32>(rn.getNextNumber()));
00324    int sessIDLen =
00325       (SSL_MAX_SSL_SESSION_ID_LENGTH < (sessID.length())) ?
00326       SSL_MAX_SSL_SESSION_ID_LENGTH : (sessID.length());
00327    ERR_clear_error();
00328    if (SSL_CTX_set_session_id_context(m_ctxServer, reinterpret_cast<const unsigned char*>(sessID.c_str()), sessIDLen) != 1)
00329    {
00330       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initServer(): SSL_CTX_set_session_id_context failed: %1", getOpenSSLErrorDescription()).c_str());
00331    }
00332    SSL_CTX_set_verify(m_ctxServer, SSL_VERIFY_PEER /*| SSL_VERIFY_FAIL_IF_NO_PEER_CERT*/, NULL);
00333 }
00335 // STATIC
00336 int
00337 SSLCtxMgr::pem_passwd_cb(char* buf, int size, int /*rwflag*/,
00338    void* /*userData*/)
00339 {
00340    String passwd = GetPass::getPass("Enter the password for the SSL certificate: ");
00341 
00342    strncpy(buf, passwd.c_str(), size);
00343    buf[size - 1] = '\0';
00344 
00345    return passwd.length();
00346 }
00348 // STATIC
00349 bool
00350 SSLCtxMgr::checkClientCert(SSL* ssl, const String& hostName)
00351 {
00352    return checkCert(ssl, hostName, m_clientCertVerifyCB);
00353 }
00355 // STATIC
00356 bool
00357 SSLCtxMgr::checkServerCert(SSL* ssl, const String& hostName)
00358 {
00359    return checkCert(ssl, hostName, m_serverCertVerifyCB);
00360 }
00362 // STATIC
00363 bool
00364 SSLCtxMgr::checkCert(SSL* ssl, const String& hostName,
00365    certVerifyFuncPtr_t certVerifyCB)
00366 {
00367    BLOCXX_ASSERT(ssl != 0);
00368 
00369    /* TODO this isn't working.
00370    if (SSL_get_verify_result(ssl)!=X509_V_OK)
00371    {
00372       cout << "SSL_get_verify_results failed." << endl;
00373       return false;
00374    }
00375    */
00376    /*Check the cert chain. The chain length
00377      is automatically checked by OpenSSL when we
00378      set the verify depth in the ctx */
00379    /*Check the common name*/
00380    if (certVerifyCB)
00381    {
00382       X509 *peer = SSL_get_peer_certificate(ssl);
00383       X509Freer x509freer(peer);
00384       if (peer == 0)
00385       {
00386          return false;
00387       }
00388       if (certVerifyCB(peer, hostName) == 0)
00389       {
00390          return false;
00391       }
00392       else
00393       {
00394          return true;
00395       }
00396    }
00397    return true;
00398 }
00400 // STATIC
00401 int
00402 SSLCtxMgr::sslRead(SSL* ssl, char* buf, int len)
00403 {
00404    int cc = SSL_ERROR_WANT_READ;
00405    int r, retries = 0;
00406    while (cc == SSL_ERROR_WANT_READ && retries < BLOCXX_SSL_RETRY_LIMIT)
00407    {
00408       r = SSL_read(ssl, buf, len);
00409       cc = SSL_get_error(ssl, r);
00410       retries++;
00411    }
00412    
00413    switch (cc)
00414    {
00415       case SSL_ERROR_NONE:
00416          return r;
00417       case SSL_ERROR_ZERO_RETURN:
00418          return -1;
00419       default:
00420          return -1;
00421    }
00422 }
00424 // STATIC
00425 int
00426 SSLCtxMgr::sslWrite(SSL* ssl, const char* buf, int len)
00427 {
00428    int r, cc, retries;
00429    int myLen = len;
00430    int offset = 0;
00431    while (myLen > 0)
00432    {
00433       cc = SSL_ERROR_WANT_WRITE;
00434       retries = 0;
00435       while(cc == SSL_ERROR_WANT_WRITE && retries < BLOCXX_SSL_RETRY_LIMIT)
00436       {
00437          r = SSL_write(ssl, buf + offset, myLen);
00438          cc = SSL_get_error(ssl, r);
00439          retries++;
00440       }
00441 
00442       if (cc == SSL_ERROR_NONE)
00443       {
00444          myLen -= r;
00445          offset += r;
00446       }
00447       else
00448       {
00449          return -1;
00450       }
00451    }
00452    return len;
00453 }
00455 void
00456 SSLCtxMgr::uninit()
00457 {
00458    uninitClient();
00459    uninitServer();
00460       
00461    // free up memory allocated in SSL_library_init()
00462    EVP_cleanup();
00463    // free up memory allocated in SSL_load_error_strings()
00464    ERR_free_strings();
00465 }
00467 void
00468 SSLCtxMgr::uninitClient()
00469 {
00470    if (m_ctxClient)
00471    {
00472       SSL_CTX_free(m_ctxClient);
00473       m_ctxClient = NULL;
00474    }
00475 }
00477 void
00478 SSLCtxMgr::uninitServer()
00479 {
00480    if (m_ctxServer)
00481    {
00482       SSL_CTX_free(m_ctxServer);
00483       m_ctxServer = NULL;
00484    }
00485 }
00486 
00487 namespace
00488 {
00489 
00491 extern "C"
00492 {
00493 static int verify_callback(int ok, X509_STORE_CTX *store)
00494 {
00495    int index = SSL_get_ex_data_X509_STORE_CTX_idx();
00496    if (index < 0)
00497    {
00498       return 0;
00499    }
00500     SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store, index));
00501    if (ssl == 0)
00502    {
00503       return 0;
00504    }
00505     OWSSLContext* owctx = static_cast<OWSSLContext*>(SSL_get_ex_data(ssl, SSLServerCtx::SSL_DATA_INDEX));
00506     BLOCXX_ASSERT(owctx);
00507    if (owctx == 0)
00508    {
00509       return 0;
00510    }
00511 
00522    if (!ok)
00523    {
00524       owctx->peerCertPassedVerify = OWSSLContext::VERIFY_FAIL;
00525    }
00526    else
00527    {
00528       // if the cert failed on a previous call, we don't want to change
00529       // the status.
00530       if (owctx->peerCertPassedVerify != OWSSLContext::VERIFY_FAIL)
00531       {
00532          owctx->peerCertPassedVerify = OWSSLContext::VERIFY_PASS;
00533       }
00534    }
00535 
00536 #ifdef BLOCXX_DEBUG
00537     if (!ok)
00538     {
00539         char data[256];
00540         X509 *cert = X509_STORE_CTX_get_current_cert(store);
00541         int  depth = X509_STORE_CTX_get_error_depth(store);
00542         int  err = X509_STORE_CTX_get_error(store);
00543 
00544         fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
00545         X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
00546         fprintf(stderr, "  issuer   = %s\n", data);
00547         X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
00548         fprintf(stderr, "  subject  = %s\n", data);
00549         fprintf(stderr, "  err %i:%s\n", err, X509_verify_cert_error_string(err));
00550     }
00551 #endif
00552 
00553     return 1;
00554 }
00555 } // end extern "C"
00556 
00557 } // end unnamed namespace
00558 
00560 SSLCtxBase::SSLCtxBase(const SSLOpts& opts)
00561    : m_ctx(0)
00562 {
00563    m_ctx = SSLCtxMgr::initCtx(opts.keyfile);
00564    
00565    SSLCtxMgr::generateEphRSAKey(m_ctx); // TODO what the heck is this?
00566    String sessID("SSL_SESSION_");
00567    CryptographicRandomNumber rn(0, 10000);
00568    sessID += String(static_cast<UInt32>(rn.getNextNumber()));
00569    int sessIDLen =
00570       (SSL_MAX_SSL_SESSION_ID_LENGTH < (sessID.length())) ?
00571       SSL_MAX_SSL_SESSION_ID_LENGTH : (sessID.length());
00572    ERR_clear_error();
00573    if (SSL_CTX_set_session_id_context(m_ctx, reinterpret_cast<const unsigned char*>(sessID.c_str()), sessIDLen) != 1)
00574    {
00575       SSL_CTX_free(m_ctx);
00576       BLOCXX_THROW(SSLException, Format("SSLCtxMgr::initServer(): SSL_CTX_set_session_id_context failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00577    }
00578 
00579    if (opts.verifyMode != SSLOpts::MODE_DISABLED && !opts.trustStore.empty())
00580    {
00581       if (!FileSystem::exists(opts.trustStore))
00582       {
00583          SSL_CTX_free(m_ctx);
00584          BLOCXX_THROW(SSLException, Format("Error loading truststore %1",
00585                                 opts.trustStore).c_str());
00586       }
00587       if (SSL_CTX_load_verify_locations(m_ctx,0,opts.trustStore.c_str()) != 1)
00588       {
00589          SSL_CTX_free(m_ctx);
00590          BLOCXX_THROW(SSLException, Format("Error loading truststore %1: %2", opts.trustStore, SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00591       }
00592    }
00593    /* TODO remove.
00594    if (SSL_CTX_set_default_verify_paths(m_ctx) != 1)
00595    {
00596       OW_THROW(SSLException, "Error loading default CA store(s)");
00597    }
00598    */
00599    switch (opts.verifyMode)
00600    {
00601    case SSLOpts::MODE_DISABLED:
00602       SSL_CTX_set_verify(m_ctx, SSL_VERIFY_NONE, 0);
00603       break;
00604    case SSLOpts::MODE_REQUIRED:
00605       SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
00606       break;
00607    case SSLOpts::MODE_OPTIONAL:
00608    case SSLOpts::MODE_AUTOUPDATE:
00609       SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER, verify_callback);
00610       break;
00611    default:
00612       BLOCXX_ASSERTMSG(false, "Bad option, shouldn't happen");
00613       break;
00614    }
00615 
00616    SSL_CTX_set_verify_depth(m_ctx, 4);
00617 
00618 }
00619 
00621 SSLCtxBase::~SSLCtxBase()
00622 {
00623    if (m_ctx)
00624    {
00625       SSL_CTX_free(m_ctx);
00626    }
00627    ERR_clear_error();
00628    ERR_remove_state(0);
00629 }
00630 
00632 SSL_CTX*
00633 SSLCtxBase::getSSLCtx() const
00634 {
00635    return m_ctx;
00636 }
00637 
00638 SSLOpts::SSLOpts()
00639    : verifyMode(MODE_DISABLED)
00640 {
00641 }
00642 
00643 
00644 
00645 
00646 
00648 SSLServerCtx::SSLServerCtx(const SSLOpts& opts)
00649    : SSLCtxBase(opts)
00650 {
00651 }
00653 SSLClientCtx::SSLClientCtx(const SSLOpts& opts)
00654    : SSLCtxBase(opts)
00655 {
00656 }
00657 
00658 static Mutex m_mapGuard;
00659 
00661 SSLTrustStore::SSLTrustStore(const String& storeLocation)
00662    : m_store(storeLocation)
00663 {
00664    m_mapfile = m_store + "/map";
00665    if (FileSystem::exists(m_mapfile))
00666    {
00667       MutexLock mlock(m_mapGuard);
00668       readMap();
00669    }
00670 }
00671 
00673 bool
00674 SSLTrustStore::getUser(const String& certhash, String& user, String& uid)
00675 {
00676    MutexLock mlock(m_mapGuard);
00677    Map<String, UserInfo>::const_iterator iter = m_map.find(certhash);
00678    if (iter == m_map.end())
00679    {
00680       return false;
00681    }
00682    user = iter->second.user;
00683    uid = iter->second.uid;
00684    return true;
00685 }
00686 
00688 void
00689 SSLTrustStore::addCertificate(X509* cert, const String& user, const String& uid)
00690 {
00691    static const int numtries = 1000;
00692    BLOCXX_ASSERT(cert);
00693    OStringStream ss;
00694    unsigned long hash = X509_subject_name_hash(cert);
00695    ss << std::hex << hash;
00696    String filename = m_store + "/" + ss.toString() + ".";
00697    int i = 0;
00698    for (i = 0; i < numtries; ++i)
00699    {
00700       String temp = filename + String(i);
00701       if (FileSystem::exists(temp))
00702       {
00703          continue;
00704       }
00705       filename = temp;
00706       break;
00707    }
00708    if (i == numtries)
00709    {
00710       BLOCXX_THROW(SSLException, "Unable to find a valid filename to store cert");
00711    }
00712    FILE* fp = fopen(filename.c_str(), "w");
00713    if (!fp)
00714    {
00715       BLOCXX_THROW_ERRNO_MSG(SSLException, Format("Unable to open new cert file for writing: %1", filename).c_str());
00716    }
00717 
00718    ERR_clear_error();
00719    // Undocumented function in OpenSSL.  We assume it returns 1 on success
00720    // like most OpenSSL funcs.
00721    if (PEM_write_X509(fp, cert) != 1)
00722    {
00723       fclose(fp);
00724       BLOCXX_THROW(SSLException, Format("SSL error while writing certificate to %1: %2", filename, SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00725    }
00726    fclose(fp);
00727 
00728    String digest = getCertMD5Fingerprint(cert);
00729    MutexLock mlock(m_mapGuard);
00730    UserInfo info;
00731    info.user = user;
00732    info.uid = uid;
00733    m_map[digest] = info;
00734    writeMap();
00735 }
00736 
00738 String
00739 SSLTrustStore::getCertMD5Fingerprint(X509* cert)
00740 {
00741    unsigned char digest[16];
00742    unsigned int len = 16;
00743    X509_digest(cert, EVP_md5(), digest, &len);
00744    return MD5::convertBinToHex(digest);
00745 }
00746 
00748 void
00749 SSLTrustStore::writeMap()
00750 {
00751    std::ofstream f(m_mapfile.c_str(), std::ios::out);
00752    if (!f)
00753    {
00754       BLOCXX_THROW_ERRNO_MSG(SSLException, Format("SSL error opening map file: %1", m_mapfile).c_str());
00755    }
00756    for (Map<String, UserInfo>::const_iterator iter = m_map.begin();
00757         iter != m_map.end(); ++iter)
00758    {
00759       f << iter->first << " " << iter->second.user
00760          << " " << iter->second.uid << "\n";
00761    }
00762    f.close();
00763 }
00764 
00766 void
00767 SSLTrustStore::readMap()
00768 {
00769    std::ifstream f(m_mapfile.c_str(), std::ios::in);
00770    if (!f)
00771    {
00772       BLOCXX_THROW_ERRNO_MSG(SSLException, Format("SSL error opening map file: %1", m_mapfile).c_str());
00773    }
00774    int lineno = 0;
00775    while (f)
00776    {
00777       String line = String::getLine(f);
00778       if (!f)
00779       {
00780          break;
00781       }
00782       ++lineno;
00783       StringArray toks = line.tokenize();
00784       if (toks.size() != 3 && toks.size() != 2)
00785       {
00786          BLOCXX_THROW(SSLException, Format("Error processing user map %1 at line %2", m_mapfile, lineno).c_str());
00787       }
00788       UserInfo info;
00789       info.user = toks[1];
00790       if (toks.size() == 3)
00791       {
00792          info.uid = toks[2];
00793       }
00794       m_map.insert(std::make_pair(toks[0], info));
00795    }
00796 #ifdef BLOCXX_DEBUG
00797    std::cerr << "cert<>user map initizialized with " << m_map.size() << " users" << std::endl;
00798 #endif
00799    f.close();
00800 }
00801 
00803 
00804 OWSSLContext::OWSSLContext()
00805     : peerCertPassedVerify(VERIFY_NONE)
00806 {
00807 }
00809 OWSSLContext::~OWSSLContext()
00810 {
00811 }
00812 
00813 
00814 } // end namespace BLOCXX_NAMESPACE
00815 
00816 #endif // #ifdef BLOCXX_HAVE_OPENSSL
00817 

Generated on Mon Sep 12 23:56:36 2005 for blocxx by  doxygen 1.4.4