📄 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::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 + -