00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "tlsopenssl.h"
00016
00017 #ifdef HAVE_OPENSSL
00018
00019 #include <algorithm>
00020 #include <cctype>
00021
00022 namespace gloox
00023 {
00024
00025 OpenSSL::OpenSSL( TLSHandler *th, const std::string& server )
00026 : TLSBase( th, server ), m_ssl( 0 ), m_ctx( 0 ), m_buf( 0 ), m_bufsize( 17000 )
00027 {
00028 m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
00029
00030 SSL_library_init();
00031
00032 SSL_COMP_add_compression_method( 1, COMP_zlib() );
00033
00034 m_ctx = SSL_CTX_new( TLSv1_client_method() );
00035 if( !m_ctx )
00036 return;
00037
00038 if( !SSL_CTX_set_cipher_list( m_ctx, "HIGH:MEDIUM:AES:@STRENGTH" ) )
00039 return;
00040
00041 m_ssl = SSL_new( m_ctx );
00042 SSL_set_connect_state( m_ssl );
00043
00044 if( !BIO_new_bio_pair( &m_ibio, 0, &m_nbio, 0 ) )
00045 {
00046 return;
00047 }
00048 SSL_set_bio( m_ssl, m_ibio, m_ibio );
00049 SSL_set_mode( m_ssl, SSL_MODE_AUTO_RETRY );
00050 }
00051
00052 OpenSSL::~OpenSSL()
00053 {
00054 m_handler = 0;
00055 free( m_buf );
00056 SSL_CTX_free( m_ctx );
00057 SSL_shutdown( m_ssl );
00058 SSL_free( m_ssl );
00059 BIO_free( m_nbio );
00060 cleanup();
00061 }
00062
00063 bool OpenSSL::encrypt( const std::string& data )
00064 {
00065 m_sendBuffer += data;
00066
00067 if( !m_secure )
00068 {
00069 handshake();
00070 return 0;
00071 }
00072
00073 doTLSOperation( TLSWrite );
00074 return true;
00075 }
00076
00077 int OpenSSL::decrypt( const std::string& data )
00078 {
00079 m_recvBuffer += data;
00080
00081 if( !m_secure )
00082 {
00083 handshake();
00084 return 0;
00085 }
00086
00087 doTLSOperation( TLSRead );
00088 return true;
00089 }
00090
00091 void OpenSSL::setCACerts( const StringList& cacerts )
00092 {
00093 m_cacerts = cacerts;
00094
00095 StringList::const_iterator it = m_cacerts.begin();
00096 for( ; it != m_cacerts.end(); ++it )
00097 SSL_CTX_load_verify_locations( m_ctx, (*it).c_str(), 0 );
00098 }
00099
00100 void OpenSSL::setClientCert( const std::string& clientKey, const std::string& clientCerts )
00101 {
00102 m_clientKey = clientKey;
00103 m_clientCerts = clientCerts;
00104
00105 if( !m_clientKey.empty() && !m_clientCerts.empty() )
00106 {
00107 SSL_CTX_use_certificate_chain_file( m_ctx, m_clientCerts.c_str() );
00108 SSL_CTX_use_PrivateKey_file( m_ctx, m_clientKey.c_str(), SSL_FILETYPE_PEM );
00109 }
00110 }
00111
00112 void OpenSSL::cleanup()
00113 {
00114 m_secure = false;
00115 m_valid = false;
00116 }
00117
00118 void OpenSSL::doTLSOperation( TLSOperation op )
00119 {
00120 if( !m_handler )
00121 return;
00122
00123 int ret = 0;
00124 bool onceAgain = false;
00125
00126 do
00127 {
00128 switch( op )
00129 {
00130 case TLSHandshake:
00131 ret = SSL_connect( m_ssl );
00132 break;
00133 case TLSWrite:
00134 ret = SSL_write( m_ssl, m_sendBuffer.c_str(), m_sendBuffer.length() );
00135 break;
00136 case TLSRead:
00137 ret = SSL_read( m_ssl, m_buf, m_bufsize );
00138 break;
00139 }
00140
00141 switch( SSL_get_error( m_ssl, ret ) )
00142 {
00143 case SSL_ERROR_WANT_READ:
00144 case SSL_ERROR_WANT_WRITE:
00145 pushFunc();
00146 break;
00147 case SSL_ERROR_NONE:
00148 if( op == TLSHandshake )
00149 m_secure = true;
00150 else if( op == TLSWrite )
00151 m_sendBuffer.erase( 0, ret );
00152 else if( op == TLSRead )
00153 m_handler->handleDecryptedData( this, std::string( m_buf, ret ) );
00154 pushFunc();
00155 break;
00156 default:
00157 if( !m_secure )
00158 m_handler->handleHandshakeResult( this, false, m_certInfo );
00159 return;
00160 break;
00161 }
00162 if( !onceAgain && !m_recvBuffer.length() )
00163 onceAgain = true;
00164 else if( onceAgain )
00165 onceAgain = false;
00166 }
00167 while( ( onceAgain || m_recvBuffer.length() ) && ( !m_secure || op == TLSRead ) );
00168 }
00169
00170 bool OpenSSL::handshake()
00171 {
00172
00173 doTLSOperation( TLSHandshake );
00174
00175 if( !m_secure )
00176 return true;
00177
00178 int res = SSL_get_verify_result( m_ssl );
00179 if( res != X509_V_OK )
00180 m_certInfo.status = CertInvalid;
00181 else
00182 m_certInfo.status = CertOk;
00183
00184 X509 *peer = SSL_get_peer_certificate( m_ssl );
00185 if( peer )
00186 {
00187 char peer_CN[256];
00188 X509_NAME_get_text_by_NID( X509_get_issuer_name( peer ), NID_commonName, peer_CN, sizeof( peer_CN ) );
00189 m_certInfo.issuer = peer_CN;
00190 X509_NAME_get_text_by_NID( X509_get_subject_name( peer ), NID_commonName, peer_CN, sizeof( peer_CN ) );
00191 m_certInfo.server = peer_CN;
00192 std::string p;
00193 p.assign( peer_CN );
00194 std::transform( p.begin(), p.end(), p.begin(), std::tolower );
00195 if( p != m_server )
00196 m_certInfo.status |= CertWrongPeer;
00197
00198 if( ASN1_UTCTIME_cmp_time_t( X509_get_notBefore( peer ), time( 0 ) ) != -1 )
00199 m_certInfo.status |= CertNotActive;
00200
00201 if( ASN1_UTCTIME_cmp_time_t( X509_get_notAfter( peer ), time( 0 ) ) != 1 )
00202 m_certInfo.status |= CertExpired;
00203 }
00204 else
00205 {
00206 m_certInfo.status = CertInvalid;
00207 }
00208
00209 const char *tmp;
00210 tmp = SSL_get_cipher_name( m_ssl );
00211 if( tmp )
00212 m_certInfo.cipher = tmp;
00213
00214 tmp = SSL_get_cipher_version( m_ssl );
00215 if( tmp )
00216 m_certInfo.protocol = tmp;
00217
00218 m_valid = true;
00219
00220 m_handler->handleHandshakeResult( this, true, m_certInfo );
00221 return true;
00222 }
00223
00224 void OpenSSL::pushFunc()
00225 {
00226 int wantwrite;
00227 size_t wantread;
00228 int frombio;
00229 int tobio;
00230
00231 while( ( wantwrite = BIO_ctrl_pending( m_nbio ) ) > 0 )
00232 {
00233 if( wantwrite > m_bufsize )
00234 wantwrite = m_bufsize;
00235
00236 if( !wantwrite )
00237 break;
00238
00239 frombio = BIO_read( m_nbio, m_buf, wantwrite );
00240
00241 if( m_handler )
00242 m_handler->handleEncryptedData( this, std::string( m_buf, frombio ) );
00243 }
00244
00245 while( ( wantread = BIO_ctrl_get_read_request( m_nbio ) ) > 0 )
00246 {
00247 if( wantread > m_recvBuffer.length() )
00248 wantread = m_recvBuffer.length();
00249
00250 if( !wantread )
00251 break;
00252
00253 tobio = BIO_write( m_nbio, m_recvBuffer.c_str(), wantread );
00254 m_recvBuffer.erase( 0, tobio );
00255 }
00256 }
00257
00258 }
00259
00260 #endif // HAVE_OPENSSL