📄 tlsconnection.cxx
字号:
#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif
#include "resip/stack/TlsConnection.hxx"
#include "resip/stack/Security.hxx"
#include "rutil/Logger.hxx"
#include "resip/stack/Uri.hxx"
#include "rutil/Socket.hxx"
#if defined(USE_SSL)
#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/x509v3.h>
#include <openssl/ssl.h>
#endif
using namespace resip;
#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
TlsConnection::TlsConnection( const Tuple& tuple, Socket fd, Security* security,
bool server, Data domain, SecurityTypes::SSLType sslType ,
Compression &compression) :
Connection(tuple, fd, compression),
mServer(server),
mSecurity(security),
mSslType( sslType ),
mDomain(domain)
{
#if defined(USE_SSL)
InfoLog (<< "Creating TLS connection for domain "
<< mDomain
<< " " << tuple
<< " on " << fd);
mSsl = NULL;
mBio= NULL;
if (mServer)
{
DebugLog( << "Trying to form TLS connection - acting as server" );
if ( mDomain.empty() )
{
ErrLog(<< "Tranport was not created with a server domain so can not act as server" );
throw Security::Exception("Trying to act as server but no domain specified",
__FILE__,__LINE__);
}
}
else
{
DebugLog( << "Trying to form TLS connection - acting as client" );
}
assert( mSecurity );
SSL_CTX* ctx=NULL;
if ( mSslType == SecurityTypes::SSLv23 )
{
ctx = mSecurity->getSslCtx();
}
else
{
ctx = mSecurity->getTlsCtx();
}
assert(ctx);
mSsl = SSL_new(ctx);
assert(mSsl);
if ( mServer )
{
assert( mSecurity );
X509* cert = mSecurity->getDomainCert(mDomain); //mDomainCerts[mDomain];
if (!cert)
{
ErrLog(<< "Don't have certificate for domain " << mDomain );
}
if( !SSL_use_certificate(mSsl, cert) )
{
throw Security::Exception("SSL_use_certificate failed",
__FILE__,__LINE__);
}
EVP_PKEY* pKey = mSecurity->getDomainKey(mDomain); //mDomainPrivateKeys[mDomain];
if (!pKey)
{
ErrLog(<< "Don't have private key for domain " << mDomain );
}
if ( !SSL_use_PrivateKey(mSsl, pKey) )
{
throw Security::Exception("SSL_use_PrivateKey failed.",
__FILE__,__LINE__);
}
}
mBio = BIO_new_socket(fd,0/*close flag*/);
assert( mBio );
SSL_set_bio( mSsl, mBio, mBio );
mTlsState = mServer ? Accepting : Connecting;
#endif // USE_SSL
}
TlsConnection::~TlsConnection()
{
#if defined(USE_SSL)
SSL_shutdown(mSsl);
SSL_free(mSsl);
#endif // USE_SSL
}
const char*
TlsConnection::fromState(TlsConnection::TlsState s)
{
switch(s)
{
case Handshaking: return "Handshaking"; break;
case Accepting: return "Accepting"; break;
case Broken: return "Broken"; break;
case Connecting: return "Connecting"; break;
case Up: return "Up"; break;
}
return "????";
}
TlsConnection::TlsState
TlsConnection::checkState()
{
#if defined(USE_SSL)
//DebugLog(<<"state is " << fromTlsState(mTlsState));
if (mTlsState == Up || mTlsState == Broken)
{
return mTlsState;
}
int ok=0;
ERR_clear_error();
if (mTlsState != Handshaking)
{
if (mTlsState == Accepting)
{
ok = SSL_accept(mSsl);
}
else
{
ok = SSL_connect(mSsl);
//StackLog( << "TLS SSL_connect - state = " << fromTlsState(mTlsState) );
}
if ( ok <= 0 )
{
int err = SSL_get_error(mSsl,ok);
char buf[256];
ERR_error_string_n(err,buf,sizeof(buf));
// StackLog( << "TLS error in "
// << (char*)( (mTlsState == Accepting) ? (char*)"accept" : (char*)"connect" )
// << " ok=" << ok << " err=" << err << " " << buf );
switch (err)
{
case SSL_ERROR_WANT_READ:
//StackLog( << "TLS connection want read" );
return mTlsState;
case SSL_ERROR_WANT_WRITE:
//StackLog( << "TLS connection want write" );
return mTlsState;
case SSL_ERROR_WANT_CONNECT:
//StackLog( << "TLS connection want connect" );
return mTlsState;
#if ( OPENSSL_VERSION_NUMBER >= 0x0090702fL )
case SSL_ERROR_WANT_ACCEPT:
//StackLog( << "TLS connection want accept" );
return mTlsState;
#endif
}
ErrLog( << "TLS connection failed "
<< "ok=" << ok << " err=" << err << " " << buf );
switch (err)
{
case SSL_ERROR_NONE:
ErrLog( <<" (SSL Error none)" );
break;
case SSL_ERROR_SSL:
ErrLog( <<" (SSL Error ssl)" );
break;
case SSL_ERROR_WANT_READ:
ErrLog( <<" (SSL Error want read)" );
break;
case SSL_ERROR_WANT_WRITE:
ErrLog( <<" (SSL Error want write)" );
break;
case SSL_ERROR_WANT_X509_LOOKUP:
ErrLog( <<" (SSL Error want x509 lookup)" );
break;
case SSL_ERROR_SYSCALL:
ErrLog( <<" (SSL Error want syscall)" );
ErrLog( <<"Error may be because trying ssl connection to tls server" );
break;
case SSL_ERROR_WANT_CONNECT:
ErrLog( <<" (SSL Error want connect)" );
break;
#if ( OPENSSL_VERSION_NUMBER >= 0x0090702fL )
case SSL_ERROR_WANT_ACCEPT:
ErrLog( <<" (SSL Error want accept)" );
break;
#endif
}
while (true)
{
const char* file;
int line;
unsigned long code = ERR_get_error_line(&file,&line);
if ( code == 0 )
{
break;
}
char buf[256];
ERR_error_string_n(code,buf,sizeof(buf));
ErrLog( << buf );
ErrLog( << "Error code = "
<< code << " file=" << file << " line=" << line );
}
mTlsState = Broken;
mBio = 0;
//.dcm. -- may not be correct
mFailureReason = TransportFailure::CertValidationFailure;
ErrLog (<< "Couldn't TLS connect");
return mTlsState;
}
InfoLog( << "TLS connected" );
mTlsState = Handshaking;
}
InfoLog( << "TLS handshake starting" );
ok = SSL_do_handshake(mSsl);
if ( ok <= 0 )
{
int err = SSL_get_error(mSsl,ok);
char buf[256];
ERR_error_string_n(err,buf,sizeof(buf));
switch (err)
{
case SSL_ERROR_WANT_READ:
StackLog( << "TLS handshake want read" );
return mTlsState;
case SSL_ERROR_WANT_WRITE:
StackLog( << "TLS handshake want write" );
return mTlsState;
default:
ErrLog( << "TLS handshake failed "
<< "ok=" << ok << " err=" << err << " " << buf );
mBio = NULL;
mTlsState = Broken;
mFailureReason = TransportFailure::CertValidationFailure;
return mTlsState;
}
}
// force peer name to get checked and perhaps cert loaded
computePeerName();
//post-connection verification: check that certificate name matches domain name
if (!mServer)
{
bool matches = false;
for(std::list<Data>::iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
{
if(isEqualNoCase(*it, who().getTargetDomain()))
{
matches=true;
break;
}
}
if(!matches)
{
mTlsState = Broken;
mBio = 0;
ErrLog (<< "Certificate name mismatch: trying to connect to <"
<< who().getTargetDomain()
<< "> remote cert domain(s) are <"
<< getPeerNamesData() << ">" );
mFailureReason = TransportFailure::CertNameMismatch;
return mTlsState;
}
}
InfoLog( << "TLS handshake done for peer " << getPeerNamesData());
mTlsState = Up;
#endif // USE_SSL
return mTlsState;
}
int
TlsConnection::read(char* buf, int count )
{
#if defined(USE_SSL)
assert( mSsl );
assert( buf );
switch(checkState())
{
case Broken:
return -1;
break;
case Up:
break;
default:
return 0;
break;
}
if (!mBio)
{
DebugLog( << "Got TLS read bad bio " );
return 0;
}
if ( !isGood() )
{
return -1;
}
int bytesRead = SSL_read(mSsl,buf,count);
StackLog(<< "SSL_read returned " << bytesRead << " bytes [" << Data(Data::Borrow, buf, bytesRead) << "]");
if (bytesRead > 0 && SSL_pending(mSsl))
{
int restBytes = SSL_pending(mSsl);
char* buffer = getWriteBufferForExtraBytes(restBytes);
StackLog(<< "reading remaining buffered bytes");
restBytes = SSL_read(mSsl, buffer, SSL_pending(mSsl));
StackLog(<< "SSL_read returned " << restBytes << " bytes [" << Data(Data::Borrow, buffer, restBytes) << "]");
if (restBytes>0)
{
bytesRead += restBytes;
}
else
{
bytesRead = restBytes;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -