reSIProcate/stack  9694
Security.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #ifdef USE_SSL
00006 
00007 #include "resip/stack/ssl/Security.hxx"
00008 
00009 #include <ostream>
00010 #include <fstream>
00011 
00012 #include "resip/stack/Contents.hxx"
00013 #include "resip/stack/MultipartSignedContents.hxx"
00014 #include "resip/stack/Pkcs7Contents.hxx"
00015 #include "resip/stack/PlainContents.hxx"
00016 #include "resip/stack/SecurityAttributes.hxx"
00017 #include "resip/stack/Transport.hxx"
00018 #include "resip/stack/SipMessage.hxx"
00019 #include "rutil/BaseException.hxx"
00020 #include "rutil/DataStream.hxx"
00021 #include "rutil/Logger.hxx"
00022 #include "rutil/Random.hxx"
00023 #include "rutil/Socket.hxx"
00024 #include "rutil/Timer.hxx"
00025 #include "rutil/ParseBuffer.hxx"
00026 #include "rutil/FileSystem.hxx"
00027 #include "rutil/WinLeakCheck.hxx"
00028 
00029 #include "rutil/ssl/SHA1Stream.hxx"
00030 
00031 #if !defined(WIN32)
00032 #include <sys/types.h>
00033 #include <sys/uio.h>
00034 #include <sys/fcntl.h>
00035 #include <unistd.h>
00036 #include <dirent.h>
00037 #endif
00038 
00039 #include <sys/types.h>
00040 #include <openssl/e_os2.h>
00041 #include <openssl/evp.h>
00042 #include <openssl/crypto.h>
00043 #include <openssl/err.h>
00044 #include <openssl/pem.h>
00045 #include <openssl/pkcs7.h>
00046 #include <openssl/ossl_typ.h>
00047 #include <openssl/x509.h>
00048 #include <openssl/x509v3.h>
00049 #include <openssl/ssl.h>
00050 
00051 using namespace resip;
00052 using namespace std;
00053 
00054 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
00055 
00056 static const Data PEM(".pem");
00057 
00058 static const Data rootCert("root_cert_");
00059 static const Data domainCert("domain_cert_");
00060 static const Data domainKey("domain_key_");
00061 static const Data userCert("user_cert_");
00062 static const Data userKey("user_key_");
00063 static const Data unknownKey("user_key_");
00064 
00065 static const Data 
00066 pemTypePrefixes(  Security::PEMType pType )
00067 {
00068    switch (pType)
00069    {
00070       case  Security::RootCert:         return rootCert;
00071       case  Security::DomainCert:       return domainCert;
00072       case  Security::DomainPrivateKey: return domainKey;
00073       case  Security::UserCert:         return userCert;
00074       case  Security::UserPrivateKey:   return userKey;
00075       default:
00076       {
00077          ErrLog( << "Some unkonw pem type prefix requested" << (int)(pType) );
00078          assert(0);
00079       }
00080    }
00081    return unknownKey;
00082 }
00083 
00084 static Data
00085 readIntoData(const Data& filename)
00086 {
00087    DebugLog( << "Trying to read file " << filename );
00088    
00089    ifstream is;
00090    is.open(filename.c_str(), ios::binary );
00091    if ( !is.is_open() )
00092    {
00093       ErrLog( << "Could not open file " << filename << " for read");
00094       throw BaseSecurity::Exception("Could not read file ", 
00095                                     __FILE__,__LINE__);
00096    }
00097    
00098    assert(is.is_open());
00099    
00100    int length = 0;
00101    
00102    // get length of file:
00103 #if !defined(__MSL_CPP__) || (__MSL_CPP_ >= 0x00012000)
00104    is.seekg (0, ios::end);
00105    length = (int)is.tellg();
00106    is.seekg (0, ios::beg);
00107 #else
00108    // this is a work around for a bug in CodeWarrior 9's implementation of seekg.
00109    // http://groups.google.ca/group/comp.sys.mac.programmer.codewarrior/browse_frm/thread/a4279eb75f3bd55a
00110    FILE * tmpFile = fopen(filename.c_str(), "r+b");
00111    assert(tmpFile != NULL);
00112    fseek(tmpFile, 0, SEEK_END);
00113    length = ftell(tmpFile);
00114    fseek(tmpFile, 0, SEEK_SET);
00115 #endif // __MWERKS__
00116    
00117    // tellg/tell will return -1 if the stream is bad
00118    if (length == -1)
00119    {
00120       ErrLog( << "Could not seek into file " << filename);
00121       throw BaseSecurity::Exception("Could not seek into file ", 
00122                                     __FILE__,__LINE__);
00123    }
00124    
00125    // !jf! +1 is a workaround for a bug in Data::c_str() that adds the 0 without
00126    // resizing. 
00127    char* buffer = new char [length+1]; 
00128    
00129    // read data as a block:
00130    is.read (buffer,length);
00131    
00132    Data target(Data::Take, buffer, length);
00133    
00134    is.close();
00135    
00136    return target;
00137 }
00138 
00139 
00140 static Data
00141 getAor(const Data& filename, const  Security::PEMType &pemType )
00142 {
00143    const Data& prefix = pemTypePrefixes( pemType );
00144    return filename.substr(prefix.size(), filename.size() - prefix.size() - PEM.size());
00145 }
00146 
00147 extern "C"
00148 {
00149    
00150 static int 
00151 verifyCallback(int iInCode, X509_STORE_CTX *pInStore)
00152 {
00153    char cBuf1[500];
00154    char cBuf2[500];
00155    X509 *pErrCert;
00156    int iErr = 0;
00157    int iDepth = 0;
00158    pErrCert = X509_STORE_CTX_get_current_cert(pInStore);
00159    iErr = X509_STORE_CTX_get_error(pInStore);
00160    iDepth = X509_STORE_CTX_get_error_depth(pInStore);
00161 
00162    if (NULL != pErrCert)
00163       X509_NAME_oneline(X509_get_subject_name(pErrCert),cBuf1,256);
00164 
00165    sprintf(cBuf2,", depth=%d %s\n",iDepth,cBuf1);
00166    if(!iInCode)
00167       ErrLog(<< "Error when verifying server's chain of certificates: " << X509_verify_cert_error_string(pInStore->error) << cBuf2 );
00168  
00169    return iInCode;
00170 }
00171  
00172 }
00173 
00174 // .amr. RFC 5922 mandates exact match only on certificates, so this is the default, but RFC 2459 and RFC 3261 don't prevent wildcards, so enable if you want that mode.
00175 bool BaseSecurity::mAllowWildcardCertificates = false;
00176 BaseSecurity::CipherList BaseSecurity::ExportableSuite("!SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES:aRSA+RC4+MEDIUM:aDSS+RC4+MEDIUM:aRSA+DES:aDSS+DES:aRSA+RC4:aDSS+RC4");
00177 BaseSecurity::CipherList BaseSecurity::StrongestSuite("!SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES");
00178 
00179 Security::Security(const CipherList& cipherSuite) : BaseSecurity(cipherSuite)
00180 {
00181 #ifdef WIN32
00182    mPath = "C:\\sipCerts\\";
00183 #else
00184    const char* env=getenv("HOME");
00185    if(env)
00186    {
00187       mPath = env;
00188    }
00189    mPath += "/.sipCerts/";
00190 #endif
00191 }
00192 
00193 Security::Security(const Data& directory, const CipherList& cipherSuite) : 
00194    BaseSecurity(cipherSuite), 
00195    mPath(directory)
00196 {
00197    // since the preloader won't work otherwise and VERY difficult to figure
00198    // out. 
00199    if ( !mPath.postfix(Symbols::SLASH))
00200    {
00201       mPath += Symbols::SLASH;
00202    }
00203 }
00204 
00205 void
00206 Security::addCADirectory(const Data& caDirectory)
00207 {
00208    mCADirectories.push_back(caDirectory);
00209    Data &_dir = mCADirectories.back();
00210    if ( !_dir.postfix(Symbols::SLASH))
00211    {
00212       _dir += Symbols::SLASH;
00213    }
00214 }
00215 
00216 void
00217 Security::addCAFile(const Data& caFile)
00218 {
00219    mCAFiles.push_back(caFile);
00220 }
00221 
00222 void
00223 Security::preload()
00224 {
00225    FileSystem::Directory dir(mPath);
00226    FileSystem::Directory::iterator it(dir);
00227    for (; it != dir.end(); ++it)
00228    {
00229       Data name = *it;
00230            
00231       if (name.postfix(PEM))
00232       {
00233          Data fileName = mPath + name;
00234          bool attemptedToLoad = true;
00235          
00236          DebugLog(<< "Checking to load file " << name );
00237          try
00238          {
00239             if (name.prefix(pemTypePrefixes(UserCert)))
00240             {
00241                addCertPEM( UserCert, getAor(name, UserCert), readIntoData(fileName), false );
00242             }
00243             else if (name.prefix(pemTypePrefixes(UserPrivateKey)))
00244             {
00245                addPrivateKeyPEM( UserPrivateKey, getAor(name, UserPrivateKey), readIntoData(fileName), false);
00246             }
00247             else if (name.prefix(pemTypePrefixes(DomainCert)))
00248             {
00249                addCertPEM( DomainCert, getAor(name, DomainCert), readIntoData(fileName), false);
00250             }
00251             else if (name.prefix(pemTypePrefixes(DomainPrivateKey)))
00252             {
00253                addPrivateKeyPEM( DomainPrivateKey, getAor(name, DomainPrivateKey), readIntoData(fileName), false);
00254             }
00255             else if (name.prefix(pemTypePrefixes(RootCert)))
00256             {
00257                addRootCertPEM(readIntoData(fileName));
00258             }
00259             else
00260             {
00261                DebugLog(<< "PEM file " << name << " does not have appropriate resip prefix, skipping...");
00262                attemptedToLoad = false;
00263             }
00264          }
00265          catch (Exception& e)
00266          {
00267             ErrLog(<< "Some problem reading " << fileName << ": " << e);
00268          }
00269          catch (...)
00270          {  
00271             ErrLog(<< "Some problem reading " << fileName );
00272          }
00273          
00274          if(attemptedToLoad)
00275          {
00276             InfoLog(<<"Successfully loaded " << fileName );
00277          }
00278       }
00279    }
00280    std::list<Data>::iterator it_d = mCADirectories.begin();
00281    for (; it_d != mCADirectories.end(); ++it_d)
00282    {
00283       const Data _dir = *it_d;
00284       FileSystem::Directory dir(_dir);
00285       FileSystem::Directory::iterator it(dir);
00286       for (; it != dir.end(); ++it)
00287       {
00288          Data name = *it;
00289          Data fileName = _dir + name;
00290          addCAFile(fileName);
00291       }
00292    }
00293    std::list<Data>::iterator it_f = mCAFiles.begin();
00294    for (; it_f != mCAFiles.end(); ++it_f)
00295    {
00296       const Data _file = *it_f;
00297       try
00298       {
00299          addRootCertPEM(readIntoData(_file));
00300       }
00301       catch (Exception& e)
00302       {
00303          ErrLog(<< "Some problem reading " << _file << ": " << e);
00304       }
00305       catch (...)
00306       {
00307          ErrLog(<< "Some problem reading " << _file);
00308       }
00309    }
00310 }
00311 
00312 SSL_CTX* 
00313 Security::createDomainCtx(const SSL_METHOD* method, const Data& domain)
00314 {
00315 #if (OPENSSL_VERSION_NUMBER >= 0x1000000fL )
00316    SSL_CTX* ctx = SSL_CTX_new(method);
00317 #else
00318    SSL_CTX* ctx = SSL_CTX_new((SSL_METHOD*)method);
00319 #endif
00320    assert(ctx);
00321 
00322    X509_STORE* x509Store = X509_STORE_new();
00323    assert(x509Store);
00324 
00325    // Load root certs into store
00326    X509List::iterator it;
00327    for(it = mRootCerts.begin(); it != mRootCerts.end(); it++)
00328    {
00329       X509_STORE_add_cert(x509Store,*it);
00330    }
00331    SSL_CTX_set_cert_store(ctx, x509Store);
00332 
00333    // Load domain cert chain and private key
00334    if(!domain.empty())
00335    {
00336       Data certFilename(mPath + pemTypePrefixes(DomainCert) + domain + PEM);
00337       if(SSL_CTX_use_certificate_chain_file(ctx, certFilename.c_str()) != 1)
00338       {
00339          ErrLog (<< "Error reading domain chain file " << certFilename);
00340          SSL_CTX_free(ctx);
00341          throw BaseSecurity::Exception("Failed opening PEM chain file", __FILE__,__LINE__);
00342       }
00343       Data keyFilename(mPath + pemTypePrefixes(DomainPrivateKey) + domain + PEM);
00344       if(SSL_CTX_use_PrivateKey_file(ctx, keyFilename.c_str(), SSL_FILETYPE_PEM) != 1)
00345       {
00346          ErrLog (<< "Error reading domain private key file " << keyFilename);
00347          SSL_CTX_free(ctx);
00348          throw BaseSecurity::Exception("Failed opening PEM private key file", __FILE__,__LINE__);
00349       }
00350       if (!SSL_CTX_check_private_key(ctx))
00351       {
00352          ErrLog (<< "Invalid domain private key from file: " << keyFilename);
00353          SSL_CTX_free(ctx);
00354          throw BaseSecurity::Exception("Invalid domain private key", __FILE__,__LINE__);
00355       }
00356    }
00357 
00358    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
00359    SSL_CTX_set_cipher_list(ctx, mCipherList.cipherList().c_str());
00360 
00361    return ctx;
00362 }
00363 
00364 void
00365 Security::onReadPEM(const Data& name, PEMType type, Data& buffer) const
00366 {
00367    Data filename = mPath + pemTypePrefixes(type) + name + PEM;
00368 
00369    InfoLog (<< "Reading PEM file " << filename << " into " << name);
00370    // .dlb. extra copy
00371    buffer = readIntoData(filename);
00372 }
00373 
00374 
00375 void
00376 Security::onWritePEM(const Data& name, PEMType type, const Data& buffer) const
00377 {
00378    Data filename = mPath + pemTypePrefixes(type) + name + PEM;
00379    InfoLog (<< "Writing PEM file " << filename << " for " << name);
00380    ofstream str(filename.c_str(), ios::binary);
00381    if (!str)
00382    {
00383       ErrLog (<< "Can't write to " << filename);
00384       throw BaseSecurity::Exception("Failed opening PEM file", __FILE__,__LINE__);
00385    }
00386    else
00387    {
00388       str.write(buffer.data(), buffer.size());
00389       if (!str)
00390       {
00391          ErrLog (<< "Failed writing to " << filename << " " << buffer.size() << " bytes");
00392          throw BaseSecurity::Exception("Failed writing PEM file", __FILE__,__LINE__);
00393       }
00394    }
00395 }
00396 
00397 
00398 void
00399 Security::onRemovePEM(const Data& name, PEMType type) const
00400 {
00401    assert(0);
00402    // TODO - should delete file 
00403 }
00404 
00405 
00406 void
00407 BaseSecurity::addCertDER (PEMType type, 
00408                           const Data& key, 
00409                           const Data& certDER, 
00410                           bool write)
00411 {
00412    if( certDER.empty() )
00413    {
00414       ErrLog(<< "File is empty. Skipping.");
00415       return;
00416    }
00417 
00418    X509* cert = 0;
00419 
00420 #if (OPENSSL_VERSION_NUMBER < 0x0090800fL )
00421    unsigned char* in = (unsigned char*)certDER.data();
00422 #else
00423    unsigned const char* in = (unsigned const char*)certDER.data();
00424 #endif
00425 
00426    if (d2i_X509(&cert,&in,(long)certDER.size()) == 0)
00427    {
00428       ErrLog(<< "Could not read DER certificate from " << certDER );
00429       throw BaseSecurity::Exception("Could not read DER certificate ", 
00430                                     __FILE__,__LINE__);
00431    }
00432    addCertX509(type,key,cert,write);
00433 }
00434 
00435 
00436 void
00437 BaseSecurity::addCertPEM (PEMType type, 
00438                           const Data& name, 
00439                           const Data& certPEM, 
00440                           bool write)
00441 {
00442    if( certPEM.empty() )
00443    {
00444       ErrLog(<< name << " is empty. Skipping.");
00445       return;
00446    }
00447    X509* cert=NULL;
00448    
00449    BIO* in = BIO_new_mem_buf(const_cast<char*>(certPEM.c_str()), -1);
00450    if ( !in )
00451    {
00452       ErrLog(<< "Could not create BIO buffer from '" << certPEM << "'");
00453       throw Exception("Could not create BIO buffer", __FILE__,__LINE__);
00454    }
00455    cert = PEM_read_bio_X509(in,0,0,0);
00456    if (cert == NULL)
00457    {
00458       ErrLog( << "Could not load X509 cert from '" << certPEM << "'" );
00459       BIO_free(in); 
00460       throw Exception("Could not load X509 cert from BIO buffer", __FILE__,__LINE__);
00461    }
00462    
00463    addCertX509(type,name,cert,write);
00464    
00465    BIO_free(in);
00466 }
00467 
00468 
00469 void
00470 BaseSecurity::addCertX509(PEMType type, const Data& key, X509* cert, bool write)
00471 {
00472    switch (type)
00473    {
00474       case DomainCert:
00475       {
00476          mDomainCerts.insert(std::make_pair(key, cert));
00477       }
00478       break;
00479       case UserCert:
00480       { 
00481          mUserCerts.insert(std::make_pair(key, cert));
00482       }
00483       break;
00484       case RootCert:
00485       {
00486          mRootCerts.push_back(cert);
00487          X509_STORE_add_cert(mRootTlsCerts,cert);
00488          X509_STORE_add_cert(mRootSslCerts,cert);
00489       }
00490       break;
00491       default:
00492       {
00493          assert(0);
00494       }
00495    }
00496    
00497    if (write)
00498    {
00499       // creates a read/write BIO buffer.
00500       BIO *out = BIO_new(BIO_s_mem());
00501       if(!out)
00502       {
00503          ErrLog(<< "Failed to create BIO: this cert will not be added.");
00504          assert(0);
00505          return;
00506       }
00507 
00508       try
00509       {
00510          int ret = PEM_write_bio_X509(out, cert);
00511          if(!ret)
00512          {
00513             assert(0);
00514             throw Exception("PEM_write_bio_X509 failed: this cert will not be "
00515                               "added.", __FILE__,__LINE__);
00516          }
00517          
00518          (void)BIO_flush(out);
00519          // get content in BIO buffer to our buffer.
00520          char* p = 0;
00521          size_t len = BIO_get_mem_data(out,&p);
00522          if(!p || !len)
00523          {
00524             assert(0);
00525             throw Exception("BIO_get_mem_data failed: this cert will not be "
00526                               "added.", __FILE__,__LINE__);
00527          }
00528          Data  buf(Data::Borrow, p, len);
00529          
00530          this->onWritePEM(key, type, buf);
00531       }
00532       catch(Exception& e)
00533       {
00534          ErrLog(<<"Caught exception: " << e);
00535       }
00536       catch(std::exception& e)
00537       {
00538          ErrLog(<<"Caught unknown exception, rethrowing");
00539          BIO_free(out);
00540          throw e;
00541       }
00542       BIO_free(out);
00543    }
00544 }
00545 
00546 
00547 bool
00548 BaseSecurity::hasCert (PEMType type, const Data& aor) const
00549 {
00550    assert( !aor.empty() );
00551    const X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts);
00552 
00553    X509Map::const_iterator where = certs.find(aor);
00554    if (where != certs.end())
00555    {
00556       return true;
00557    }
00558    
00559    try
00560    {
00561       Data certPEM;
00562       onReadPEM(aor, type, certPEM);
00563       if (certPEM.empty())
00564       {
00565          return false;
00566       }
00567       BaseSecurity*  mutable_this = const_cast<BaseSecurity*>(this);
00568       mutable_this->addCertPEM(type, aor, certPEM, false);
00569    }
00570    catch (Exception& e)
00571    {
00572       ErrLog(<<"Caught exception: " << e);
00573       return   false;
00574    }
00575    catch (...)
00576    {
00577       ErrLog(<<"Caught exception: ");
00578       return   false;
00579    }
00580 
00581    assert(  certs.find(aor) != certs.end() );
00582    
00583    return   true;
00584 }
00585 
00586 
00587 void
00588 BaseSecurity::removeCert (PEMType type, const Data& aor)
00589 {
00590    assert( !aor.empty() );
00591    X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts);
00592 
00593    X509Map::iterator iter = certs.find(aor);
00594    if (iter != certs.end())
00595    {
00596       X509_free(iter->second);
00597       certs.erase(iter);
00598 
00599       onRemovePEM(aor, type);
00600    } 
00601 
00602    assert(  certs.find(aor) == certs.end() );
00603 }
00604 
00605 
00606 Data
00607 BaseSecurity::getCertDER (PEMType type, const Data& key) const
00608 {
00609    assert( !key.empty() );
00610 
00611    if (hasCert(type, key) == false)
00612    {
00613       ErrLog(<< "Could not find certificate for '" << key << "'");
00614       throw BaseSecurity::Exception("Could not find certificate", __FILE__,__LINE__);
00615    }
00616 
00617    const X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts);
00618    BaseSecurity::X509Map::const_iterator where = certs.find(key);
00619    if (where == certs.end())
00620    {
00621       // not supposed to happen,
00622       // hasCert() should have inserted a value into certs
00623       // or we should have throwed.
00624       assert(0);
00625    }
00626 
00627    //assert(0); // the code following this has no hope of working 
00628    
00629    X509* x = where->second;
00630    unsigned char* buffer=0;
00631    int len = i2d_X509(x, &buffer);
00632 
00633    // !kh!
00634    // Although len == 0 is not an error, I am not sure what quite to do.
00635    // Asserting for now.
00636    assert(len != 0);
00637    if(len < 0)
00638    {
00639       ErrLog(<< "Could encode certificate of '" << key << "' to DER form");
00640       throw BaseSecurity::Exception("Could encode certificate to DER form", __FILE__,__LINE__);
00641    }
00642    Data certDER((char*)buffer, len);
00643    OPENSSL_free(buffer);
00644    return certDER;
00645 }
00646 
00647 
00648 void 
00649 BaseSecurity::addPrivateKeyPKEY(PEMType type, 
00650                                 const Data& name, 
00651                                 EVP_PKEY* pKey, 
00652                                 bool write)
00653 { 
00654    PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? 
00655                                  mDomainPrivateKeys : mUserPrivateKeys);
00656 
00657    /*
00658    // make a copy of the the key 
00659    assert( EVP_PKEY_type(pKey->type) == EVP_PKEY_RSA );
00660    RSA* rsa = EVP_PKEY_get1_RSA(pKey);
00661    assert( rsa );
00662    EVP_PKEY* nKey = EVP_PKEY_new();
00663    assert( nKey );
00664    EVP_PKEY_set1_RSA(nKey, rsa);
00665    */
00666    
00667    //privateKeys.insert(std::make_pair(name, nKey));
00668    privateKeys.insert(std::make_pair(name, pKey));
00669       
00670    if (write)
00671    {
00672       // figure out a passPhrase to encrypt with 
00673       char* kstr=NULL;
00674       int klen=0;
00675       if (type != DomainPrivateKey)
00676       {
00677          PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name);
00678          if(iter != mUserPassPhrases.end())
00679          {
00680             kstr = (char*)iter->second.c_str(); 
00681             klen = (int)iter->second.size();
00682          }
00683       }
00684 
00685       BIO *bio = BIO_new(BIO_s_mem());
00686       if(!bio)
00687       {
00688          ErrLog(<< "BIO_new failed: cannot add private key.");
00689          assert(0);
00690       }
00691 
00692       try
00693       {
00694          assert( EVP_des_ede3_cbc() );
00695          const EVP_CIPHER* cipher = EVP_des_ede3_cbc();
00696          if (kstr == NULL )
00697          {
00698             cipher = NULL;
00699          }
00700 #if 0 // TODO - need to figure out what format to write in 
00701          int ret = PEM_write_bio_PrivateKey(bio, pKey, cipher, 
00702                                             (unsigned char*)kstr, klen,
00703                                             NULL, NULL);
00704 #else
00705          int ret = PEM_write_bio_PKCS8PrivateKey(bio, pKey, cipher, 
00706                                                  kstr, klen,
00707                                                  NULL, NULL);
00708 #endif
00709          if(!ret)
00710          {
00711             assert(0);
00712             throw Exception("PEM_write_bio_PKCS8PrivateKey failed: cannot add"
00713                               " private key.", __FILE__, __LINE__);
00714          }
00715 
00716          (void)BIO_flush(bio);
00717          char* p = 0;
00718          size_t len = BIO_get_mem_data(bio,&p);
00719          if(!p || !len)
00720          {
00721             assert(0);
00722             throw Exception("BIO_get_mem_data failed: cannot add"
00723                               " private key.", __FILE__, __LINE__);
00724          }
00725          Data  pem(Data::Borrow, p, len);
00726          onWritePEM(name, type, pem );
00727       }
00728       catch(Exception& e)
00729       {
00730          ErrLog( << "Caught exception: " << e);
00731       }
00732       catch(std::exception& e)
00733       {
00734          ErrLog(<<"Caught unknown exception, rethrowing: " << e.what());
00735          BIO_free(bio);
00736          throw e;
00737       }
00738       BIO_free(bio);
00739    }
00740 }
00741 
00742 
00743 void
00744 BaseSecurity::addPrivateKeyDER( PEMType type,
00745                                 const Data& name,
00746                                 const Data& privateKeyDER,
00747                                 bool write )
00748 {
00749    assert( !name.empty() );
00750    if( privateKeyDER.empty() )
00751    {
00752       ErrLog(<< name << " is empty. Skipping.");
00753       return;
00754    }
00755 
00756    char* passPhrase = 0;
00757    if (type != DomainPrivateKey)
00758    {
00759       PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name);
00760       if(iter != mUserPassPhrases.end())
00761       {
00762          passPhrase = const_cast<char*>(iter->second.c_str());
00763       }
00764    }
00765    
00766    BIO* in = BIO_new_mem_buf(const_cast<char*>(privateKeyDER.c_str()), -1);
00767    if ( !in )
00768    {
00769       ErrLog(<< "Could create BIO buffer from '" << privateKeyDER << "'");
00770       throw Exception("Could not create BIO buffer", __FILE__,__LINE__);
00771    }
00772    
00773    try
00774    {
00775 
00776       EVP_PKEY* privateKey;
00777       if (d2i_PKCS8PrivateKey_bio(in, &privateKey, 0, passPhrase) == 0)
00778       {
00779          ErrLog(<< "Could not read private key from <" << privateKeyDER << ">" );
00780          throw Exception("Could not read private key ", __FILE__,__LINE__);
00781       }
00782       
00783       addPrivateKeyPKEY(type,name,privateKey,write);
00784    }
00785    catch(std::exception& e)
00786    {
00787       ErrLog(<<"Caught exception: ");
00788       BIO_free(in);
00789       throw e;
00790    }
00791    
00792    BIO_free(in);
00793 }
00794 
00795 
00796 void
00797 BaseSecurity::addPrivateKeyPEM( PEMType type,
00798                                 const Data& name,
00799                                 const Data& privateKeyPEM,
00800                                 bool write )
00801 {
00802    assert( !name.empty() );
00803    if( privateKeyPEM.empty() )
00804    {
00805       ErrLog(<< name << " is empty. Skipping.");
00806       return;
00807    }
00808 
00809    BIO* in = BIO_new_mem_buf(const_cast<char*>(privateKeyPEM.c_str()), -1);
00810    if ( !in )
00811    {
00812       ErrLog(<< "Could create BIO buffer from '" << privateKeyPEM << "'");
00813       throw Exception("Could not create BIO buffer", __FILE__,__LINE__);
00814    }
00815    
00816    char* passPhrase = 0;
00817    try
00818    {
00819       if (type == UserPrivateKey)
00820       {
00821          PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name);
00822          if(iter != mUserPassPhrases.end())
00823          {
00824             passPhrase = const_cast<char*>(iter->second.c_str());
00825          }
00826       }
00827       
00828       EVP_PKEY* privateKey=0;
00829       if ( ( privateKey = PEM_read_bio_PrivateKey(in, NULL, 0, passPhrase)) == NULL)
00830       {
00831          ErrLog(<< "Could not read private key from <" << privateKeyPEM << ">" );
00832          throw Exception("Could not read private key ", __FILE__,__LINE__);
00833       }
00834       
00835       addPrivateKeyPKEY(type,name,privateKey,write);
00836    }
00837    catch(std::exception& e)
00838    {
00839       ErrLog(<<"Caught exception: ");
00840       BIO_free(in);
00841       throw e;
00842    }
00843 
00844    BIO_free(in);
00845 }
00846 
00847 
00848 bool
00849 BaseSecurity::hasPrivateKey( PEMType type,
00850                              const Data& key ) const
00851 {
00852    assert( !key.empty() );
00853 
00854    const PrivateKeyMap& privateKeys = (type == DomainPrivateKey 
00855                                  ? mDomainPrivateKeys : mUserPrivateKeys);
00856 
00857    PrivateKeyMap::const_iterator where = privateKeys.find(key);
00858    if (where != privateKeys.end())
00859    {
00860       return true;
00861    }
00862    
00863    Data privateKeyPEM;
00864    try
00865    {
00866       onReadPEM(key, type, privateKeyPEM);
00867       BaseSecurity* mutable_this = const_cast<BaseSecurity*>(this);
00868       mutable_this->addPrivateKeyPEM(type, key, privateKeyPEM, false);
00869    }
00870    catch(std::exception& e)
00871    {
00872       ErrLog(<<"Caught exception: " << e.what());
00873       return   false;
00874    }
00875    catch(...)
00876    {
00877       ErrLog(<<"Caught unknown class!");
00878       return   false;
00879    }
00880 
00881    return   true;
00882 }
00883 
00884 
00885 Data
00886 BaseSecurity::getPrivateKeyPEM( PEMType type,
00887                                 const Data& key) const
00888 {
00889    assert( !key.empty() );
00890 
00891    if ( !hasPrivateKey(type, key) )
00892    {
00893       ErrLog(<< "Could find private key for '" << key << "'");
00894       throw Exception("Could not find private key", __FILE__,__LINE__);
00895    }
00896 
00897    const PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys);
00898 
00899    PrivateKeyMap::const_iterator where = privateKeys.find(key);
00900    char* p = 0;
00901    if (type != DomainPrivateKey)
00902    {
00903       PassPhraseMap::const_iterator iter = mUserPassPhrases.find(key);
00904       if (iter != mUserPassPhrases.end())
00905       {
00906          p = const_cast<char*>(iter->second.c_str());
00907       }
00908    }
00909 
00910    assert(0); // TODO - following code has no hope of working 
00911     
00912    // !kh!
00913    // creates a read/write BIO buffer.
00914    BIO *out = BIO_new(BIO_s_mem());
00915    assert(out);
00916    EVP_PKEY* pk = where->second;
00917    assert(pk);
00918 
00919    // write pk to out using key phrase p, with no cipher.
00920    int ret = PEM_write_bio_PrivateKey(out, pk, 0, 0, 0, 0, p);  // paraters
00921                                                                 // are in the wrong order
00922    (void)ret;
00923    assert(ret == 1);
00924 
00925    // get content in BIO buffer to our buffer.
00926    // hand our buffer to a Data object.
00927    (void)BIO_flush(out);
00928    char* buf = 0;
00929    int len = BIO_get_mem_data(out, &buf);
00930    Data retVal(Data::Borrow, buf, len);
00931 
00932    BIO_free(out);
00933 
00934    return retVal;
00935 }
00936 
00937 
00938 Data
00939 BaseSecurity::getPrivateKeyDER( PEMType type,
00940                                 const Data& key) const
00941 {
00942    assert( !key.empty() );
00943 
00944    if ( !hasPrivateKey(type, key) )
00945    {
00946       ErrLog(<< "Could find private key for '" << key << "'");
00947       throw Exception("Could not find private key", __FILE__,__LINE__);
00948    }
00949 
00950    const PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys);
00951 
00952    PrivateKeyMap::const_iterator where = privateKeys.find(key);
00953    char* p = 0;
00954    if (type != DomainPrivateKey)
00955    {
00956       PassPhraseMap::const_iterator iter = mUserPassPhrases.find(key);
00957       if(iter != mUserPassPhrases.end())
00958       {
00959          p = const_cast<char*>(iter->second.c_str());
00960       }
00961    }
00962 
00963    assert(0); // TODO - following code has no hope of working 
00964     
00965    // !kh!
00966    // creates a read/write BIO buffer.
00967    BIO *out = BIO_new(BIO_s_mem());
00968    assert(out);
00969    EVP_PKEY* pk = where->second;
00970    assert(pk);
00971 
00972    // write pk to out using key phrase p, with no cipher.
00973    int ret = i2d_PKCS8PrivateKey_bio(out, pk, 0, 0, 0, 0, p);
00974    (void)ret;
00975    assert(ret == 1);
00976 
00977    // get content in BIO buffer to our buffer.
00978    // hand our buffer to a Data object.
00979    (void)BIO_flush(out);
00980    char* buf = 0;
00981    int len = BIO_get_mem_data(out, &buf);
00982    Data retVal(Data::Borrow, buf, len);
00983 
00984    BIO_free(out);
00985    
00986    return retVal;
00987 }
00988 
00989 
00990 void
00991 BaseSecurity::removePrivateKey(PEMType type, const Data& key)
00992 {
00993    assert( !key.empty() );
00994 
00995    PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys);
00996 
00997    assert( !key.empty() );
00998    PrivateKeyMap::iterator iter = privateKeys.find(key);
00999    if (iter != privateKeys.end())
01000    {
01001       EVP_PKEY_free(iter->second);
01002       privateKeys.erase(iter);
01003 
01004       onRemovePEM(key, type);
01005    }
01006 }
01007 
01008 
01009 Security::Exception::Exception(const Data& msg, const Data& file, const int line)
01010 :  BaseException(msg,file,line)
01011 {
01012 }
01013 
01014 
01015 BaseSecurity::BaseSecurity (const CipherList& cipherSuite) :
01016    mTlsCtx(0),
01017    mSslCtx(0),
01018    mCipherList(cipherSuite),
01019    mRootTlsCerts(0),                    
01020    mRootSslCerts(0)
01021 { 
01022    DebugLog(<< "BaseSecurity::BaseSecurity");
01023    
01024    int ret;
01025    initialize(); 
01026    
01027    mRootTlsCerts = X509_STORE_new();
01028    mRootSslCerts = X509_STORE_new();
01029    assert(mRootTlsCerts && mRootSslCerts);
01030 
01031    mTlsCtx = SSL_CTX_new( TLSv1_method() );
01032    if (!mTlsCtx)
01033    {
01034       ErrLog(<< "SSL_CTX_new failed, dumping OpenSSL error stack:");
01035       while (ERR_peek_error())
01036       {
01037          char errBuf[120];
01038          ERR_error_string(ERR_get_error(), errBuf);
01039          ErrLog(<< "OpenSSL error stack: " << errBuf);
01040       }
01041    }
01042    assert(mTlsCtx);
01043 
01044    SSL_CTX_set_cert_store(mTlsCtx, mRootTlsCerts);
01045    SSL_CTX_set_verify(mTlsCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
01046    ret = SSL_CTX_set_cipher_list(mTlsCtx, cipherSuite.cipherList().c_str());
01047    assert(ret);
01048    
01049    mSslCtx = SSL_CTX_new( SSLv23_method() );
01050    assert(mSslCtx);
01051    SSL_CTX_set_cert_store(mSslCtx, mRootSslCerts);
01052    SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
01053    ret = SSL_CTX_set_cipher_list(mSslCtx,cipherSuite.cipherList().c_str());
01054    assert(ret);
01055 }
01056 
01057 
01058 template<class T, class Func> 
01059 void clearMap(T& m, Func& clearFunc)
01060 {
01061    for (typename T::iterator it = m.begin(); it != m.end(); it++)
01062    {
01063       clearFunc(it->second);
01064    }
01065    m.clear();
01066 }
01067 
01068 template<class T, class Func> 
01069 void clearList(T& m, Func& clearFunc)
01070 {
01071    for (typename T::iterator it = m.begin(); it != m.end(); it++)
01072    {
01073       clearFunc(*it);
01074    }
01075    m.clear();
01076 }
01077 
01078 BaseSecurity::~BaseSecurity ()
01079 {
01080    DebugLog(<< "BaseSecurity::~BaseSecurity");
01081 
01082    // cleanup certificates
01083    clearList(mRootCerts, X509_free);
01084    clearMap(mDomainCerts, X509_free);
01085    clearMap(mUserCerts, X509_free);
01086 
01087    // cleanup private keys
01088    clearMap(mDomainPrivateKeys, EVP_PKEY_free);
01089    clearMap(mUserPrivateKeys, EVP_PKEY_free);
01090 
01091    // cleanup SSL_CTXes
01092    if (mTlsCtx)
01093    {
01094       SSL_CTX_free(mTlsCtx);mTlsCtx=0;  // This free's X509_STORE (mRootTlsCerts)
01095    }
01096    if (mSslCtx)
01097    {
01098       SSL_CTX_free(mSslCtx);mSslCtx=0;  // This free's X509_STORE (mRootSslCerts)
01099    }
01100 
01101 }
01102 
01103 
01104 void
01105 BaseSecurity::initialize ()
01106 {
01107   Timer::getTimeMs(); // initalize time offsets
01108 }
01109 
01110 
01111 Security::CertificateInfoContainer
01112 BaseSecurity::getRootCertDescriptions() const
01113 {
01114    // !kh!
01115    // need to be implemented.
01116    assert(0); // TODO 
01117    return   CertificateInfoContainer();
01118 }
01119 
01120 
01121 void
01122 BaseSecurity::addRootCertPEM(const Data& x509PEMEncodedRootCerts)
01123 { 
01124    assert( mRootTlsCerts && mRootSslCerts );
01125 #if 1
01126    addCertPEM(RootCert,Data::Empty,x509PEMEncodedRootCerts,false);
01127 #else
01128    assert( !x509PEMEncodedRootCerts.empty() );
01129 
01130    static X509_LOOKUP_METHOD x509_pemstring_lookup =
01131   {
01132      "Load cert from PEM string into cache",
01133      NULL,  /* new */
01134      NULL,  /* free */
01135      NULL,   /* init */
01136      NULL,  /* shutdown */
01137      pemstring_ctrl,/* ctrl */
01138      NULL,  /* get_by_subject */
01139      NULL,  /* get_by_issuer_serial */
01140      NULL,  /* get_by_fingerprint */
01141      NULL,  /* get_by_alias */
01142   };
01143 
01144    if (mRootCerts == 0)
01145    {
01146       mRootCerts = X509_STORE_new();
01147    }
01148    
01149    assert( mRootCerts );
01150 
01151    X509_LOOKUP* lookup = X509_STORE_add_lookup(mRootCerts, &x509_pemstring_lookup);
01152 
01153    if (lookup == NULL)
01154       throw Exception("Error in BaseSecurity::addRootCertPEM()", __FILE__,__LINE__);
01155 
01156    // !kh!
01157    // bug, no error handling here.
01158    X509_LOOKUP_ctrl(lookup, X509_L_FILE_LOAD, x509PEMEncodedRootCerts.c_str(), 0, 0);
01159 #endif
01160 }
01161 
01162 
01163 void
01164 BaseSecurity::addDomainCertPEM(const Data& domainName, const Data& certPEM)
01165 {
01166    addCertPEM(DomainCert, domainName, certPEM, true);
01167 }
01168 
01169 
01170 void
01171 BaseSecurity::addDomainCertDER(const Data& domainName, const Data& certDER)
01172 {
01173    addCertDER(DomainCert, domainName, certDER, true);
01174 }
01175 
01176 
01177 bool
01178 BaseSecurity::hasDomainCert(const Data& domainName) const
01179 {
01180    return   hasCert(DomainCert, domainName);
01181 }
01182 
01183 
01184 void
01185 BaseSecurity::removeDomainCert(const Data& domainName)
01186 {
01187    return   removeCert(DomainCert, domainName);
01188 }
01189 
01190 
01191 Data
01192 BaseSecurity::getDomainCertDER(const Data& domainName) const
01193 {
01194    return   getCertDER(DomainCert, domainName);
01195 }
01196 
01197 
01198 void
01199 BaseSecurity::addDomainPrivateKeyPEM(const Data& domainName, const Data& privateKeyPEM)
01200 {
01201    addPrivateKeyPEM(DomainPrivateKey, domainName, privateKeyPEM, true);
01202 }
01203 
01204 
01205 bool
01206 BaseSecurity::hasDomainPrivateKey(const Data& domainName) const
01207 {
01208    return   hasPrivateKey(DomainPrivateKey, domainName);
01209 }
01210 
01211 
01212 void
01213 BaseSecurity::removeDomainPrivateKey(const Data& domainName)
01214 {
01215    removePrivateKey(DomainPrivateKey, domainName);
01216 }
01217 
01218 
01219 Data
01220 BaseSecurity::getDomainPrivateKeyPEM(const Data& domainName) const
01221 {
01222    return   getPrivateKeyPEM(DomainPrivateKey, domainName);
01223 }
01224 
01225 
01226 void
01227 BaseSecurity::addUserCertPEM(const Data& aor, const Data& certPEM)
01228 {
01229    addCertPEM(UserCert, aor, certPEM, true);
01230 }
01231 
01232 
01233 void
01234 BaseSecurity::addUserCertDER(const Data& aor, const Data& certDER)
01235 {
01236    addCertDER(UserCert, aor, certDER, true);
01237 }
01238 
01239 
01240 bool
01241 BaseSecurity::hasUserCert(const Data& aor) const
01242 {
01243    return   hasCert(UserCert, aor);
01244 }
01245 
01246 
01247 void
01248 BaseSecurity::removeUserCert(const Data& aor)
01249 {
01250    removeCert(UserCert, aor);
01251 }
01252 
01253 
01254 Data
01255 BaseSecurity::getUserCertDER(const Data& aor) const
01256 {
01257    return   getCertDER(UserCert, aor);
01258 }
01259 
01260 
01261 void
01262 BaseSecurity::setUserPassPhrase(const Data& aor, const Data& passPhrase)
01263 {
01264    assert(!aor.empty());
01265 
01266    PassPhraseMap::iterator iter = mUserPassPhrases.find(aor);
01267    if (iter == mUserPassPhrases.end())
01268    {
01269       mUserPassPhrases.insert(std::make_pair(aor, passPhrase));
01270    }
01271 }
01272 
01273 
01274 bool
01275 BaseSecurity::hasUserPassPhrase(const Data& aor) const
01276 {
01277    assert(aor.empty());
01278 
01279    PassPhraseMap::const_iterator iter = mUserPassPhrases.find(aor);
01280    if (iter == mUserPassPhrases.end())
01281    {
01282       return   false;
01283    }
01284    else
01285    {
01286       return   true;
01287    }
01288 }
01289 
01290 
01291 void
01292 BaseSecurity::removeUserPassPhrase(const Data& aor)
01293 {
01294    assert(aor.empty());
01295 
01296    PassPhraseMap::iterator iter = mUserPassPhrases.find(aor);
01297    if(iter != mUserPassPhrases.end())
01298    {
01299       mUserPassPhrases.erase(iter);
01300    }
01301 }
01302 
01303 
01304 Data
01305 BaseSecurity::getUserPassPhrase(const Data& aor) const
01306 {
01307    assert(aor.empty());
01308 
01309    PassPhraseMap::const_iterator iter = mUserPassPhrases.find(aor);
01310    if(iter == mUserPassPhrases.end())
01311    {
01312       return   iter->second;
01313    }
01314    else
01315    {
01316       return   Data::Empty;
01317    }
01318 }
01319 
01320 
01321 void
01322 BaseSecurity::addUserPrivateKeyPEM(const Data& aor, const Data& cert)
01323 {
01324    addPrivateKeyPEM(UserPrivateKey, aor, cert, true);
01325 }
01326 
01327 
01328 void
01329 BaseSecurity::addUserPrivateKeyDER(const Data& aor, const Data& cert)
01330 {
01331    addPrivateKeyDER(UserPrivateKey, aor, cert, true);
01332 }
01333 
01334 
01335 bool
01336 BaseSecurity::hasUserPrivateKey(const Data& aor) const
01337 {
01338    return   hasPrivateKey(UserPrivateKey, aor);
01339 }
01340 
01341 
01342 void
01343 BaseSecurity::removeUserPrivateKey(const Data& aor)
01344 {
01345    removePrivateKey(UserPrivateKey, aor);
01346 }
01347 
01348 
01349 Data
01350 BaseSecurity::getUserPrivateKeyPEM(const Data& aor) const
01351 {
01352    return   getPrivateKeyPEM(UserPrivateKey, aor);
01353 }
01354 
01355 
01356 Data
01357 BaseSecurity::getUserPrivateKeyDER(const Data& aor) const
01358 {
01359    return   getPrivateKeyDER(UserPrivateKey, aor);
01360 }
01361 
01362 
01363 void
01364 BaseSecurity::generateUserCert (const Data& pAor, int expireDays, int keyLen )
01365 {
01366    int ret;
01367    
01368    InfoLog( <<"Generating new user cert for " << pAor );
01369  
01370    Data domain;
01371    Data aor;
01372 
01373    try
01374    {
01375       Uri uri( Data("sip:")+pAor );
01376       aor = uri.getAor();
01377       domain = uri.host();
01378    }
01379    catch (...)
01380    { 
01381       ErrLog( <<"Invalid aor passed to generateUserCert");
01382       throw Exception("Bad aor passed to generateUserCert", __FILE__,__LINE__);
01383    }
01384    
01385    // Make sure that necessary algorithms exist:
01386    assert(EVP_sha1());
01387 
01388    RSA* rsa = RSA_generate_key(keyLen, RSA_F4, NULL, NULL);
01389    assert(rsa);    // couldn't make key pair
01390    
01391    EVP_PKEY* privkey = EVP_PKEY_new();
01392    assert(privkey);
01393    ret = EVP_PKEY_set1_RSA(privkey, rsa);
01394    assert(ret);
01395 
01396    X509* cert = X509_new();
01397    assert(cert);
01398    
01399    X509_NAME* subject = X509_NAME_new();
01400    X509_EXTENSION* ext = X509_EXTENSION_new();
01401    
01402    // set version to X509v3 (starts from 0)
01403    X509_set_version(cert, 2L);
01404    
01405    int serial = Random::getRandom();  // get an int worth of randomness
01406    assert(sizeof(int)==4);
01407    ASN1_INTEGER_set(X509_get_serialNumber(cert),serial);
01408    
01409    ret = X509_NAME_add_entry_by_txt( subject, "O",  MBSTRING_ASC, 
01410                                      (unsigned char *) domain.data(), (int)domain.size(), 
01411                                      -1, 0);
01412    assert(ret);
01413    ret = X509_NAME_add_entry_by_txt( subject, "CN", MBSTRING_ASC, 
01414                                      (unsigned char *) aor.data(), (int)aor.size(), 
01415                                      -1, 0);
01416    assert(ret);
01417    
01418    ret = X509_set_issuer_name(cert, subject);
01419    assert(ret);
01420    ret = X509_set_subject_name(cert, subject);
01421    assert(ret);
01422    
01423    const long duration = 60*60*24*expireDays;   
01424    X509_gmtime_adj(X509_get_notBefore(cert),0);
01425    X509_gmtime_adj(X509_get_notAfter(cert), duration);
01426    
01427    ret = X509_set_pubkey(cert, privkey);
01428    assert(ret);
01429    
01430    Data subjectAltNameStr = Data("URI:sip:") + aor
01431       + Data(",URI:im:")+aor
01432       + Data(",URI:pres:")+aor;
01433    ext = X509V3_EXT_conf_nid( NULL , NULL , NID_subject_alt_name, 
01434                               (char*) subjectAltNameStr.c_str() );
01435    X509_add_ext( cert, ext, -1);
01436    X509_EXTENSION_free(ext);
01437    
01438    static char CA_FALSE[] = "CA:FALSE";
01439    ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, CA_FALSE);
01440    ret = X509_add_ext( cert, ext, -1);
01441    assert(ret);
01442    X509_EXTENSION_free(ext);
01443    
01444    // TODO add extensions NID_subject_key_identifier and NID_authority_key_identifier
01445    
01446    ret = X509_sign(cert, privkey, EVP_sha1());
01447    assert(ret);
01448    
01449    addCertX509( UserCert, aor, cert, true /* write */ );
01450    addPrivateKeyPKEY( UserPrivateKey, aor, privkey, true /* write */ );
01451 }
01452 
01453 MultipartSignedContents*
01454 BaseSecurity::sign(const Data& senderAor, Contents* contents)
01455 {
01456    assert( contents );
01457 
01458    // form the multipart
01459    MultipartSignedContents* multi = new MultipartSignedContents;
01460    multi->header(h_ContentType).param( p_micalg ) = "sha1";
01461    multi->header(h_ContentType).param( p_protocol ) = "application/pkcs7-signature";
01462 
01463    // add the main body to it
01464    Contents* body =  contents->clone();
01465    multi->parts().push_back( body );
01466 
01467    Data bodyData;
01468    DataStream strm( bodyData );
01469    body->encodeHeaders( strm );
01470    body->encode( strm );
01471    strm.flush();
01472 
01473    DebugLog( << "signing data <" << bodyData.escaped() << ">" );
01474    //Security::dumpAsn("resip-sign-out-data",bodyData);
01475 
01476    const char* p = bodyData.data();
01477    int s = (int)bodyData.size();
01478    BIO* in=BIO_new_mem_buf( (void*)p,s);
01479    assert(in);
01480    DebugLog( << "created in BIO");
01481 
01482    BIO* out = BIO_new(BIO_s_mem()); // TODO - mem leak 
01483    assert(out);
01484    DebugLog( << "created out BIO" );
01485 
01486    STACK_OF(X509)* chain = sk_X509_new_null();
01487    assert(chain);
01488 
01489    DebugLog( << "searching for cert/key for <" << senderAor << ">" );
01490    if (mUserCerts.count(senderAor) == 0 ||
01491        mUserPrivateKeys.count(senderAor) == 0)
01492    {
01493       BIO_free(in);
01494       BIO_free(out);
01495       sk_X509_free(chain);
01496       WarningLog (<< "Tried to sign with no cert or private key for " << senderAor);
01497       throw Exception("No cert or private key to sign with",__FILE__,__LINE__);
01498    }
01499    
01500    X509* publicCert = mUserCerts[senderAor];
01501    EVP_PKEY* privateKey = mUserPrivateKeys[senderAor];
01502 
01503    int rv = X509_check_private_key(publicCert, privateKey);
01504    if(!rv)
01505    {
01506       BIO_free(in);
01507       BIO_free(out);
01508       sk_X509_free(chain);
01509       ErrLog (<< "X509_check_private_key failed for " << senderAor);
01510       return 0;
01511    }
01512 
01513    // compute the signature
01514    int flags = 0;
01515    flags |= PKCS7_BINARY; 
01516    flags |= PKCS7_DETACHED; 
01517    if ( true ) // don't do caps
01518    {
01519       flags |= PKCS7_NOSMIMECAP; 
01520       flags |= PKCS7_NOATTR; 
01521    }
01522    if ( true ) // don't do certs 
01523    {
01524       flags |= PKCS7_NOCERTS;  
01525    }
01526 
01527    PKCS7* pkcs7 = PKCS7_sign( publicCert, privateKey, chain, in, flags);
01528    if ( !pkcs7 )
01529    {
01530       BIO_free(in);
01531       BIO_free(out);
01532       sk_X509_free(chain);
01533       ErrLog( << "Error creating PKCS7 signature object" );
01534       return 0;
01535    }
01536    DebugLog( << "created PKCS7 signature object " );
01537 
01538    i2d_PKCS7_bio(out,pkcs7);
01539    (void)BIO_flush(out);
01540 
01541    char* outBuf=0;
01542    long size = BIO_get_mem_data(out,&outBuf);
01543    assert( size > 0 );
01544 
01545    Data outData(outBuf,size);
01546    static char RESIP_SIGN_OUT_SIG[] = "resip-sign-out-sig";
01547    Security::dumpAsn(RESIP_SIGN_OUT_SIG,outData);
01548 
01549    Pkcs7SignedContents* sigBody = new Pkcs7SignedContents( outData );
01550    assert( sigBody );
01551 
01552    // add the signature to it
01553    sigBody->header(h_ContentType).param( p_name ) = "smime.p7s";
01554    sigBody->header(h_ContentDisposition).param( p_handling ) = "required";
01555    sigBody->header(h_ContentDisposition).param( p_filename ) = "smime.p7s";
01556    sigBody->header(h_ContentDisposition).value() =  "attachment" ;
01557    sigBody->header(h_ContentTransferEncoding).value() = "binary";
01558    multi->parts().push_back( sigBody );
01559 
01560    assert( multi->parts().size() == 2 );
01561 
01562    BIO_free(in);
01563    BIO_free(out);
01564    sk_X509_free(chain);
01565    PKCS7_free(pkcs7);
01566 
01567    return multi;
01568 }
01569 
01570 
01571 Pkcs7Contents*
01572 BaseSecurity::encrypt(Contents* bodyIn, const Data& recipCertName )
01573 {
01574    assert( bodyIn );
01575 
01576    int flags = 0 ;
01577    flags |= PKCS7_BINARY;
01578    flags |= PKCS7_NOCERTS;
01579 
01580    Data bodyData;
01581    DataStream strm(bodyData);
01582    bodyIn->encodeHeaders(strm);
01583    bodyIn->encode( strm );
01584    strm.flush();
01585 
01586    InfoLog( << "body data to encrypt is <" << bodyData.escaped() << ">" );
01587 
01588    const char* p = bodyData.data();
01589    int s = (int)bodyData.size();
01590 
01591    BIO* in = BIO_new_mem_buf( (void*)p,s);
01592    assert(in);
01593    DebugLog( << "created in BIO");
01594 
01595    BIO* out = BIO_new(BIO_s_mem());
01596    assert(out);
01597    DebugLog( << "created out BIO" );
01598 
01599    InfoLog( << "target cert name is <" << recipCertName << ">" );
01600    if (mUserCerts.count(recipCertName) == 0)
01601    {
01602       BIO_free(in);
01603       BIO_free(out);
01604       WarningLog (<< "Tried to encrypt with no cert or private key for " << recipCertName);
01605       throw Exception("No cert or private key to encrypt with",__FILE__,__LINE__);
01606    }
01607 
01608    X509* cert = mUserCerts[recipCertName];
01609    assert(cert);
01610 
01611    STACK_OF(X509) *certs = sk_X509_new_null();
01612    assert(certs);
01613    sk_X509_push(certs, cert);
01614 
01615 // if you think you need to change the following few lines, please email fluffy
01616 // the value of OPENSSL_VERSION_NUMBER ( in opensslv.h ) and the signature of
01617 // PKCS_encrypt found ( in pkcs7.h ) and the OS you are using
01618 #if (  OPENSSL_VERSION_NUMBER > 0x009060ffL )
01619 //   const EVP_CIPHER* cipher =  EVP_des_ede3_cbc();
01620    const EVP_CIPHER* cipher =  EVP_aes_128_cbc(); 
01621 #else
01622    //const EVP_CIPHER* cipher = EVP_enc_null();
01623    EVP_CIPHER* cipher =  EVP_des_ede3_cbc();
01624 #endif
01625    assert( cipher );
01626 
01627 #if (OPENSSL_VERSION_NUMBER < 0x0090705fL )
01628 #warning PKCS7_encrypt() is broken in OpenSSL 0.9.7d
01629 #endif
01630 
01631    PKCS7* pkcs7 = PKCS7_encrypt( certs, in, cipher, flags);
01632    if ( !pkcs7 )
01633    {
01634       BIO_free(in);
01635       BIO_free(out);
01636       sk_X509_free(certs);
01637       ErrLog( << "Error creating PKCS7 encrypt object" );
01638       //throw Exception("Can't encrypt",__FILE__,__LINE__);
01639       return 0;
01640    }
01641    DebugLog( << "created PKCS7 encrypt object " );
01642 
01643    i2d_PKCS7_bio(out,pkcs7);
01644 
01645    (void)BIO_flush(out);
01646 
01647    char* outBuf=0;
01648    long size = BIO_get_mem_data(out,&outBuf);
01649    assert( size > 0 );
01650 
01651    Data outData(outBuf,size);
01652    assert( (long)outData.size() == size );
01653 
01654    InfoLog( << "Encrypted body size is " << outData.size() );
01655    InfoLog( << "Encrypted body is <" << outData.escaped() << ">" );
01656 
01657    static char RESIP_ENCRYPT_OUT[] = "resip-encrypt-out";
01658    Security::dumpAsn(RESIP_ENCRYPT_OUT, outData);
01659 
01660    Pkcs7Contents* outBody = new Pkcs7Contents( outData );
01661    assert( outBody );
01662 
01663    outBody->header(h_ContentType).param( p_smimeType ) = "enveloped-data";
01664    outBody->header(h_ContentType).param( p_name ) = "smime.p7m";
01665    outBody->header(h_ContentDisposition).param( p_handling ) = "required";
01666    outBody->header(h_ContentDisposition).param( p_filename ) = "smime.p7";
01667    outBody->header(h_ContentDisposition).value() =  "attachment" ;
01668    outBody->header(h_ContentTransferEncoding).value() = "binary";
01669 
01670    BIO_free(in);
01671    BIO_free(out);
01672    sk_X509_free(certs);
01673    PKCS7_free(pkcs7);
01674 
01675    return outBody;
01676 }
01677 
01678 
01679 MultipartSignedContents *
01680 BaseSecurity::signAndEncrypt( const Data& senderAor, Contents* body, const Data& recipCertName )
01681 {
01682    //assert(0);
01683    //return 0;
01684    return sign(senderAor, encrypt(body, recipCertName));
01685 }
01686 
01687 
01688 Data
01689 BaseSecurity::computeIdentity( const Data& signerDomain, const Data& in ) const
01690 {
01691    DebugLog( << "Compute identity for " << in );
01692 
01693    PrivateKeyMap::const_iterator k(mDomainPrivateKeys.find(signerDomain));
01694    if (k == mDomainPrivateKeys.end())
01695    {
01696       InfoLog( << "No private key for " << signerDomain );
01697       throw Exception("Missing private key when computing identity",__FILE__,__LINE__);
01698    }
01699 
01700    EVP_PKEY* pKey = k->second;
01701    assert( pKey );
01702  
01703    if ( pKey->type !=  EVP_PKEY_RSA )
01704    {
01705       ErrLog( << "Private key (type=" << pKey->type <<"for " 
01706               << signerDomain << " is not of type RSA" );
01707       throw Exception("No RSA private key when computing identity",__FILE__,__LINE__);
01708    }
01709 
01710    assert( pKey->type ==  EVP_PKEY_RSA );
01711    RSA* rsa = EVP_PKEY_get1_RSA(pKey);
01712 
01713    unsigned char result[4096];
01714    int resultSize = sizeof(result);
01715    assert( resultSize >= RSA_size(rsa) );
01716 
01717    SHA1Stream sha;
01718    sha << in;
01719    Data hashRes =  sha.getBin();
01720    DebugLog( << "hash of string is 0x" << hashRes.hex() );
01721 
01722 #if 1
01723    int r = RSA_sign(NID_sha1, (unsigned char *)hashRes.data(), (unsigned int)hashRes.size(),
01724                     result, (unsigned int*)( &resultSize ),
01725             rsa);
01726    if( r != 1 )
01727    {
01728       ErrLog(<< "RSA_sign failed with return " << r);
01729       assert(0);
01730       return Data::Empty;
01731    }
01732 #else
01733    resultSize = RSA_private_encrypt(hashResLen, hashRes,
01734                                     result, rsa, RSA_PKCS1_PADDING);
01735    if ( resultSize == -1 )
01736    {
01737       DebugLog( << "Problem doing RSA encrypt for identity");
01738       while (1)
01739       {
01740          const char* file;
01741          int line;
01742 
01743          unsigned long code = ERR_get_error_line(&file,&line);
01744          if ( code == 0 )
01745          {
01746             break;
01747          }
01748 
01749          char buf[256];
01750          ERR_error_string_n(code,buf,sizeof(buf));
01751          ErrLog( << buf  );
01752          InfoLog( << "Error code = " << code << " file="<<file<<" line=" << line );
01753       }
01754 
01755       return Data::Empty;
01756    }
01757 #endif
01758 
01759    Data res(result,resultSize);
01760    DebugLog( << "rsa encrypt of hash is 0x"<< res.hex() );
01761 
01762    Data enc = res.base64encode();
01763 
01764    static char IDENTITY_IN[] = "identity-in";
01765    static char IDENTITY_IN_HASH[] = "identity-in-hash";
01766    static char IDENTITY_IN_RSA[] = "identity-in-rsa";
01767    static char IDENTITY_IN_BASE64[] = "identity-in-base64";
01768 
01769    Security::dumpAsn(IDENTITY_IN, in );
01770    Security::dumpAsn(IDENTITY_IN_HASH, hashRes );
01771    Security::dumpAsn(IDENTITY_IN_RSA,res);
01772    Security::dumpAsn(IDENTITY_IN_BASE64,enc);
01773 
01774    return enc;
01775 }
01776 
01777 
01778 bool
01779 BaseSecurity::checkIdentity( const Data& signerDomain, const Data& in, const Data& sigBase64, X509* pCert ) const
01780 {
01781    X509* cert =  pCert;
01782    if (!cert)
01783    {
01784       X509Map::const_iterator x=mDomainCerts.find(signerDomain);
01785       if (x == mDomainCerts.end())
01786       {
01787          ErrLog( << "No public key for " << signerDomain );
01788          throw Exception("Missing public key when verifying identity",__FILE__,__LINE__);
01789       }
01790       cert = x->second;
01791    }
01792    
01793    DebugLog( << "Check identity for " << in );
01794    DebugLog( << " base64 data is " << sigBase64 );
01795 
01796    Data sig = sigBase64.base64decode();
01797    DebugLog( << "decoded sig is 0x"<< sig.hex() );
01798 
01799    SHA1Stream sha;
01800    sha << in;
01801    Data hashRes =  sha.getBin();
01802    DebugLog( << "hash of string is 0x" << hashRes.hex() );
01803 
01804    EVP_PKEY* pKey = X509_get_pubkey( cert );
01805    assert( pKey );
01806 
01807    assert( pKey->type ==  EVP_PKEY_RSA );
01808    RSA* rsa = EVP_PKEY_get1_RSA(pKey);
01809 
01810 #if 1
01811    int ret = RSA_verify(NID_sha1, (unsigned char *)hashRes.data(),
01812                         (unsigned int)hashRes.size(), (unsigned char*)sig.data(), (unsigned int)sig.size(),
01813                         rsa);
01814 #else
01815    unsigned char result[4096];
01816    int resultSize = sizeof(result);
01817    assert( resultSize >= RSA_size(rsa) );
01818 
01819    resultSize = RSA_public_decrypt(sig.size(),(unsigned char*)sig.data(),
01820                                    result, rsa, RSA_PKCS1_PADDING );
01821    assert( resultSize != -1 );
01822    //assert( resultSize == SHA_DIGEST_LENGTH );
01823    Data recievedHash(result,resultSize);
01824    dumpAsn("identity-out-decrypt", recievedHash );
01825 
01826    bool ret =  ( computedHash == recievedHash );
01827 #endif
01828 
01829    DebugLog( << "rsa verify result is " << ret  );
01830 
01831    static char IDENTITY_OUT_MSG[] = "identity-out-msg";
01832    static char IDENTITY_OUT_BASE64[] = "identity-out-base64";
01833    static char IDENTITY_OUT_SIG[] = "identity-out-sig";
01834    static char IDENTITY_OUT_HASH[] = "identity-out-hash";
01835 
01836    Security::dumpAsn(IDENTITY_OUT_MSG, in );
01837    Security::dumpAsn(IDENTITY_OUT_BASE64,sigBase64);
01838    Security::dumpAsn(IDENTITY_OUT_SIG, sig);
01839    Security::dumpAsn(IDENTITY_OUT_HASH, hashRes );
01840 
01841    return (ret != 0);
01842 }
01843 
01844 
01845 void
01846 BaseSecurity::checkAndSetIdentity(SipMessage& msg, const Data& certDer) const
01847 {
01848    auto_ptr<SecurityAttributes> sec(new SecurityAttributes);
01849    X509* cert=NULL;
01850    
01851    try
01852    {
01853       if ( !certDer.empty() )
01854       {
01855 #if (OPENSSL_VERSION_NUMBER < 0x0090800fL )
01856          unsigned char* in = (unsigned char*)certDer.data();
01857 #else
01858          unsigned const char* in = (unsigned const char*)certDer.data();
01859 #endif
01860          if (d2i_X509(&cert,&in,(long)certDer.size()) == 0)
01861          {
01862             DebugLog(<< "Could not read DER certificate from " << certDer );
01863             cert = NULL;
01864          }
01865       }
01866       if ( certDer.empty() || cert )
01867       {
01868          if ( checkIdentity(msg.const_header(h_From).uri().host(),
01869                             msg.getCanonicalIdentityString(),
01870                             msg.const_header(h_Identity).value(),
01871                             cert ) )
01872          {
01873             sec->setIdentity(msg.const_header(h_From).uri().getAor());
01874             sec->setIdentityStrength(SecurityAttributes::Identity);
01875          }
01876          else
01877          {
01878             sec->setIdentity(msg.const_header(h_From).uri().getAor());
01879             sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
01880          }
01881       }
01882       else
01883       {
01884          sec->setIdentity(msg.const_header(h_From).uri().getAor());
01885          sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
01886       }
01887    }
01888    catch (BaseException& e)
01889    {
01890       ErrLog(<<"Caught exception: "<< e);
01891       sec->setIdentity(msg.const_header(h_From).uri().getAor());
01892       sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
01893    }
01894    msg.setSecurityAttributes(sec);
01895 }
01896 
01897 
01898 Contents*
01899 BaseSecurity::decrypt( const Data& decryptorAor, const Pkcs7Contents* contents)
01900 {
01901 
01902    DebugLog( << "decryptor Aor: <" << decryptorAor << ">" );
01903 
01904    int flags=0;
01905    flags |= PKCS7_BINARY;
01906 
01907    // for now, assume that this is only a singed message
01908    assert( contents );
01909 
01910    Data text = contents->getBodyData();
01911    DebugLog( << "uncode body = <" << text.escaped() << ">" );
01912    DebugLog( << "uncode body size = " << text.size() );
01913 
01914    static char RESIP_ASN_DECRYPT[] = "resip-asn-decrypt";
01915    Security::dumpAsn(RESIP_ASN_DECRYPT, text );
01916 
01917    BIO* in = BIO_new_mem_buf( (void*)text.c_str(), (int)text.size());
01918    assert(in);
01919    InfoLog( << "created in BIO");
01920 
01921    BIO* out;
01922    out = BIO_new(BIO_s_mem());
01923    assert(out);
01924    InfoLog( << "created out BIO" );
01925 
01926    PKCS7* pkcs7 = d2i_PKCS7_bio(in, 0);
01927    if ( !pkcs7 )
01928    {
01929       ErrLog( << "Problems doing decode of PKCS7 object" );
01930 
01931       while (1)
01932       {
01933          const char* file;
01934          int line;
01935 
01936          unsigned long code = ERR_get_error_line(&file,&line);
01937          if ( code == 0 )
01938          {
01939             break;
01940          }
01941 
01942          char buf[256];
01943          ERR_error_string_n(code,buf,sizeof(buf));
01944          ErrLog( << buf  );
01945          InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
01946       }
01947 
01948       BIO_free(in);
01949       BIO_free(out);
01950 
01951       return 0;
01952    }
01953    (void)BIO_flush(in);
01954 
01955    int type=OBJ_obj2nid(pkcs7->type);
01956    switch (type)
01957    {
01958       case NID_pkcs7_signed:
01959          InfoLog( << "data is pkcs7 signed" );
01960          break;
01961       case NID_pkcs7_signedAndEnveloped:
01962          InfoLog( << "data is pkcs7 signed and enveloped" );
01963          break;
01964       case NID_pkcs7_enveloped:
01965          InfoLog( << "data is pkcs7 enveloped" );
01966          break;
01967       case NID_pkcs7_data:
01968          InfoLog( << "data i pkcs7 data" );
01969          break;
01970       case NID_pkcs7_encrypted:
01971          InfoLog( << "data is pkcs7 encrypted " );
01972          break;
01973       case NID_pkcs7_digest:
01974          InfoLog( << "data is pkcs7 digest" );
01975          break;
01976       default:
01977          InfoLog( << "Unknown pkcs7 type" );
01978          break;
01979    }
01980 
01981    STACK_OF(X509)* certs = sk_X509_new_null();
01982    assert( certs );
01983 
01984    //   flags |= PKCS7_NOVERIFY;
01985 
01986    assert( mRootTlsCerts );
01987 
01988    switch (type)
01989    {
01990       case NID_pkcs7_signedAndEnveloped:
01991       {
01992          BIO_free(in);
01993          BIO_free(out);
01994          sk_X509_free(certs);
01995          PKCS7_free(pkcs7);
01996          throw Exception("Signed and enveloped is not supported", __FILE__, __LINE__);
01997       }
01998       break;
01999 
02000       case NID_pkcs7_enveloped:
02001       {
02002          if (mUserPrivateKeys.count(decryptorAor) == 0)
02003          {
02004             BIO_free(in);
02005             BIO_free(out);
02006             sk_X509_free(certs);
02007             PKCS7_free(pkcs7);
02008             InfoLog( << "Don't have a private key for " << decryptorAor << " for  PKCS7_decrypt" );
02009             throw Exception("Missing private key", __FILE__, __LINE__);
02010          }
02011          else if (mUserCerts.count(decryptorAor) == 0)
02012          {
02013             BIO_free(in);
02014             BIO_free(out);
02015             sk_X509_free(certs);
02016             PKCS7_free(pkcs7);
02017             InfoLog( << "Don't have a public cert for " << decryptorAor << " for  PKCS7_decrypt" );
02018             throw Exception("Missing cert", __FILE__, __LINE__);
02019          }
02020 
02021          EVP_PKEY* privateKey = mUserPrivateKeys[decryptorAor];
02022          X509* publicCert = mUserCerts[decryptorAor];
02023 
02024          if ( PKCS7_decrypt(pkcs7, privateKey, publicCert, out, flags ) != 1 )
02025          {
02026             ErrLog( << "Problems doing PKCS7_decrypt" );
02027             while (1)
02028             {
02029                const char* file;
02030                int line;
02031 
02032                unsigned long code = ERR_get_error_line(&file,&line);
02033                if ( code == 0 )
02034                {
02035                   break;
02036                }
02037 
02038                char buf[256];
02039                ERR_error_string_n(code,buf,sizeof(buf));
02040                ErrLog( << buf  );
02041                InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
02042             }
02043 
02044             BIO_free(in);
02045             BIO_free(out);
02046             sk_X509_free(certs);
02047             PKCS7_free(pkcs7);
02048             return 0;
02049          }
02050       }
02051       break;
02052 
02053       default:
02054          BIO_free(in);
02055          BIO_free(out);
02056          sk_X509_free(certs);
02057          PKCS7_free(pkcs7);
02058          ErrLog(<< "Got PKCS7 data that could not be handled type=" << type );
02059          throw Exception("Unsupported PKCS7 data type", __FILE__, __LINE__);
02060    }
02061 
02062    (void)BIO_flush(out);   
02063    BUF_MEM* bufMem;
02064    BIO_get_mem_ptr(out, &bufMem);
02065 
02066    int len = bufMem->length;
02067    char* buffer = new char[len];
02068    memcpy(buffer, bufMem->data, len);
02069 
02070    (void)BIO_set_close(out, BIO_CLOSE);
02071    BIO_free(in);
02072    BIO_free(out);
02073    sk_X509_free(certs);
02074    PKCS7_free(pkcs7);
02075 
02076    // parse out the header information and form new body.
02077    // TODO !jf! this is a really crappy parser - shoudl do proper mime stuff 
02078    ParseBuffer pb(buffer, len);
02079 
02080    const char* headerStart = pb.position();
02081 
02082    // pull out contents type only
02083    pb.skipToChars("Content-Type");
02084    pb.assertNotEof();
02085 
02086    pb.skipToChar(Symbols::COLON[0]);
02087    pb.skipChar();
02088    pb.assertNotEof();
02089 
02090    pb.skipWhitespace();
02091    const char* typeStart = pb.position();
02092    pb.assertNotEof();
02093 
02094    // determine contents-type header buffer
02095    pb.skipToTermCRLF();
02096    pb.assertNotEof();
02097 
02098    ParseBuffer subPb(typeStart, pb.position() - typeStart);
02099    Mime contentType;
02100    contentType.parse(subPb);
02101 
02102    pb.assertNotEof();
02103 
02104    // determine body start
02105    pb.reset(typeStart);
02106    const char* bodyStart = pb.skipToChars(Symbols::CRLFCRLF);
02107    pb.assertNotEof();
02108    bodyStart += 4;
02109 
02110    // determine contents body buffer
02111    pb.skipToEnd();
02112    Data tmp;
02113    pb.data(tmp, bodyStart);
02114    // create contents against body
02115    Contents* ret = Contents::createContents(contentType, tmp);
02116    ret->addBuffer(buffer);
02117    
02118    // pre-parse headers
02119    ParseBuffer headersPb(headerStart, bodyStart-4-headerStart);
02120    ret->preParseHeaders(headersPb);
02121 
02122    InfoLog( << "Got body data of " << ret->getBodyData() );
02123 
02124    return ret;
02125 }
02126 
02127 
02128 
02129 
02130 
02131 Contents*
02132 BaseSecurity::checkSignature(MultipartSignedContents* multi,
02133                              Data* signedBy,
02134                              SignatureStatus* sigStat )
02135 {
02136    if ( multi->parts().size() != 2 )
02137    {
02138       ErrLog(<< "Trying to decode a message with wrong number of contents " << multi->parts().size());
02139       throw Exception("Invalid contents passed to checkSignature", __FILE__, __LINE__);
02140    }
02141 
02142    MultipartSignedContents::Parts::const_iterator it = multi->parts().begin();
02143    Contents* first = *it;
02144    ++it;
02145    assert( it != multi->parts().end() );
02146    Contents* second = *it;
02147 
02148    assert( second );
02149    assert( first );
02150 
02151    InfoLog( << "message to signature-check is " << *first );
02152 
02153    Pkcs7SignedContents* sig = dynamic_cast<Pkcs7SignedContents*>( second );
02154    if ( !sig )
02155    {
02156       ErrLog( << "Don't know how to deal with signature type " );
02157       //throw Exception("Invalid contents passed to checkSignature", __FILE__,
02158       //__LINE__);
02159       return first;
02160    }
02161    Data sigData = sig->getBodyData();
02162 
02163    Data textData;
02164    DataStream strm( textData );
02165    first->encodeHeaders( strm );
02166    first->encode( strm );
02167    strm.flush();
02168 
02169    InfoLog( << "text <"    << textData.escaped() << ">" );
02170    InfoLog( << "signature <" << sigData.escaped() << ">" );
02171 
02172    static char RESIP_ASN_UNCODE_SIGNED_TEXT[] = "resip-asn-uncode-signed-text";
02173    static char RESIP_ASN_UNCODE_SIGNED_SIG[] = "resip-asn-uncode-signed-sig";
02174 
02175    Security::dumpAsn( RESIP_ASN_UNCODE_SIGNED_TEXT, textData );
02176    Security::dumpAsn( RESIP_ASN_UNCODE_SIGNED_SIG, sigData );
02177 
02178    BIO* in = BIO_new_mem_buf( (void*)sigData.data(),(int)sigData.size());
02179    assert(in);
02180    InfoLog( << "created in BIO");
02181 
02182    BIO* out = BIO_new(BIO_s_mem());
02183    assert(out);
02184    InfoLog( << "created out BIO" );
02185 
02186    BIO* pkcs7Bio = BIO_new_mem_buf( (void*) textData.data(),(int)textData.size());
02187    assert(pkcs7Bio);
02188    InfoLog( << "created pkcs7 BIO");
02189 
02190    PKCS7* pkcs7 = d2i_PKCS7_bio(in, 0);
02191    if ( !pkcs7 )
02192    {
02193       ErrLog( << "Problems doing decode of PKCS7 object <"
02194               << sigData.escaped() << ">" );
02195 
02196       while (1)
02197       {
02198          const char* file;
02199          int line;
02200 
02201          unsigned long code = ERR_get_error_line(&file,&line);
02202          if ( code == 0 )
02203          {
02204             break;
02205          }
02206 
02207          char buf[256];
02208          ERR_error_string_n(code,buf,sizeof(buf));
02209          ErrLog( << buf  );
02210          InfoLog( <<"Error code = "<< code <<" file=" << file << " line=" << line );
02211       }
02212       BIO_free(in);
02213       BIO_free(out);
02214       BIO_free(pkcs7Bio);
02215 
02216       return first;
02217    }
02218    (void)BIO_flush(in);
02219 
02220    int type=OBJ_obj2nid(pkcs7->type);
02221    switch (type)
02222    {
02223       case NID_pkcs7_signed:
02224          InfoLog( << "data is pkcs7 signed" );
02225          break;
02226       case NID_pkcs7_signedAndEnveloped:
02227          InfoLog( << "data is pkcs7 signed and enveloped" );
02228          break;
02229       case NID_pkcs7_enveloped:
02230          InfoLog( << "data is pkcs7 enveloped" );
02231          break;
02232       case NID_pkcs7_data:
02233          InfoLog( << "data is pkcs7 data" );
02234          break;
02235       case NID_pkcs7_encrypted:
02236          InfoLog( << "data is pkcs7 encrypted " );
02237          break;
02238       case NID_pkcs7_digest:
02239          InfoLog( << "data is pkcs7 digest" );
02240          break;
02241       default:
02242          InfoLog( << "Unknown pkcs7 type" );
02243          break;
02244    }
02245 
02246    STACK_OF(X509)* certs = 0;
02247    certs = sk_X509_new_null();
02248    assert( certs );
02249 
02250    if ( *signedBy == Data::Empty )
02251    {   
02252        //add all the certificates from mUserCerts stack to 'certs' stack  
02253        for(X509Map::iterator it = mUserCerts.begin(); it != mUserCerts.end(); it++)
02254        {
02255            assert(it->second);
02256            sk_X509_push(certs, it->second);
02257        }
02258    }
02259    else
02260    {
02261       if (mUserCerts.count( *signedBy ))
02262       {
02263          InfoLog( <<"Adding cert from " <<  *signedBy << " to check sig" );
02264          X509* cert = mUserCerts[ *signedBy ];
02265          assert(cert);
02266          sk_X509_push(certs, cert);
02267       }
02268    }
02269 
02270    int flags = 0;
02271    flags |= PKCS7_NOINTERN;
02272 
02273    // matches on certificate issuer and serial number - they must be unique
02274    STACK_OF(X509)* signers = PKCS7_get0_signers(pkcs7, certs, flags);
02275    if ( signers )
02276    {
02277 
02278       DebugLog( << "Found " << sk_X509_num(signers) << " signers." );
02279       for (int i=0; i<sk_X509_num(signers); i++)
02280       {
02281          X509* x = sk_X509_value(signers, i);
02282          InfoLog(<< "Got a signer <" << i << "> : " << getCertName(x) );
02283 
02284          GENERAL_NAMES* gens = 0;
02285          gens = (GENERAL_NAMES*)X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
02286 
02287          for (int j = 0; j < sk_GENERAL_NAME_num(gens); j++)
02288          {
02289             GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, j);
02290             if (gen->type == GEN_URI)
02291             {
02292                ASN1_IA5STRING* uri = gen->d.uniformResourceIdentifier;
02293                Data name(uri->data, uri->length);
02294                InfoLog(<< "subjectAltName of signing cert contains <" << name << ">" );
02295                try
02296                {
02297                   Uri n(name);
02298                   if ( n.scheme() == "sip" )
02299                   {
02300                      *signedBy = name;
02301                      InfoLog(<< "choose <" << name << "> signature" );
02302                  }
02303                }
02304                catch (ParseException& e)
02305                {
02306                   ErrLog(<<"Caught exception: "<< e);
02307                }
02308             }
02309          }
02310 
02311          sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
02312       }
02313    }
02314    else
02315    {
02316       BIO_free(in);
02317       BIO_free(out);
02318       BIO_free(pkcs7Bio);
02319       sk_X509_free(certs);
02320       PKCS7_free(pkcs7);
02321       *sigStat = SignatureIsBad;
02322       InfoLog(<< "No valid signers of this messages" );
02323       return first;
02324    }
02325 
02326 #if 0
02327    // this is debugging information to get the serial number of the signed
02328    // information
02329    STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
02330    PKCS7_SIGNER_INFO *si;
02331    PKCS7_ISSUER_AND_SERIAL *ias;
02332    ASN1_INTEGER* asnSerial;
02333    long longSerial;
02334    X509_NAME* name;
02335 
02336    sinfos = PKCS7_get_signer_info(pkcs7);
02337    if ( sinfos  )
02338    {
02339       int num = sk_PKCS7_SIGNER_INFO_num(sinfos);
02340       for ( int i=0; i<num; i++ )
02341       {
02342          si = sk_PKCS7_SIGNER_INFO_value (sinfos, i) ;
02343          ias = si->issuer_and_serial;
02344          name = ias->issuer;
02345          asnSerial = ias->serial;
02346          longSerial = ASN1_INTEGER_get( (ASN1_INTEGER*)asnSerial );
02347          InfoLog( << "Signed with serial " << hex << longSerial );
02348          InfoLog( << "Name " << name );
02349       }
02350    }
02351 #endif
02352 
02353    assert( mRootTlsCerts );
02354 
02355    switch (type)
02356    {
02357       case NID_pkcs7_signed:
02358       {
02359          int flags = 0;
02360 
02361          if (isSelfSigned(sk_X509_value(signers,0)))
02362          {
02363             flags |= PKCS7_NOVERIFY;
02364          }
02365 
02366          if ( PKCS7_verify(pkcs7, certs, mRootTlsCerts, pkcs7Bio, out, flags ) != 1 )
02367          {
02368             ErrLog( << "Problems doing PKCS7_verify" );
02369 
02370             if ( sigStat )
02371             {
02372                *sigStat = SignatureIsBad;
02373             }
02374 
02375             while (1)
02376             {
02377                const char* file;
02378                int line;
02379 
02380                unsigned long code = ERR_get_error_line(&file,&line);
02381                if ( code == 0 )
02382                {
02383                   break;
02384                }
02385 
02386                char buf[256];
02387                ERR_error_string_n(code,buf,sizeof(buf));
02388                ErrLog( << buf  );
02389                InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
02390             }
02391             BIO_free(in);
02392             BIO_free(out);
02393             BIO_free(pkcs7Bio);
02394             sk_X509_free(certs);
02395             PKCS7_free(pkcs7);
02396             return first;
02397          }
02398          if ( sigStat )
02399          {
02400             if ( (flags & PKCS7_NOVERIFY) )
02401             {
02402                if (isSelfSigned(sk_X509_value(signers,0)))
02403                {
02404                   DebugLog( << "Signature is selfSigned");
02405                   *sigStat = SignatureSelfSigned;
02406                }
02407                else
02408                {
02409                   DebugLog( << "Signature is notTrusted" );
02410                   *sigStat = SignatureNotTrusted;
02411                }
02412             }
02413             else
02414             {
02415                if (false) // !jf! TODO look for this cert in store
02416                {
02417                   DebugLog( << "Signature is trusted" );
02418                   *sigStat = SignatureTrusted;
02419                }
02420                else
02421                {
02422                   DebugLog( << "Signature is caTrusted" );
02423                   *sigStat = SignatureCATrusted;
02424                }
02425             }
02426          }
02427       }
02428       break;
02429 
02430       default:
02431          BIO_free(in);
02432          BIO_free(out);
02433          BIO_free(pkcs7Bio);
02434          sk_X509_free(certs);
02435          PKCS7_free(pkcs7);
02436          ErrLog(<< "Got PKCS7 data that could not be handled type=" << type );
02437          return 0;
02438    }
02439 
02440    (void)BIO_flush(out);
02441    char* outBuf=0;
02442    long size = BIO_get_mem_data(out,&outBuf);
02443    assert( size >= 0 );
02444 
02445    Data outData(outBuf,size);
02446    DebugLog( << "uncoded body is <" << outData.escaped() << ">" );
02447 
02448    BIO_free(in);
02449    BIO_free(out);
02450    BIO_free(pkcs7Bio);
02451    sk_X509_free(certs);
02452    PKCS7_free(pkcs7);
02453    return first;
02454 }
02455 
02456 
02457 SSL_CTX*
02458 BaseSecurity::getTlsCtx ()
02459 {
02460    assert(mTlsCtx);
02461    return   mTlsCtx;
02462 }
02463 
02464 
02465 SSL_CTX*
02466 BaseSecurity::getSslCtx ()
02467 {
02468    assert(mSslCtx);
02469    return   mSslCtx;
02470 }
02471 
02472 void 
02473 BaseSecurity::getCertNames(X509 *cert, std::list<PeerName> &peerNames,
02474                            bool useEmailAsSIP) 
02475 {
02476    if(NULL == cert)
02477       return;
02478 
02479    if(peerNames.size() > 0)
02480       peerNames.clear();
02481 
02482    Data commonName;
02483 
02484    // look at the Common Name to find the peerName of the cert 
02485    X509_NAME* subject = X509_get_subject_name(cert);
02486    if(NULL == subject)
02487    {
02488       ErrLog( << "Invalid certificate: subject not found ");
02489       return;
02490    }
02491 
02492    int i =-1;
02493    while( true )
02494    {
02495       i = X509_NAME_get_index_by_NID(subject, NID_commonName,i);
02496       if ( i == -1 )
02497       {
02498          break;
02499       }
02500       assert( i != -1 );
02501       X509_NAME_ENTRY* entry = X509_NAME_get_entry(subject,i);
02502       assert( entry );
02503       
02504       ASN1_STRING*      s = X509_NAME_ENTRY_get_data(entry);
02505       assert( s );
02506       
02507       int t = M_ASN1_STRING_type(s);
02508       int l = M_ASN1_STRING_length(s);
02509       unsigned char* d = M_ASN1_STRING_data(s);
02510       Data name(d,l);
02511       DebugLog( << "got x509 string type=" << t << " len="<< l << " data=" << d );
02512       assert( name.size() == (unsigned)l );
02513       
02514       DebugLog( << "Found common name in cert of " << name );
02515       
02516       commonName = name;
02517    }
02518 
02519 #if 0  // junk code to print certificates extentions for debugging 
02520    int numExt = X509_get_ext_count(cert);
02521    ErrLog(<< "Got peer certificate with " << numExt << " extentions" );
02522 
02523    for ( int i=0; i<numExt; i++ )
02524    {
02525       X509_EXTENSION* ext = X509_get_ext(cert,i);
02526       assert( ext );
02527       
02528       const char* str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
02529       assert(str);
02530       DebugLog(<< "Got certificate extention" << str );
02531 
02532       if  ( OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name )
02533       {   
02534          DebugLog(<< "Got subjectAltName extention" );
02535       }
02536    }
02537 #endif 
02538 
02539    // Look at the SubjectAltName, and if found, set as peerName
02540    GENERAL_NAMES* gens;
02541    gens = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
02542    for(int i = 0; i < sk_GENERAL_NAME_num(gens); i++)
02543    {  
02544       GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
02545 
02546       DebugLog(<< "subjectAltName of cert contains type <" << gen->type << ">" );
02547 
02548       if (gen->type == GEN_DNS)
02549       {
02550          ASN1_IA5STRING* asn = gen->d.dNSName;
02551          Data dns(asn->data, asn->length);
02552          PeerName peerName(SubjectAltName, dns);
02553          peerNames.push_back(peerName);
02554          InfoLog(<< "subjectAltName of TLS session cert contains DNS <" << dns << ">" );
02555       }
02556           
02557       if (gen->type == GEN_EMAIL)
02558       {
02559          if(useEmailAsSIP)
02560          {
02561             ASN1_IA5STRING* asn = gen->d.rfc822Name;
02562             Data email(asn->data, asn->length);
02563             PeerName peerName(SubjectAltName, email);
02564             peerNames.push_back(peerName);
02565             InfoLog(<< "subjectAltName of TLS session cert contains EMAIL <" << email << ">" );
02566          }
02567          else
02568             DebugLog(<< "subjectAltName of cert has EMAIL type" );
02569       }
02570           
02571       if(gen->type == GEN_URI) 
02572       {
02573          ASN1_IA5STRING* asn = gen->d.uniformResourceIdentifier;
02574          Uri uri(Data(asn->data, asn->length));
02575          try
02576          {
02577              PeerName peerName(SubjectAltName, uri.host());
02578              peerNames.push_back(peerName);
02579              InfoLog(<< "subjectAltName of TLS session cert contains URI <" << uri << ">" );
02580          }
02581          catch (...)
02582          {
02583              InfoLog(<< "subjectAltName of TLS session cert contains unparseable URI");
02584          }
02585       }
02586    }
02587    sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
02588 
02589    // If there are no peer names from the subjectAltName, then use the commonName
02590    if(peerNames.empty())
02591    {
02592       PeerName peerName(CommonName, commonName);
02593       peerNames.push_back(peerName);
02594    }
02595 }
02596 
02597 Data 
02598 BaseSecurity::getCertName(X509 *cert)
02599 {
02600    Data certName;
02601    std::list<PeerName> cNames;
02602 
02603    //get all the names (subjectAltName or CommonName)
02604    getCertNames(cert, cNames);
02605 
02606    //prefere the subjectAltName
02607    for(std::list<PeerName>::const_iterator it = cNames.begin(); it != cNames.end(); it++)
02608    {
02609       if(it->mType == SubjectAltName)
02610       {
02611          return it->mName;
02612       }
02613    }
02614 
02615    //if not subjectAltName found, get the CommonName
02616    for(std::list<PeerName>::const_iterator it = cNames.begin(); it != cNames.end(); it++)
02617    {
02618       if(it->mType == CommonName)
02619       {
02620          return it->mName;
02621       }
02622    }
02623    ErrLog(<< "This certificate doesn't have neither subjectAltName nor commonName");
02624    return Data::Empty;
02625 }
02629 int 
02630 BaseSecurity::matchHostName(const Data& certificateName, const Data& domainName)
02631 {
02632    if(mAllowWildcardCertificates)
02633       return matchHostNameWithWildcards(certificateName,domainName);
02634    return isEqualNoCase(certificateName,domainName);
02635 }
02640 int 
02641 BaseSecurity::matchHostNameWithWildcards(const Data& certificateName, const Data& domainName)
02642 {
02643    const char *dot = NULL;
02644 
02645    const char *certName = certificateName.c_str();
02646    if(certName == NULL)
02647       return 0;
02648 
02649    const char *domName = domainName.c_str();
02650    if(domName == NULL)
02651       return 0;
02652 
02653    dot = strchr(domName, '.');
02654    if (dot == NULL)
02655    {
02656       char *pnt = (char *)strchr(certName, '.'); // bad
02657       /* hostname is not fully-qualified; unqualify the certName. */
02658       if (pnt != NULL) 
02659       {
02660          *pnt = '\0';
02661       }
02662    }
02663    else 
02664    {
02665       if (strncmp(certName, "*.", 2) == 0) 
02666       {
02667          domName = dot + 1;
02668          certName += 2;
02669       }
02670    }
02671    return !strcasecmp(certName, domName);
02672 }
02673 
02674 bool
02675 BaseSecurity::isSelfSigned(const X509 *cert)
02676 {
02677    int iRet = X509_NAME_cmp(cert->cert_info->issuer, cert->cert_info->subject);
02678    return (iRet == 0);
02679 }
02680 
02681 void
02682 BaseSecurity::dumpAsn( char* name, Data data)
02683 {
02684 #if 0 // for debugging
02685    assert(name);
02686 
02687    if (true) // dump asn.1 stuff to debug file
02688    {
02689       ofstream strm(name, std::ios_base::trunc);
02690       if ( !strm )
02691       {
02692          ErrLog( <<"Could not write to " << name );
02693       }
02694       else
02695       {
02696          strm.write( data.data() , data.size() );
02697       }
02698       strm.flush();
02699    }
02700 #endif
02701 }
02702 
02703 X509*     
02704 BaseSecurity::getDomainCert( const Data& domain )
02705 {
02706    return mDomainCerts.count(domain) ? mDomainCerts[domain] : 0;
02707 }
02708 
02709 X509*     
02710 BaseSecurity::getUserCert( const Data& aor )
02711 {
02712    return mUserCerts.count(aor) ? mUserCerts[aor] : 0;
02713 }
02714 
02715 EVP_PKEY* 
02716 BaseSecurity::getDomainKey(  const Data& domain )
02717 {
02718    return mDomainPrivateKeys.count(domain) ? mDomainPrivateKeys[domain] : 0;
02719 }
02720 
02721 EVP_PKEY*
02722 BaseSecurity::getUserPrivateKey( const Data& aor )
02723 {
02724    return mUserPrivateKeys.count(aor) ? mUserPrivateKeys[aor] : 0;
02725 }
02726 
02727 #endif
02728 
02729 
02730 
02731 
02732 /* ====================================================================
02733 * The Vovida Software License, Version 1.0
02734 *
02735 * Copyright (c) 2002-2005 Vovida Networks, Inc.  All rights reserved.
02736 *
02737 * Redistribution and use in source and binary forms, with or without
02738 * modification, are permitted provided that the following conditions
02739 * are met:
02740 *
02741 * 1. Redistributions of source code must retain the above copyright
02742 *    notice, this list of conditions and the following disclaimer.
02743 *
02744 * 2. Redistributions in binary form must reproduce the above copyright
02745 *    notice, this list of conditions and the following disclaimer in
02746 *    the documentation and/or other materials provided with the
02747 *    distribution.
02748 *
02749 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
02750 *    and "Vovida Open Communication Application Library (VOCAL)" must
02751 *    not be used to endorse or promote products derived from this
02752 *    software without prior written permission. For written
02753 *    permission, please contact vocal@vovida.org.
02754 *
02755 * 4. Products derived from this software may not be called "VOCAL", nor
02756 *    may "VOCAL" appear in their name, without prior written
02757 *    permission of Vovida Networks, Inc.
02758 *
02759 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
02760 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
02761 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
02762 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
02763 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
02764 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
02765 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
02766 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
02767 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
02768 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
02769 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
02770 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
02771 * DAMAGE.
02772 *
02773 * ====================================================================
02774 *
02775 * This software consists of voluntary contributions made by Vovida
02776 * Networks, Inc. and many individuals on behalf of Vovida Networks,
02777 * Inc.  For more information on Vovida Networks, Inc., please see
02778 * <http://www.vovida.org/>.
02779 *
02780 */