⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 security.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 5 页
字号:
#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif

#include <ostream>
#include <fstream>

#include "resip/stack/Contents.hxx"
#include "resip/stack/MultipartSignedContents.hxx"
#include "resip/stack/Pkcs7Contents.hxx"
#include "resip/stack/PlainContents.hxx"
#include "resip/stack/Security.hxx"
#include "resip/stack/SecurityAttributes.hxx"
#include "resip/stack/Transport.hxx"
#include "resip/stack/SipMessage.hxx"
#include "rutil/BaseException.hxx"
#include "rutil/DataStream.hxx"
#include "rutil/Logger.hxx"
#include "rutil/Random.hxx"
#include "rutil/SHA1Stream.hxx"
#include "rutil/Socket.hxx"
#include "rutil/Timer.hxx"
#include "rutil/ParseBuffer.hxx"
#include "rutil/FileSystem.hxx"
#include "rutil/WinLeakCheck.hxx"


#if defined(USE_SSL)

#if !defined(WIN32)
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <dirent.h>
#endif

#include <sys/types.h>
#include <openssl/e_os2.h>
#include <openssl/evp.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/ossl_typ.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/ssl.h>

using namespace resip;
using namespace std;

#define RESIPROCATE_SUBSYSTEM Subsystem::SIP

static const Data PEM(".pem");

static const Data 
pemTypePrefixes(  Security::PEMType pType )
{
   static const Data rootCert("root_cert_");
   static const Data domainCert("domain_cert_");
   static const Data domainKey("domain_key_");
   static const Data userCert("user_cert_");
   static const Data userKey("user_key_");
   static const Data unknownKey("user_key_");

   switch (pType)
   {
      case  Security::RootCert:         return rootCert;
      case  Security::DomainCert:       return domainCert;
      case  Security::DomainPrivateKey: return domainKey;
      case  Security::UserCert:         return userCert;
      case  Security::UserPrivateKey:   return userKey;
      default:
      {
         ErrLog( << "Some unkonw pem type prefix requested" << (int)(pType) );
         assert(0);
      }
   }
   return unknownKey;
}

static Data
readIntoData(const Data& filename)
{
   DebugLog( << "Trying to read file " << filename );
   
   ifstream is;
   is.open(filename.c_str(), ios::binary );
   if ( !is.is_open() )
   {
      ErrLog( << "Could not open file " << filename << " for read");
      throw BaseSecurity::Exception("Could not read file ", 
                                    __FILE__,__LINE__);
   }
   
   assert(is.is_open());
   
   int length = 0;
   
   // get length of file:
#if !defined(__MSL_CPP__) || (__MSL_CPP_ >= 0x00012000)
   is.seekg (0, ios::end);
   length = is.tellg();
   is.seekg (0, ios::beg);
#else
   // this is a work around for a bug in CodeWarrior 9's implementation of seekg.
   // http://groups.google.ca/group/comp.sys.mac.programmer.codewarrior/browse_frm/thread/a4279eb75f3bd55a
   FILE * tmpFile = fopen(filename.c_str(), "r+b");
   assert(tmpFile != NULL);
   fseek(tmpFile, 0, SEEK_END);
   length = ftell(tmpFile);
   fseek(tmpFile, 0, SEEK_SET);
#endif // __MWERKS__
   
   // tellg/tell will return -1 if the stream is bad
   if (length == -1)
   {
      ErrLog( << "Could not seek into file " << filename);
      throw BaseSecurity::Exception("Could not seek into file ", 
                                    __FILE__,__LINE__);
   }
   
   // !jf! +1 is a workaround for a bug in Data::c_str() that adds the 0 without
   // resizing. 
   char* buffer = new char [length+1]; 
   
   // read data as a block:
   is.read (buffer,length);
   
   Data target(Data::Take, buffer, length);
   
   is.close();
   
   return target;
}


static Data
getAor(const Data& filename, const  Security::PEMType &pemType )
{
   const Data& prefix = pemTypePrefixes( pemType );
   return filename.substr(prefix.size(), filename.size() - prefix.size() - PEM.size());
}

