OW_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. 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 "OW_config.h"
00038 #ifdef OW_HAVE_OPENSSL
00039 #include "OW_SSLCtxMgr.hpp"
00040 #include "OW_GetPass.hpp"
00041 #include "OW_Format.hpp"
00042 #include "OW_FileSystem.hpp"
00043 #include "OW_ThreadImpl.hpp"
00044 #include "OW_Mutex.hpp"
00045 #include "OW_MutexLock.hpp"
00046 #include "OW_Assertion.hpp"
00047 #include "OW_MD5.hpp"
00048 #include "OW_Array.hpp"
00049 #include "OW_CryptographicRandomNumber.hpp"
00050 
00051 #include <openssl/rand.h>
00052 #include <openssl/err.h>
00053 #include <cstring>
00054 #include <csignal>
00055 #include <cerrno>
00056 #ifndef OW_WIN32
00057 #include <sys/time.h>
00058 #include <sys/resource.h>
00059 #endif
00060 #include <fcntl.h>
00061 
00062 #ifdef OW_HAVE_SYS_TYPES_H
00063 #include <sys/types.h>
00064 #endif
00065 
00066 #ifdef OW_HAVE_SYS_STAT_H
00067 #include <sys/stat.h>
00068 #endif
00069 
00070 #ifdef OW_HAVE_UNISTD_H
00071 #include <unistd.h>
00072 #endif
00073 
00074 #ifdef OW_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    OW_NAMESPACE::Mutex mutex;
00086 };
00087 }
00088 
00089 namespace OW_NAMESPACE
00090 {
00091 
00092 namespace
00093 {
00094 
00095 OW_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>(OW_NAMESPACE::ThreadImpl::thread_t_ToUInt64(OW_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    OW_ASSERT(freerv == 1);
00184    return rval;
00185 }
00186 
00188 SSL_CTX*
00189 SSLCtxMgr::initCtx(const String& certfile, const String& keyfile)
00190 {
00191    ERR_clear_error();
00192    SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
00193    if (ctx == 0)
00194    {
00195       OW_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 (!certfile.empty())
00199    {
00200       if (SSL_CTX_use_certificate_chain_file(ctx, certfile.c_str()) != 1)
00201       {
00202          SSL_CTX_free(ctx);
00203          OW_THROW(SSLException, Format("SSLCtxMgr::initCtx(): Couldn't read certificate from file: %1: %2",
00204             certfile, getOpenSSLErrorDescription()).c_str());
00205       }
00206       if (SSL_CTX_use_PrivateKey_file(ctx, keyfile.empty()?certfile.c_str():keyfile.c_str(), SSL_FILETYPE_PEM) != 1)
00207       {
00208          SSL_CTX_free(ctx);
00209          OW_THROW(SSLException, Format("SSLCtxMgr::initCtx(): Couldn't read key from file: %1: %2",
00210             keyfile.empty()?certfile:keyfile, getOpenSSLErrorDescription()).c_str());
00211       }
00212    }
00213 
00214    CryptographicRandomNumber::initRandomness();
00215 
00216    return ctx;
00217 }
00219 namespace
00220 {
00221 
00222 class SSLGlobalWork
00223 {
00224 public:
00225    SSLGlobalWork()
00226    {
00227       if (!mutex_buf)
00228       {
00229          mutex_buf = new Mutex[CRYPTO_num_locks()];
00230       }
00231       SSL_library_init();
00232       SSL_load_error_strings();
00233 
00234       CRYPTO_set_id_callback(id_function);
00235       CRYPTO_set_locking_callback(locking_function);
00236 
00237        // The following three CRYPTO_... functions are the OpenSSL functions
00238       // for registering the callbacks we implemented above
00239       CRYPTO_set_dynlock_create_callback(dyn_create_function);
00240       CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
00241       CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
00242    }
00243 
00244    ~SSLGlobalWork()
00245    {
00246       if (SSLCtxMgr::isClient() || SSLCtxMgr::isServer())
00247       {
00248          CryptographicRandomNumber::saveRandomState();
00249       }
00250       SSLCtxMgr::uninit();
00251       delete[] mutex_buf;
00252       mutex_buf = 0;
00253    }
00254 private:
00255 };
00256 
00257 SSLGlobalWork g_sslGLobalWork;
00258 
00259 } // end unnamed namespace
00260 
00262 void
00263 SSLCtxMgr::loadDHParams(SSL_CTX* ctx, const String& file)
00264 {
00265    OW_ASSERT(ctx != 0);
00266    ERR_clear_error();
00267    BIO* bio = BIO_new_file(file.c_str(), "r");
00268    if (bio == NULL)
00269    {
00270       OW_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): Couldn't open DH file %1: %2", file, getOpenSSLErrorDescription()).c_str());
00271    }
00272    DH* ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
00273    BIO_free(bio);
00274    if (ret == 0)
00275    {
00276       OW_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): PEM_read_bio_DHparams failed: %1", getOpenSSLErrorDescription()).c_str());
00277    }
00278    if (SSL_CTX_set_tmp_dh(ctx, ret) != 1)
00279    {
00280       OW_THROW(SSLException, Format("SSLCtxMgr::loadDHParams(): Couldn't set DH parameters because SSL_CTX_set_tmp_dh failed: %1", getOpenSSLErrorDescription()).c_str());
00281    }
00282 }
00284 void
00285 SSLCtxMgr::generateEphRSAKey(SSL_CTX* ctx)
00286 {
00287    OW_ASSERT(ctx != 0);
00288    ERR_clear_error();
00289    RSA* rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
00290    if (rsa == 0)
00291    {
00292       OW_THROW(SSLException, Format("SSLCtxMgr::generateEphRSAKey(): RSA_generate_key failed: %1", getOpenSSLErrorDescription()).c_str());
00293    }
00294    if (SSL_CTX_set_tmp_rsa(ctx, rsa) != 1)
00295    {
00296       RSA_free(rsa);
00297       OW_THROW(SSLException, Format("SSLCtxMgr::generateEphRSAKey(): SSL_CTX_set_tmp_rsa failed. Couldn't set RSA key: %1", getOpenSSLErrorDescription()).c_str());
00298    }
00299    RSA_free(rsa);
00300 }
00302 void
00303 SSLCtxMgr::initClient(const String& certfile, const String& keyfile)
00304 {
00305    if (m_ctxClient)
00306    {
00307       uninitClient();
00308    }
00309    m_ctxClient = initCtx(certfile,keyfile);
00310 }
00312 void
00313 SSLCtxMgr::initServer(const String& certfile, const String& keyfile)
00314 {
00315    if (certfile.empty())
00316    {
00317       OW_THROW(SSLException, "SSLCtxMgr::initCtx(): no certificate file specified");
00318    }
00319    if (m_ctxServer)
00320    {
00321       uninitServer();
00322    }
00323    m_ctxServer = initCtx(certfile,keyfile);
00324    //loadDHParams(m_ctx, dhfile);
00325    generateEphRSAKey(m_ctxServer);
00326    String sessID("SSL_SESSION_");
00327    CryptographicRandomNumber rn(0, 10000);
00328    sessID += String(static_cast<UInt32>(rn.getNextNumber()));
00329    int sessIDLen =
00330       (SSL_MAX_SSL_SESSION_ID_LENGTH < (sessID.length())) ?
00331       SSL_MAX_SSL_SESSION_ID_LENGTH : (sessID.length());
00332    ERR_clear_error();
00333    if (SSL_CTX_set_session_id_context(m_ctxServer, reinterpret_cast<const unsigned char*>(sessID.c_str()), sessIDLen) != 1)
00334    {
00335       OW_THROW(SSLException, Format("SSLCtxMgr::initServer(): SSL_CTX_set_session_id_context failed: %1", getOpenSSLErrorDescription()).c_str());
00336    }
00337    SSL_CTX_set_verify(m_ctxServer, SSL_VERIFY_PEER /*| SSL_VERIFY_FAIL_IF_NO_PEER_CERT*/, NULL);
00338 }
00340 // STATIC
00341 int
00342 SSLCtxMgr::pem_passwd_cb(char* buf, int size, int /*rwflag*/,
00343    void* /*userData*/)
00344 {
00345    String passwd = GetPass::getPass("Enter the password for the SSL certificate: ");
00346 
00347    strncpy(buf, passwd.c_str(), size);
00348    buf[size - 1] = '\0';
00349 
00350    return passwd.length();
00351 }
00353 // STATIC
00354 bool
00355 SSLCtxMgr::checkClientCert(SSL* ssl, const String& hostName)
00356 {
00357    return checkCert(ssl, hostName, m_clientCertVerifyCB);
00358 }
00360 // STATIC
00361 bool
00362 SSLCtxMgr::checkServerCert(SSL* ssl, const String& hostName)
00363 {
00364    return checkCert(ssl, hostName, m_serverCertVerifyCB);
00365 }
00367 // STATIC
00368 bool
00369 SSLCtxMgr::checkCert(SSL* ssl, const String& hostName,
00370    certVerifyFuncPtr_t certVerifyCB)
00371 {
00372    OW_ASSERT(ssl != 0);
00373 
00374    /* TODO this isn't working.
00375    if (SSL_get_verify_result(ssl)!=X509_V_OK)
00376    {
00377       cout << "SSL_get_verify_results failed." << endl;
00378       return false;
00379    }
00380    */
00381    /*Check the cert chain. The chain length
00382      is automatically checked by OpenSSL when we
00383      set the verify depth in the ctx */
00384    /*Check the common name*/
00385    if (certVerifyCB)
00386    {
00387       X509 *peer = SSL_get_peer_certificate(ssl);
00388       X509Freer x509freer(peer);
00389       if (peer == 0)
00390       {
00391          return false;
00392       }
00393       if (certVerifyCB(peer, hostName) == 0)
00394       {
00395          return false;
00396       }
00397       else
00398       {
00399          return true;
00400       }
00401    }
00402    return true;
00403 }
00405 // STATIC
00406 int
00407 SSLCtxMgr::sslRead(SSL* ssl, char* buf, int len)
00408 {
00409    int cc = SSL_ERROR_WANT_READ;
00410    int r, retries = 0;
00411    while (cc == SSL_ERROR_WANT_READ && retries < OW_SSL_RETRY_LIMIT)
00412    {
00413       r = SSL_read(ssl, buf, len);
00414       cc = SSL_get_error(ssl, r);
00415       retries++;
00416    }
00417    
00418    switch (cc)
00419    {
00420       case SSL_ERROR_NONE:
00421          return r;
00422       case SSL_ERROR_ZERO_RETURN:
00423          return -1;
00424       default:
00425          return -1;
00426    }
00427 }
00429 // STATIC
00430 int
00431 SSLCtxMgr::sslWrite(SSL* ssl, const char* buf, int len)
00432 {
00433    int r, cc, retries;
00434    int myLen = len;
00435    int offset = 0;
00436    while (myLen > 0)
00437    {
00438       cc = SSL_ERROR_WANT_WRITE;
00439       retries = 0;
00440       while(cc == SSL_ERROR_WANT_WRITE && retries < OW_SSL_RETRY_LIMIT)
00441       {
00442          r = SSL_write(ssl, buf + offset, myLen);
00443          cc = SSL_get_error(ssl, r);
00444          retries++;
00445       }
00446 
00447       if (cc == SSL_ERROR_NONE)
00448       {
00449          myLen -= r;
00450          offset += r;
00451       }
00452       else
00453       {
00454          return -1;
00455       }
00456    }
00457    return len;
00458 }
00460 void
00461 SSLCtxMgr::uninit()
00462 {
00463    uninitClient();
00464    uninitServer();
00465       
00466    // free up memory allocated in SSL_library_init()
00467    EVP_cleanup();
00468    // free up memory allocated in SSL_load_error_strings()
00469    ERR_free_strings();
00470 }
00472 void
00473 SSLCtxMgr::uninitClient()
00474 {
00475    if (m_ctxClient)
00476    {
00477       SSL_CTX_free(m_ctxClient);
00478       m_ctxClient = NULL;
00479    }
00480 }
00482 void
00483 SSLCtxMgr::uninitServer()
00484 {
00485    if (m_ctxServer)
00486    {
00487       SSL_CTX_free(m_ctxServer);
00488       m_ctxServer = NULL;
00489    }
00490 }
00491 
00492 namespace
00493 {
00494 
00496 extern "C"
00497 {
00498 static int verify_callback(int ok, X509_STORE_CTX *store)
00499 {
00500    int index = SSL_get_ex_data_X509_STORE_CTX_idx();
00501    if (index < 0)
00502    {
00503       return 0;
00504    }
00505     SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store, index));
00506    if (ssl == 0)
00507    {
00508       return 0;
00509    }
00510     OWSSLContext* owctx = static_cast<OWSSLContext*>(SSL_get_ex_data(ssl, SSLServerCtx::SSL_DATA_INDEX));
00511     OW_ASSERT(owctx);
00512    if (owctx == 0)
00513    {
00514       return 0;
00515    }
00516 
00527    if (!ok)
00528    {
00529       owctx->peerCertPassedVerify = OWSSLContext::VERIFY_FAIL;
00530    }
00531    else
00532    {
00533       // if the cert failed on a previous call, we don't want to change
00534       // the status.
00535       if (owctx->peerCertPassedVerify != OWSSLContext::VERIFY_FAIL)
00536       {
00537          owctx->peerCertPassedVerify = OWSSLContext::VERIFY_PASS;
00538       }
00539    }
00540 
00541 #ifdef OW_DEBUG
00542     if (!ok)
00543     {
00544         char data[256];
00545         X509 *cert = X509_STORE_CTX_get_current_cert(store);
00546         int  depth = X509_STORE_CTX_get_error_depth(store);
00547         int  err = X509_STORE_CTX_get_error(store);
00548 
00549         fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
00550         X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
00551         fprintf(stderr, "  issuer   = %s\n", data);
00552         X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
00553         fprintf(stderr, "  subject  = %s\n", data);
00554         fprintf(stderr, "  err %i:%s\n", err, X509_verify_cert_error_string(err));
00555     }
00556 #endif
00557 
00558     return 1;
00559 }
00560 } // end extern "C"
00561 
00562 } // end unnamed namespace
00563 
00565 SSLCtxBase::SSLCtxBase(const SSLOpts& opts)
00566    : m_ctx(0)
00567 {
00568    m_ctx = SSLCtxMgr::initCtx(opts.certfile,opts.keyfile);
00569    
00570    SSLCtxMgr::generateEphRSAKey(m_ctx); // TODO what the heck is this?
00571    String sessID("SSL_SESSION_");
00572    CryptographicRandomNumber rn(0, 10000);
00573    sessID += String(static_cast<UInt32>(rn.getNextNumber()));
00574    int sessIDLen =
00575       (SSL_MAX_SSL_SESSION_ID_LENGTH < (sessID.length())) ?
00576       SSL_MAX_SSL_SESSION_ID_LENGTH : (sessID.length());
00577    ERR_clear_error();
00578    if (SSL_CTX_set_session_id_context(m_ctx, reinterpret_cast<const unsigned char*>(sessID.c_str()), sessIDLen) != 1)
00579    {
00580       SSL_CTX_free(m_ctx);
00581       OW_THROW(SSLException, Format("SSLCtxMgr::initServer(): SSL_CTX_set_session_id_context failed: %1", SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00582    }
00583 
00584    if (opts.verifyMode != SSLOpts::MODE_DISABLED && !opts.trustStore.empty())
00585    {
00586       if (!FileSystem::exists(opts.trustStore))
00587       {
00588          SSL_CTX_free(m_ctx);
00589          OW_THROW(SSLException, Format("Error loading truststore %1",
00590                                 opts.trustStore).c_str());
00591       }
00592       if (SSL_CTX_load_verify_locations(m_ctx,0,opts.trustStore.c_str()) != 1)
00593       {
00594          SSL_CTX_free(m_ctx);
00595          OW_THROW(SSLException, Format("Error loading truststore %1: %2", opts.trustStore, SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00596       }
00597    }
00598    /* TODO remove.
00599    if (SSL_CTX_set_default_verify_paths(m_ctx) != 1)
00600    {
00601       OW_THROW(SSLException, "Error loading default CA store(s)");
00602    }
00603    */
00604    switch (opts.verifyMode)
00605    {
00606    case SSLOpts::MODE_DISABLED:
00607       SSL_CTX_set_verify(m_ctx, SSL_VERIFY_NONE, 0);
00608       break;
00609    case SSLOpts::MODE_REQUIRED:
00610       SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
00611       break;
00612    case SSLOpts::MODE_OPTIONAL:
00613    case SSLOpts::MODE_AUTOUPDATE:
00614       SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER, verify_callback);
00615       break;
00616    default:
00617       OW_ASSERTMSG(false, "Bad option, shouldn't happen");
00618       break;
00619    }
00620 
00621    SSL_CTX_set_verify_depth(m_ctx, 4);
00622 
00623 }
00624 
00626 SSLCtxBase::~SSLCtxBase()
00627 {
00628    if (m_ctx)
00629    {
00630       SSL_CTX_free(m_ctx);
00631    }
00632    ERR_clear_error();
00633    ERR_remove_state(0);
00634 }
00635 
00637 SSL_CTX*
00638 SSLCtxBase::getSSLCtx() const
00639 {
00640    return m_ctx;
00641 }
00642 
00643 SSLOpts::SSLOpts()
00644    : verifyMode(MODE_DISABLED)
00645 {
00646 }
00647 
00648 
00649 
00650 
00651 
00653 SSLServerCtx::SSLServerCtx(const SSLOpts& opts)
00654    : SSLCtxBase(opts)
00655 {
00656 }
00658 SSLClientCtx::SSLClientCtx(const SSLOpts& opts)
00659    : SSLCtxBase(opts)
00660 {
00661 }
00662 
00663 static Mutex m_mapGuard;
00664 
00666 SSLTrustStore::SSLTrustStore(const String& storeLocation)
00667    : m_store(storeLocation)
00668 {
00669    m_mapfile = m_store + "/map";
00670    if (FileSystem::exists(m_mapfile))
00671    {
00672       MutexLock mlock(m_mapGuard);
00673       readMap();
00674    }
00675 }
00676 
00678 bool
00679 SSLTrustStore::getUser(const String& certhash, String& user, String& uid)
00680 {
00681    MutexLock mlock(m_mapGuard);
00682    Map<String, UserInfo>::const_iterator iter = m_map.find(certhash);
00683    if (iter == m_map.end())
00684    {
00685       return false;
00686    }
00687    user = iter->second.user;
00688    uid = iter->second.uid;
00689    return true;
00690 }
00691 
00693 void
00694 SSLTrustStore::addCertificate(X509* cert, const String& user, const String& uid)
00695 {
00696    static const int numtries = 1000;
00697    OW_ASSERT(cert);
00698    OStringStream ss;
00699    unsigned long hash = X509_subject_name_hash(cert);
00700    ss << std::hex << hash;
00701    String filename = m_store + "/" + ss.toString() + ".";
00702    int i = 0;
00703    for (i = 0; i < numtries; ++i)
00704    {
00705       String temp = filename + String(i);
00706       if (FileSystem::exists(temp))
00707       {
00708          continue;
00709       }
00710       filename = temp;
00711       break;
00712    }
00713    if (i == numtries)
00714    {
00715       OW_THROW(SSLException, "Unable to find a valid filename to store cert");
00716    }
00717    FILE* fp = fopen(filename.c_str(), "w");
00718    if (!fp)
00719    {
00720       OW_THROW_ERRNO_MSG(SSLException, Format("Unable to open new cert file for writing: %1", filename).c_str());
00721    }
00722 
00723    ERR_clear_error();
00724    // Undocumented function in OpenSSL.  We assume it returns 1 on success
00725    // like most OpenSSL funcs.
00726    if (PEM_write_X509(fp, cert) != 1)
00727    {
00728       fclose(fp);
00729       OW_THROW(SSLException, Format("SSL error while writing certificate to %1: %2", filename, SSLCtxMgr::getOpenSSLErrorDescription()).c_str());
00730    }
00731    fclose(fp);
00732 
00733    String digest = getCertMD5Fingerprint(cert);
00734    MutexLock mlock(m_mapGuard);
00735    UserInfo info;
00736    info.user = user;
00737    info.uid = uid;
00738    m_map[digest] = info;
00739    writeMap();
00740 }
00741 
00743 String
00744 SSLTrustStore::getCertMD5Fingerprint(X509* cert)
00745 {
00746    unsigned char digest[16];
00747    unsigned int len = 16;
00748    X509_digest(cert, EVP_md5(), digest, &len);
00749    return MD5::convertBinToHex(digest);
00750 }
00751 
00753 void
00754 SSLTrustStore::writeMap()
00755 {
00756    std::ofstream f(m_mapfile.c_str(), std::ios::out);
00757    if (!f)
00758    {
00759       OW_THROW_ERRNO_MSG(SSLException, Format("SSL error opening map file: %1", m_mapfile).c_str());
00760    }
00761    for (Map<String, UserInfo>::const_iterator iter = m_map.begin();
00762         iter != m_map.end(); ++iter)
00763    {
00764       f << iter->first << " " << iter->second.user
00765          << " " << iter->second.uid << "\n";
00766    }
00767    f.close();
00768 }
00769 
00771 void
00772 SSLTrustStore::readMap()
00773 {
00774    std::ifstream f(m_mapfile.c_str(), std::ios::in);
00775    if (!f)
00776    {
00777       OW_THROW_ERRNO_MSG(SSLException, Format("SSL error opening map file: %1", m_mapfile).c_str());
00778    }
00779    int lineno = 0;
00780    while (f)
00781    {
00782       String line = String::getLine(f);
00783       if (!f)
00784       {
00785          break;
00786       }
00787       ++lineno;
00788       StringArray toks = line.tokenize();
00789       if (toks.size() != 3 && toks.size() != 2)
00790       {
00791          OW_THROW(SSLException, Format("Error processing user map %1 at line %2", m_mapfile, lineno).c_str());
00792       }
00793       UserInfo info;
00794       info.user = toks[1];
00795       if (toks.size() == 3)
00796       {
00797          info.uid = toks[2];
00798       }
00799       m_map.insert(std::make_pair(toks[0], info));
00800    }
00801 #ifdef OW_DEBUG
00802    std::cerr << "cert<>user map initizialized with " << m_map.size() << " users" << std::endl;
00803 #endif
00804    f.close();
00805 }
00806 
00808 
00809 OWSSLContext::OWSSLContext()
00810     : peerCertPassedVerify(VERIFY_NONE)
00811 {
00812 }
00814 OWSSLContext::~OWSSLContext()
00815 {
00816 }
00817 
00818 
00819 } // end namespace OW_NAMESPACE
00820 
00821 #endif // #ifdef OW_HAVE_OPENSSL
00822 

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