{
#endif /* _NO_CSOCKET_NS */
-static int g_iCsockSSLIdx = 0; //!< this get setup once in InitSSL
-int GetCsockClassIdx()
+static int s_iCsockSSLIdx = 0; //!< this gets setup once in InitSSL
+int GetCsockSSLIdx()
{
- return( g_iCsockSSLIdx );
+ return( s_iCsockSSLIdx );
}
#ifdef _WIN32
static int _CertVerifyCB( int preverify_ok, X509_STORE_CTX *x509_ctx )
{
- /*
- * A small quick example on how to get ahold of the Csock in the data portion of x509_ctx
Csock * pSock = GetCsockFromCTX( x509_ctx );
- assert( pSock );
- cerr << pSock->GetRemoteIP() << endl;
- */
+ if( pSock )
+ return( pSock->VerifyPeerCertificate( preverify_ok, x509_ctx ) );
- /*
- * as it stands, this is just not doing any verification. To let SSL validate the certificates
- * set the callback to NULL (Csock::SetCertVerifyCB()), otherwise you can do additional checking here.
- */
- return( 1 );
+ return( preverify_ok );
+}
+
+static void _InfoCallback( const SSL * pSSL, int where, int ret )
+{
+ if( ( where & SSL_CB_HANDSHAKE_DONE ) && ret != 0 )
+ {
+ Csock * pSock = static_cast<Csock *>( SSL_get_ex_data( pSSL, GetCsockSSLIdx() ) );
+ if( pSock )
+ pSock->SSLHandShakeFinished();
+ }
}
Csock * pSock = NULL;
SSL * pSSL = ( SSL * ) X509_STORE_CTX_get_ex_data( pCTX, SSL_get_ex_data_X509_STORE_CTX_idx() );
if( pSSL )
- pSock = ( Csock * ) SSL_get_ex_data( pSSL, GetCsockClassIdx() );
+ pSock = ( Csock * ) SSL_get_ex_data( pSSL, GetCsockSSLIdx() );
return( pSock );
}
#endif /* HAVE_LIBSSL */
}
// setting this up once in the begining
- g_iCsockSSLIdx = SSL_get_ex_new_index( 0, ( void * )"CsockGlobalIndex", NULL, NULL, NULL );
+ s_iCsockSSLIdx = SSL_get_ex_new_index( 0, NULL, NULL, NULL, NULL );
return( true );
}
SSL_set_rfd( m_ssl, ( int )m_iReadSock );
SSL_set_wfd( m_ssl, ( int )m_iWriteSock );
SSL_set_verify( m_ssl, SSL_VERIFY_PEER, m_pCerVerifyCB );
- SSL_set_ex_data( m_ssl, GetCsockClassIdx(), this );
+ SSL_set_info_callback( m_ssl, _InfoCallback );
+ SSL_set_ex_data( m_ssl, GetCsockSSLIdx(), this );
#if defined( SSL_set_tlsext_host_name )
CS_STRING sSNIHostname;
if( m_iRequireClientCertFlags )
{
SSL_set_verify( m_ssl, m_iRequireClientCertFlags, m_pCerVerifyCB );
- SSL_set_ex_data( m_ssl, GetCsockClassIdx(), this );
}
+ SSL_set_info_callback( m_ssl, _InfoCallback );
+ SSL_set_ex_data( m_ssl, GetCsockSSLIdx(), this );
SSLFinishSetup( m_ssl );
return( true );
switch( bytes )
{
- case Csock::READ_EOF:
- {
- DelSockByAddr( pcSock );
- break;
- }
+ case Csock::READ_EOF:
+ {
+ DelSockByAddr( pcSock );
+ break;
+ }
- case Csock::READ_ERR:
- {
- bool bHandled = false;
-#ifdef HAVE_LIBSSL
- if( pcSock->GetSSL() )
+ case Csock::READ_ERR:
{
- unsigned long iSSLError = ERR_peek_error();
- if( iSSLError )
+ bool bHandled = false;
+#ifdef HAVE_LIBSSL
+ if( pcSock->GetSSL() )
{
- char szError[512];
- memset( ( char * ) szError, '\0', 512 );
- ERR_error_string_n( iSSLError, szError, 511 );
- SSLErrors( __FILE__, __LINE__ );
- pcSock->CallSockError( GetSockError(), szError );
- bHandled = true;
+ unsigned long iSSLError = ERR_peek_error();
+ if( iSSLError )
+ {
+ char szError[512];
+ memset( ( char * ) szError, '\0', 512 );
+ ERR_error_string_n( iSSLError, szError, 511 );
+ SSLErrors( __FILE__, __LINE__ );
+ pcSock->CallSockError( GetSockError(), szError );
+ bHandled = true;
+ }
}
- }
#endif
- if( !bHandled )
- pcSock->CallSockError( GetSockError() );
- DelSockByAddr( pcSock );
- break;
- }
+ if( !bHandled )
+ pcSock->CallSockError( GetSockError() );
+ DelSockByAddr( pcSock );
+ break;
+ }
- case Csock::READ_EAGAIN:
- break;
+ case Csock::READ_EAGAIN:
+ break;
- case Csock::READ_CONNREFUSED:
- pcSock->ConnectionRefused();
- DelSockByAddr( pcSock );
- break;
+ case Csock::READ_CONNREFUSED:
+ pcSock->ConnectionRefused();
+ DelSockByAddr( pcSock );
+ break;
- case Csock::READ_TIMEDOUT:
- pcSock->Timeout();
- DelSockByAddr( pcSock );
- break;
+ case Csock::READ_TIMEDOUT:
+ pcSock->Timeout();
+ DelSockByAddr( pcSock );
+ break;
- default:
- {
- if( Csock::TMO_READ & pcSock->GetTimeoutType() )
- pcSock->ResetTimer(); // reset the timeout timer
+ default:
+ {
+ if( Csock::TMO_READ & pcSock->GetTimeoutType() )
+ pcSock->ResetTimer(); // reset the timeout timer
- pcSock->ReadData( cBuff(), bytes ); // Call ReadData() before PushBuff() so that it is called before the ReadLine() event - LD 07/18/05
- pcSock->PushBuff( cBuff(), bytes );
- break;
- }
+ pcSock->ReadData( cBuff(), bytes ); // Call ReadData() before PushBuff() so that it is called before the ReadLine() event - LD 07/18/05
+ pcSock->PushBuff( cBuff(), bytes );
+ break;
+ }
}
}
else if( iErrno == SELECT_ERROR )
//! backwards compatible wrapper around CGetAddrInfo and gethostbyname
int GetAddrInfo( const CS_STRING & sHostname, Csock * pSock, CSSockAddr & csSockAddr );
-//! used to retrieve the context position of the socket to its associated ssl connection. Setup once in InitSSL() via SSL_get_ex_new_index
-int GetCsockClassIdx();
+/**
+ * This returns the [ex_]data index position for SSL objects only. If you want to tie more data
+ * to the SSL object, you should generate your own at application start so as to avoid collision
+ * with Csocket SSL_set_ex_data()
+ */
+int GetCsockSSLIdx();
#ifdef HAVE_LIBSSL
//! returns the sock object associated to the particular context. returns NULL on failure or if not available
//! Get the peer's X509 cert
#ifdef HAVE_LIBSSL
+ //! it is up to you, the caller to call X509_free() on this object
X509 *GetX509() const;
//! Returns the peer's public key
virtual bool SNIConfigureClient( CS_STRING & sHostname ) { return( false ); }
//! creates a new SSL_CTX based on the setup of this sock
SSL_CTX * SetupServerCTX();
+
+ /**
+ * @brief called once the SSL handshake is complete, this is triggered via SSL_CB_HANDSHAKE_DONE in SSL_set_info_callback()
+ *
+ * This is a spot where you can look at the finished peer certifificate ... IE
+ * <pre>
+ * X509 * pCert = GetX509();
+ * char szName[256];
+ * memset( szName, '\0', 256 );
+ * X509_NAME_get_text_by_NID ( X509_get_subject_name( pCert ), NID_commonName, szName, 255 );
+ * cerr << "Name! " << szName << endl;
+ * X509_free( pCert );
+ * </pre>
+ */
+ virtual void SSLHandShakeFinished() {}
+ /**
+ * @brief this is hooked in via SSL_set_verify, and be default it just returns 1 meaning success
+ * @param iPreVerify the pre-verification status as determined by openssl internally
+ * @param pStoreCTX the X509_STORE_CTX containing the certificate
+ * @return 1 to continue, 0 to abort
+ *
+ * This may get called multiple times, for example with a chain certificate which is fairly typical with
+ * certificates from godaddy, freessl, etc. Additionally, openssl does not do any host verification, they
+ * leave that up to the you. One easy way to deal with this is to wait for SSLHandShakeFinished() and examine
+ * the peer certificate @see SSLHandShakeFinished
+ */
+ virtual int VerifyPeerCertificate( int iPreVerify, X509_STORE_CTX * pStoreCTX ) { return( 1 ); }
#endif /* HAVE_LIBSSL */