extern "C"
{
   
static int 
verifyCallback(int iInCode, X509_STORE_CTX *pInStore)
{
   char cBuf1[500];
   char cBuf2[500];
   X509 *pErrCert;
   int iErr = 0;
   int iDepth = 0;
   pErrCert = X509_STORE_CTX_get_current_cert(pInStore);
   iErr = X509_STORE_CTX_get_error(pInStore);
   iDepth = X509_STORE_CTX_get_error_depth(pInStore);

   if (NULL != pErrCert)
      X509_NAME_oneline(X509_get_subject_name(pErrCert),cBuf1,256);

   sprintf(cBuf2,", depth=%d %s\n",iDepth,cBuf1);
   if(!iInCode)
      ErrLog(<< "Error when verifying server's chain of certificates: " << X509_verify_cert_error_string(pInStore->error) << cBuf2 );
 
   return iInCode;
}
 
}

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");
BaseSecurity::CipherList BaseSecurity::StrongestSuite("!SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES");

Security::Security(const CipherList& cipherSuite) : BaseSecurity(cipherSuite)
{
#ifdef WIN32
   mPath = "C:\\sipCerts\\";
#else
   mPath = getenv("HOME");
   mPath += "/.sipCerts/";
#endif
}

Security::Security(const Data& directory, const CipherList& cipherSuite) : 
   BaseSecurity(cipherSuite), 
   mPath(directory)
{
   // since the preloader won't work otherwise and VERY difficult to figure
   // out. 
   if ( !mPath.postfix(Symbols::SLASH))
   {
      mPath += Symbols::SLASH;
   }
}


void
Security::preload()
{
#if 1
   FileSystem::Directory dir(mPath);
   FileSystem::Directory::iterator it(dir);
   for (; it != dir.end(); ++it)
   {
      Data name = *it;
           
      if (name.postfix(PEM))
      {
         Data fileName = mPath + name;
         
         DebugLog(<< "Trying to load file " << name );
         try
         {
            if (name.prefix(pemTypePrefixes(UserCert)))
            {
               addCertPEM( UserCert, getAor(name, UserCert), readIntoData(fileName), false );
            }
            else if (name.prefix(pemTypePrefixes(UserPrivateKey)))
            {
               addPrivateKeyPEM( UserPrivateKey, getAor(name, UserPrivateKey), readIntoData(fileName), false);
            }
            else if (name.prefix(pemTypePrefixes(DomainCert)))
            {
               addCertPEM( DomainCert, getAor(name, DomainCert), readIntoData(fileName), false);
            }
            else if (name.prefix(pemTypePrefixes(DomainPrivateKey)))
            {
               addPrivateKeyPEM( DomainPrivateKey, getAor(name, DomainPrivateKey), readIntoData(fileName), false);
            }
            else if (name.prefix(pemTypePrefixes(RootCert)))
            {
               addRootCertPEM(readIntoData(fileName));
            }
         }
         catch (...)
         {  
            ErrLog(<< "Some problem reading " << fileName );
         }
         
         InfoLog(<<"Sucessfully loaded " << fileName );
      }
   }
#else
   // CJ - TODO - delete this old crap 
   DIR* dir = opendir( mPath.c_str() );

   if (!dir )
   {
      ErrLog( << "Error reading public key directory  " << mPath );
      return;      
   }

   struct dirent * d = 0;
   while (1)
   {
      d = readdir(dir);
      if ( !d )
      {
         break;
      }

      Data name( d->d_name );
      Data fileName = mPath+name;
      
      if (name.postfix(PEM))
      {
         InfoLog( << "Going to try to read file " << fileName );
         
         try
         {
            if (name.prefix(pemTypePrefixes(UserCert)))
            {
               addCertPEM( UserCert, getAor(name, UserCert), readIntoData(fileName), false );
            }
            else if (name.prefix(pemTypePrefixes(UserPrivateKey)))
            {
               addPrivateKeyPEM( UserPrivateKey, getAor(name, UserPrivateKey), readIntoData(fileName), false);
            }
            else if (name.prefix(pemTypePrefixes(DomainCert)))
            {
               addCertPEM( DomainCert, getAor(name, DomainCert), readIntoData(fileName), false);
            }
            else if (name.prefix(pemTypePrefixes(DomainPrivateKey)))
            {
               addPrivateKeyPEM( DomainPrivateKey, getAor(name, DomainPrivateKey), readIntoData(fileName), false);
            }
            else if (name.prefix(pemTypePrefixes(RootCert)))
            {
               addRootCertPEM(readIntoData(fileName));
            }
         }
         catch (...)
         {  
            ErrLog(<< "Some problem reading " << fileName );
         }
         
         InfoLog(<<"Sucessfully loaded " << fileName );
      }
   }
   closedir( dir );
#endif
}


void
Security::onReadPEM(const Data& name, PEMType type, Data& buffer) const
{
   Data filename = mPath + pemTypePrefixes(type) + name + PEM;

   InfoLog (<< "Reading PEM file " << filename << " into " << name);
   // .dlb. extra copy
   buffer = readIntoData(filename);
}


void
Security::onWritePEM(const Data& name, PEMType type, const Data& buffer) const
{
   Data filename = mPath + pemTypePrefixes(type) + name + PEM;
   InfoLog (<< "Writing PEM file " << filename << " for " << name);
   ofstream str(filename.c_str(), ios::binary);
   if (!str)
   {
      ErrLog (<< "Can't write to " << filename);
      throw BaseSecurity::Exception("Failed opening PEM file", __FILE__,__LINE__);
   }
   else
   {
      str.write(buffer.data(), buffer.size());
      if (!str)
      {
         ErrLog (<< "Failed writing to " << filename << " " << buffer.size() << " bytes");
         throw BaseSecurity::Exception("Failed writing PEM file", __FILE__,__LINE__);
      }
   }
}


void
Security::onRemovePEM(const Data& name, PEMType type) const
{
   assert(0);
   // TODO - should delete file 
}


void
BaseSecurity::addCertDER (PEMType type, 
                          const Data& key, 
                          const Data& certDER, 
                          bool write) const
{
   assert( !certDER.empty() );

   X509* cert = 0;

#if (OPENSSL_VERSION_NUMBER < 0x0090800fL )
   unsigned char* in = (unsigned char*)certDER.data();
#else
   unsigned const char* in = (unsigned const char*)certDER.data();
#endif

   if (d2i_X509(&cert,&in,certDER.size()) == 0)
   {
      ErrLog(<< "Could not read DER certificate from " << certDER );
      throw BaseSecurity::Exception("Could not read DER certificate ", 
                                    __FILE__,__LINE__);
   }
   addCertX509(type,key,cert,write);
}


void
BaseSecurity::addCertPEM (PEMType type, 
                          const Data& name, 
                          const Data& certPEM, 
                          bool write) const
{
   assert( !certPEM.empty() );
   X509* cert=NULL;
   
   BIO* in = BIO_new_mem_buf(const_cast<char*>(certPEM.c_str()), -1);
   if ( !in )
   {
      ErrLog(<< "Could not create BIO buffer from '" << certPEM << "'");
      throw Exception("Could not create BIO buffer", __FILE__,__LINE__);
   }
   cert = PEM_read_bio_X509(in,0,0,0);
   if (cert == NULL)
   {
	   ErrLog( << "Could not load X509 cert from '" << certPEM << "'" );
	   BIO_free(in); 
	   throw Exception("Could not load X509 cert from BIO buffer", __FILE__,__LINE__);
   }
   
   addCertX509(type,name,cert,write);
   
   BIO_free(in);
}


void
BaseSecurity::addCertX509(PEMType type, const Data& key, X509* cert, bool write) const
{
   switch (type)
   {
      case DomainCert:
      {
         mDomainCerts.insert(std::make_pair(key, cert));
      }
      break;
      case UserCert:
      { 
         mUserCerts.insert(std::make_pair(key, cert));
      }
      break;
      case RootCert:
      {
         X509_STORE_add_cert(mRootTlsCerts,cert);
         X509_STORE_add_cert(mRootSslCerts,cert);
         X509_free(cert);
      }
      break;
      default:
      {
         assert(0);
      }
   }
   
   if (write)
   {
      // creates a read/write BIO buffer.
      BIO *out = BIO_new(BIO_s_mem());
      assert(out);
      try
      {
         int ret = PEM_write_bio_X509(out, cert);
         assert(ret);
         
         BIO_flush(out);
         // get content in BIO buffer to our buffer.
         char* p = 0;
         size_t len = BIO_get_mem_data(out,&p);
         assert(p);
         assert(len);
         Data  buf(Data::Borrow, p, len);
         
         this->onWritePEM(key, type, buf);
      }
      catch(...)
      {
         BIO_free(out);
         throw;
      }
      BIO_free(out);
   }
}


bool
BaseSecurity::hasCert (PEMType type, const Data& aor) const
{
   assert( !aor.empty() );
   X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts);

   X509Map::iterator where = certs.find(aor);
   if (where != certs.end())
   {
      return true;
   }
   
   try
   {
      Data certPEM;
      onReadPEM(aor, type, certPEM);
      if (certPEM.empty())
      {
         return false;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -