📄 security.cxx
字号:
#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::SIPstatic 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 DatareadIntoData(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 DatagetAor(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 const char* env=getenv("HOME"); if(env) { mPath = env; } 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; }}voidSecurity::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; bool attemptedToLoad = true; DebugLog(<< "Checking 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)); } else { DebugLog(<< "PEM file " << name << " does not have appropriate resip prefix, skipping..."); attemptedToLoad = false; } } catch (...) { ErrLog(<< "Some problem reading " << fileName ); } if(attemptedToLoad) { 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}voidSecurity::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);}voidSecurity::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__); } }}voidSecurity::onRemovePEM(const Data& name, PEMType type) const{ assert(0); // TODO - should delete file }voidBaseSecurity::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);}voidBaseSecurity::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);}voidBaseSecurity::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(...) { ErrLog(<<"Caught exception: "); BIO_free(out); throw; } BIO_free(out); }}boolBaseSecurity::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; } BaseSecurity* mutable_this = const_cast<BaseSecurity*>(this); mutable_this->addCertPEM(type, aor, certPEM, false); } catch (...) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -