|
reSIProcate/stack
9694
|
#include <TlsConnection.hxx>


Public Types | |
| enum | TlsState { Initial, Broken, Handshaking, Up } |
| typedef enum resip::TlsConnection::TlsState | TlsState |
Public Member Functions | |
| RESIP_HeapCount (TlsConnection) | |
| TlsConnection (Transport *transport, const Tuple &who, Socket fd, Security *security, bool server, Data domain, SecurityTypes::SSLType sslType, Compression &compression) | |
| virtual | ~TlsConnection () |
| int | read (char *buf, const int count) |
| pure virtual, but need concrete Connection for book-ends of lists | |
| int | write (const char *buf, const int count) |
| pure virtual, but need concrete Connection for book-ends of lists | |
| virtual bool | hasDataToRead () |
| always true -- always add to fdset as read ready | |
| virtual bool | isGood () |
| has valid connection | |
| virtual bool | isWritable () |
| virtual bool | transportWrite () |
| void | getPeerNames (std::list< Data > &peerNames) const |
Static Public Member Functions | |
| static const char * | fromState (TlsState) |
Private Member Functions | |
| TlsConnection () | |
| No default c'tor. | |
| void | computePeerName () |
| Data | getPeerNamesData () const |
| TlsState | checkState () |
Private Attributes | |
| bool | mServer |
| Security * | mSecurity |
| SecurityTypes::SSLType | mSslType |
| Data | mDomain |
| TlsState | mTlsState |
| bool | mHandShakeWantsRead |
| SSL * | mSsl |
| BIO * | mBio |
| std::list< BaseSecurity::PeerName > | mPeerNames |
Definition at line 32 of file TlsConnection.hxx.
Definition at line 54 of file TlsConnection.hxx.
{ Initial, Broken, Handshaking, Up } TlsState;
| TlsConnection::TlsConnection | ( | Transport * | transport, |
| const Tuple & | who, | ||
| Socket | fd, | ||
| Security * | security, | ||
| bool | server, | ||
| Data | domain, | ||
| SecurityTypes::SSLType | sslType, | ||
| Compression & | compression | ||
| ) |
Definition at line 28 of file TlsConnection.cxx.
References DebugLog, resip::Data::empty(), ErrLog, resip::TlsTransport::getClientVerificationMode(), resip::TlsTransport::getCtx(), InfoLog, Initial, resip::SecurityTypes::Mandatory, mBio, mDomain, mHandShakeWantsRead, mSecurity, mServer, mSsl, mTlsState, resip::SecurityTypes::None, resip::SecurityTypes::Optional, and resip::ConnectionBase::transport().
: Connection(transport,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 ); TlsTransport *t = dynamic_cast<TlsTransport*>(transport); assert(t); SSL_CTX* ctx=t->getCtx(); assert(ctx); mSsl = SSL_new(ctx); assert(mSsl); assert( mSecurity ); if(mServer) { // clear SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE set in SSL_CTX if we are a server int verify_mode; switch(t->getClientVerificationMode()) { case SecurityTypes::None: verify_mode = SSL_VERIFY_NONE; DebugLog(<< "Not expecting client certificate" ); break; case SecurityTypes::Optional: verify_mode = SSL_VERIFY_PEER; DebugLog(<< "Optional client certificate mode" ); break; case SecurityTypes::Mandatory: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; DebugLog(<< "Mandatory client certificate mode" ); break; default: assert( 0 ); } SSL_set_verify(mSsl, verify_mode, 0); } mBio = BIO_new_socket((int)fd,0/*close flag*/); assert( mBio ); SSL_set_bio( mSsl, mBio, mBio ); mTlsState = Initial; mHandShakeWantsRead = false; #endif // USE_SSL }

| TlsConnection::~TlsConnection | ( | ) | [virtual] |
Definition at line 109 of file TlsConnection.cxx.
References mSsl.
| resip::TlsConnection::TlsConnection | ( | ) | [private] |
No default c'tor.
| TlsConnection::TlsState TlsConnection::checkState | ( | ) | [private] |
Definition at line 132 of file TlsConnection.cxx.
References Broken, resip::TransportFailure::CertNameMismatch, resip::TransportFailure::CertValidationFailure, computePeerName(), resip::Connection::ensureWritable(), ErrLog, resip::Transport::error(), resip::getErrno(), getPeerNamesData(), Handshaking, InfoLog, resip::BaseSecurity::matchHostName(), mBio, resip::ConnectionBase::mFailureReason, mHandShakeWantsRead, resip::ConnectionBase::mOutstandingSends, mPeerNames, mServer, mSsl, mTlsState, StackLog, Up, and resip::ConnectionBase::who().
Referenced by hasDataToRead(), read(), transportWrite(), and write().
{
#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 (mServer)
{
InfoLog( << "TLS handshake starting (Server mode)" );
SSL_set_accept_state(mSsl);
mTlsState = Handshaking;
}
else
{
InfoLog( << "TLS handshake starting (client mode)" );
SSL_set_connect_state(mSsl);
mTlsState = Handshaking;
}
InfoLog( << "TLS connected" );
mTlsState = Handshaking;
}
mHandShakeWantsRead = false;
ok = SSL_do_handshake(mSsl);
if ( ok <= 0 )
{
int err = SSL_get_error(mSsl,ok);
switch (err)
{
case SSL_ERROR_WANT_READ:
StackLog( << "TLS handshake want read" );
mHandShakeWantsRead = true;
return mTlsState;
case SSL_ERROR_WANT_WRITE:
StackLog( << "TLS handshake want write" );
ensureWritable();
return mTlsState;
case SSL_ERROR_ZERO_RETURN:
StackLog( << "TLS connection closed cleanly");
return mTlsState;
case SSL_ERROR_WANT_CONNECT:
StackLog( << "BIO not connected, try later");
return mTlsState;
#if ( OPENSSL_VERSION_NUMBER >= 0x0090702fL )
case SSL_ERROR_WANT_ACCEPT:
StackLog( << "TLS connection want accept" );
return mTlsState;
#endif
case SSL_ERROR_WANT_X509_LOOKUP:
StackLog( << "Try later");
return mTlsState;
default:
if(err == SSL_ERROR_SYSCALL)
{
int e = getErrno();
switch(e)
{
case EINTR:
case EAGAIN:
StackLog( << "try later");
return mTlsState;
}
ErrLog( << "socket error " << e);
Transport::error(e);
}
else if (err == SSL_ERROR_SSL)
{
mFailureReason = TransportFailure::CertValidationFailure;
}
ErrLog( << "TLS handshake failed ");
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 );
}
mBio = NULL;
mTlsState = Broken;
return mTlsState;
}
}
else // ok > 1
{
InfoLog( << "TLS connected" );
}
// 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<BaseSecurity::PeerName>::iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
{
if(BaseSecurity::matchHostName(it->mName, who().getTargetDomain()))
{
matches=true;
break;
}
}
if(!matches)
{
mTlsState = Broken;
mBio = NULL;
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;
if (!mOutstandingSends.empty())
{
ensureWritable();
}
#endif // USE_SSL
return mTlsState;
}

| void TlsConnection::computePeerName | ( | ) | [private] |
Definition at line 568 of file TlsConnection.cxx.
References resip::BaseSecurity::addDomainCertDER(), DebugLog, ErrLog, resip::BaseSecurity::getCertNames(), resip::BaseSecurity::hasDomainCert(), InfoLog, resip::TlsTransport::isUseEmailAsSIP(), len, mBio, mPeerNames, mSecurity, mServer, mSsl, and resip::ConnectionBase::mTransport.
Referenced by checkState().
{
#if defined(USE_SSL)
Data commonName;
assert(mSsl);
if (!mBio)
{
ErrLog( << "bad bio" );
return;
}
// print session infor
const SSL_CIPHER *ciph;
ciph=SSL_get_current_cipher(mSsl);
InfoLog( << "TLS sessions set up with "
<< SSL_get_version(mSsl) << " "
<< SSL_CIPHER_get_version(ciph) << " "
<< SSL_CIPHER_get_name(ciph) << " " );
// get the certificate if other side has one
X509* cert = SSL_get_peer_certificate(mSsl);
if ( !cert )
{
DebugLog(<< "No peer certificate in TLS connection" );
return;
}
// check that this certificate is valid
if (X509_V_OK != SSL_get_verify_result(mSsl))
{
DebugLog(<< "Peer certificate in TLS connection is not valid" );
X509_free(cert); cert=NULL;
return;
}
TlsTransport *t = dynamic_cast<TlsTransport*>(mTransport);
assert(t);
mPeerNames.clear();
BaseSecurity::getCertNames(cert, mPeerNames,
t->isUseEmailAsSIP());
if(mPeerNames.empty())
{
ErrLog(<< "Invalid certificate: no subjectAltName/CommonName found");
return;
}
if(!mServer)
{
// add the certificate to the Security store
unsigned char* buf = NULL;
int len = i2d_X509( cert, &buf );
Data derCert( buf, len );
for(std::list<BaseSecurity::PeerName>::iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
{
if ( !mSecurity->hasDomainCert( it->mName ) )
{
mSecurity->addDomainCertDER(it->mName,derCert);
}
}
OPENSSL_free(buf); buf=NULL;
}
X509_free(cert); cert=NULL;
#endif // USE_SSL
}

| const char * TlsConnection::fromState | ( | TlsConnection::TlsState | s | ) | [static] |
Definition at line 119 of file TlsConnection.cxx.
References Broken, Handshaking, Initial, and Up.
Referenced by isWritable(), and transportWrite().
{
switch(s)
{
case Initial: return "Initial"; break;
case Handshaking: return "Handshaking"; break;
case Broken: return "Broken"; break;
case Up: return "Up"; break;
}
return "????";
}
| void TlsConnection::getPeerNames | ( | std::list< Data > & | peerNames | ) | const |
Definition at line 540 of file TlsConnection.cxx.
References mPeerNames.
Referenced by resip::ConnectionBase::preparseNewBytes().
{
for(std::list<BaseSecurity::PeerName>::const_iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
{
peerNames.push_back(it->mName);
}
}
| Data TlsConnection::getPeerNamesData | ( | ) | const [private] |
Definition at line 549 of file TlsConnection.cxx.
References mPeerNames.
Referenced by checkState().
{
Data peerNamesString;
for(std::list<BaseSecurity::PeerName>::const_iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
{
if(it == mPeerNames.begin())
{
peerNamesString += it->mName;
}
else
{
peerNamesString += ", " + it->mName;
}
}
return peerNamesString;
}
| bool TlsConnection::hasDataToRead | ( | ) | [virtual] |
always true -- always add to fdset as read ready
Reimplemented from resip::Connection.
Definition at line 479 of file TlsConnection.cxx.
References checkState(), Initial, mSsl, mTlsState, and Up.
{
#if defined(USE_SSL)
//hack (for now)
if(mTlsState == Initial)
return false;
if (checkState() != Up)
{
return false;
}
int p = SSL_pending(mSsl);
//DebugLog(<<"hasDataToRead(): " <<p);
return (p>0);
#else // USE_SSL
return false;
#endif
}

| bool TlsConnection::isGood | ( | ) | [virtual] |
has valid connection
Reimplemented from resip::Connection.
Definition at line 501 of file TlsConnection.cxx.
Referenced by isWritable(), and read().
| bool TlsConnection::isWritable | ( | ) | [virtual] |
Reimplemented from resip::Connection.
Definition at line 520 of file TlsConnection.cxx.
References DebugLog, fromState(), Handshaking, Initial, isGood(), mHandShakeWantsRead, mTlsState, and Up.
{
#if defined(USE_SSL)
switch(mTlsState)
{
case Handshaking:
return mHandShakeWantsRead ? false : true;
case Initial:
case Up:
return isGood();
default:
return false;
}
//dragos -- to remove
DebugLog( << "Current state: " << fromState(mTlsState));
//end dragos
#endif
return false;
}

| int TlsConnection::read | ( | char * | , |
| const int | |||
| ) | [virtual] |
pure virtual, but need concrete Connection for book-ends of lists
Reimplemented from resip::Connection.
Definition at line 287 of file TlsConnection.cxx.
References resip::Data::Borrow, Broken, checkState(), DebugLog, ErrLog, resip::ConnectionBase::getWriteBufferForExtraBytes(), isGood(), mBio, mSsl, StackLog, and Up.
Referenced by main().
{
#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 > 0)?(bytesRead):(0)) << "]");
int bytesPending = SSL_pending(mSsl);
if ((bytesRead > 0) && (bytesPending > 0))
{
char* buffer = getWriteBufferForExtraBytes(bytesPending);
if (buffer)
{
StackLog(<< "reading remaining buffered bytes");
bytesPending = SSL_read(mSsl, buffer, bytesPending);
StackLog(<< "SSL_read returned " << bytesPending << " bytes [" << Data(Data::Borrow, buffer, (bytesPending > 0)?(bytesPending):(0)) << "]");
if (bytesPending > 0)
{
bytesRead += bytesPending;
}
else
{
bytesRead = bytesPending;
}
}
else
{
assert(0);
}
}
if (bytesRead <= 0)
{
int err = SSL_get_error(mSsl,bytesRead);
switch (err)
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_NONE:
{
StackLog( << "Got TLS read got condition of " << err );
return 0;
}
break;
default:
{
char buf[256];
ERR_error_string_n(err,buf,sizeof(buf));
ErrLog( << "Got TLS read ret=" << bytesRead << " error=" << err << " " << buf );
return -1;
}
break;
}
assert(0);
}
StackLog(<<"SSL bytesRead="<<bytesRead);
return bytesRead;
#endif // USE_SSL
return -1;
}

| resip::TlsConnection::RESIP_HeapCount | ( | TlsConnection | ) |
| bool TlsConnection::transportWrite | ( | ) | [virtual] |
Reimplemented from resip::Connection.
Definition at line 376 of file TlsConnection.cxx.
References Broken, checkState(), DebugLog, fromState(), Handshaking, Initial, mHandShakeWantsRead, mTlsState, and Up.
{
switch(mTlsState)
{
case Handshaking:
case Initial:
checkState();
if (mTlsState == Handshaking)
{
DebugLog(<< "Transportwrite--Handshaking--remove from write: " << mHandShakeWantsRead);
return mHandShakeWantsRead;
}
else
{
DebugLog(<< "Transportwrite--Handshake complete, in " << fromState(mTlsState) << " calling write");
return false;
}
case Up:
case Broken:
DebugLog(<< "Transportwrite--" << fromState(mTlsState) << " fall through to write");
return false;
}
assert(0);
return false;
}

| int TlsConnection::write | ( | const char * | , |
| const int | |||
| ) | [virtual] |
pure virtual, but need concrete Connection for book-ends of lists
Reimplemented from resip::Connection.
Definition at line 403 of file TlsConnection.cxx.
References resip::Data::Borrow, Broken, checkState(), DebugLog, ErrLog, mBio, mSsl, StackLog, and Up.
Referenced by main().
{
#if defined(USE_SSL)
assert( mSsl );
assert( buf );
int ret;
switch(checkState())
{
case Broken:
return -1;
break;
case Up:
break;
default:
DebugLog( << "Tried to Tls write - but connection is not Up" );
return 0;
break;
}
if (!mBio)
{
DebugLog( << "Got TLS write bad bio " );
return 0;
}
ret = SSL_write(mSsl,(const char*)buf,count);
if (ret < 0 )
{
int err = SSL_get_error(mSsl,ret);
switch (err)
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_NONE:
{
StackLog( << "Got TLS write got condition of " << err );
return 0;
}
break;
default:
{
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 );
DebugLog( << "Error code = " << code << " file=" << file << " line=" << line );
}
ErrLog( << "Got TLS write error=" << err << " ret=" << ret );
return -1;
}
break;
}
}
Data monkey(Data::Borrow, buf, count);
StackLog( << "Did TLS write " << ret << " " << count << " " << "[[" << monkey << "]]" );
return ret;
#endif // USE_SSL
return -1;
}

BIO* resip::TlsConnection::mBio [private] |
Definition at line 73 of file TlsConnection.hxx.
Referenced by checkState(), computePeerName(), isGood(), read(), TlsConnection(), and write().
Data resip::TlsConnection::mDomain [private] |
Definition at line 67 of file TlsConnection.hxx.
Referenced by TlsConnection().
bool resip::TlsConnection::mHandShakeWantsRead [private] |
Definition at line 70 of file TlsConnection.hxx.
Referenced by checkState(), isWritable(), TlsConnection(), and transportWrite().
std::list<BaseSecurity::PeerName> resip::TlsConnection::mPeerNames [private] |
Definition at line 74 of file TlsConnection.hxx.
Referenced by checkState(), computePeerName(), getPeerNames(), and getPeerNamesData().
Security* resip::TlsConnection::mSecurity [private] |
Definition at line 65 of file TlsConnection.hxx.
Referenced by computePeerName(), and TlsConnection().
bool resip::TlsConnection::mServer [private] |
Definition at line 64 of file TlsConnection.hxx.
Referenced by checkState(), computePeerName(), and TlsConnection().
SSL* resip::TlsConnection::mSsl [private] |
Definition at line 72 of file TlsConnection.hxx.
Referenced by checkState(), computePeerName(), hasDataToRead(), isGood(), read(), TlsConnection(), write(), and ~TlsConnection().
Definition at line 66 of file TlsConnection.hxx.
TlsState resip::TlsConnection::mTlsState [private] |
Definition at line 69 of file TlsConnection.hxx.
Referenced by checkState(), hasDataToRead(), isWritable(), TlsConnection(), and transportWrite().
1.7.5.1