00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "tlsopensslbase.h"
00016
00017 #ifdef HAVE_OPENSSL
00018
00019 #include <algorithm>
00020 #include <cctype>
00021 #include <ctime>
00022 #include <cstdlib>
00023
00024 #include <openssl/err.h>
00025
00026 namespace gloox
00027 {
00028
00029 OpenSSLBase::OpenSSLBase( TLSHandler* th, const std::string& server )
00030 : TLSBase( th, server ), m_ssl( 0 ), m_ctx( 0 ), m_buf( 0 ), m_bufsize( 17000 )
00031 {
00032 m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
00033 }
00034
00035 OpenSSLBase::~OpenSSLBase()
00036 {
00037 m_handler = 0;
00038 free( m_buf );
00039 SSL_CTX_free( m_ctx );
00040 SSL_shutdown( m_ssl );
00041 SSL_free( m_ssl );
00042 BIO_free( m_nbio );
00043 cleanup();
00044 }
00045
00046 bool OpenSSLBase::init( const std::string& clientKey,
00047 const std::string& clientCerts,
00048 const StringList& cacerts )
00049 {
00050 if( m_initLib )
00051 SSL_library_init();
00052
00053 SSL_COMP_add_compression_method( 193, COMP_zlib() );
00054
00055 OpenSSL_add_all_algorithms();
00056
00057 if( !setType() )
00058 return false;
00059
00060 setClientCert( clientKey, clientCerts );
00061 setCACerts( cacerts );
00062
00063 if( !SSL_CTX_set_cipher_list( m_ctx, "HIGH:MEDIUM:AES:@STRENGTH" ) )
00064 return false;
00065
00066 m_ssl = SSL_new( m_ctx );
00067 if( !m_ssl )
00068 return false;
00069
00070 if( !BIO_new_bio_pair( &m_ibio, 0, &m_nbio, 0 ) )
00071 return false;
00072
00073 SSL_set_bio( m_ssl, m_ibio, m_ibio );
00074 SSL_set_mode( m_ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE );
00075
00076 ERR_load_crypto_strings();
00077 SSL_load_error_strings();
00078
00079 if( !privateInit() )
00080 return false;
00081
00082 m_valid = true;
00083 return true;
00084 }
00085
00086 bool OpenSSLBase::encrypt( const std::string& data )
00087 {
00088 m_sendBuffer += data;
00089
00090 if( !m_secure )
00091 {
00092 handshake();
00093 return 0;
00094 }
00095
00096 doTLSOperation( TLSWrite );
00097 return true;
00098 }
00099
00100 int OpenSSLBase::decrypt( const std::string& data )
00101 {
00102 m_recvBuffer += data;
00103
00104 if( !m_secure )
00105 {
00106 handshake();
00107 return 0;
00108 }
00109
00110 doTLSOperation( TLSRead );
00111 return true;
00112 }
00113
00114 void OpenSSLBase::setCACerts( const StringList& cacerts )
00115 {
00116 m_cacerts = cacerts;
00117
00118 StringList::const_iterator it = m_cacerts.begin();
00119 for( ; it != m_cacerts.end(); ++it )
00120 SSL_CTX_load_verify_locations( m_ctx, (*it).c_str(), 0 );
00121 }
00122
00123 void OpenSSLBase::setClientCert( const std::string& clientKey, const std::string& clientCerts )
00124 {
00125 m_clientKey = clientKey;
00126 m_clientCerts = clientCerts;
00127
00128 if( !m_clientKey.empty() && !m_clientCerts.empty() )
00129 {
00130 if( SSL_CTX_use_certificate_chain_file( m_ctx, m_clientCerts.c_str() ) != 1 )
00131 {
00132
00133 }
00134 if( SSL_CTX_use_RSAPrivateKey_file( m_ctx, m_clientKey.c_str(), SSL_FILETYPE_PEM ) != 1 )
00135 {
00136
00137 }
00138 }
00139
00140 if ( SSL_CTX_check_private_key( m_ctx ) != 1 )
00141 {
00142
00143 }
00144 }
00145
00146 void OpenSSLBase::cleanup()
00147 {
00148 if( !m_mutex.trylock() )
00149 return;
00150
00151 m_secure = false;
00152 m_valid = false;
00153
00154 m_mutex.unlock();
00155 }
00156
00157 void OpenSSLBase::doTLSOperation( TLSOperation op )
00158 {
00159 if( !m_handler )
00160 return;
00161
00162 int ret = 0;
00163 bool onceAgain = false;
00164
00165 do
00166 {
00167 switch( op )
00168 {
00169 case TLSHandshake:
00170 ret = handshakeFunction();
00171 break;
00172 case TLSWrite:
00173 ret = SSL_write( m_ssl, m_sendBuffer.c_str(), m_sendBuffer.length() );
00174 break;
00175 case TLSRead:
00176 ret = SSL_read( m_ssl, m_buf, m_bufsize );
00177 break;
00178 }
00179
00180 switch( SSL_get_error( m_ssl, ret ) )
00181 {
00182 case SSL_ERROR_WANT_READ:
00183 case SSL_ERROR_WANT_WRITE:
00184 pushFunc();
00185 break;
00186 case SSL_ERROR_NONE:
00187 if( op == TLSHandshake )
00188 m_secure = true;
00189 else if( op == TLSWrite )
00190 m_sendBuffer.erase( 0, ret );
00191 else if( op == TLSRead )
00192 m_handler->handleDecryptedData( this, std::string( m_buf, ret ) );
00193 pushFunc();
00194 break;
00195 default:
00196 if( !m_secure )
00197 m_handler->handleHandshakeResult( this, false, m_certInfo );
00198 return;
00199 break;
00200 }
00201 if( !onceAgain && !m_recvBuffer.length() )
00202 onceAgain = true;
00203 else if( onceAgain )
00204 onceAgain = false;
00205 }
00206 while( ( ( onceAgain || m_recvBuffer.length() ) && ( !m_secure || op == TLSRead ) )
00207 || ( ( op == TLSWrite ) && ( ret > 0 ) ));
00208 }
00209
00210 int OpenSSLBase::openSSLTime2UnixTime( const char* time_string )
00211 {
00212 char tstring[19];
00213
00214
00215 int m = 0;
00216 for( int n = 0; n < 12; n += 2 )
00217 {
00218 tstring[m] = time_string[n];
00219 tstring[m + 1] = time_string[n + 1];
00220 tstring[m + 2] = 0;
00221 m += 3;
00222 }
00223
00224
00225 tm time_st;
00226 time_st.tm_year = ( atoi( &tstring[3 * 0] ) >= 70 ) ? atoi( &tstring[3 * 0] )
00227 : atoi( &tstring[3 * 0] ) + 100;
00228 time_st.tm_mon = atoi( &tstring[3 * 1] ) - 1;
00229 time_st.tm_mday = atoi( &tstring[3 * 2] );
00230 time_st.tm_hour = atoi( &tstring[3 * 3] );
00231 time_st.tm_min = atoi( &tstring[3 * 4] );
00232 time_st.tm_sec = atoi( &tstring[3 * 5] );
00233
00234 time_t unixt = mktime( &time_st );
00235 return unixt;
00236 }
00237
00238 bool OpenSSLBase::handshake()
00239 {
00240
00241 doTLSOperation( TLSHandshake );
00242
00243 if( !m_secure )
00244 return true;
00245
00246 int res = SSL_get_verify_result( m_ssl );
00247 if( res != X509_V_OK )
00248 m_certInfo.status = CertInvalid;
00249 else
00250 m_certInfo.status = CertOk;
00251
00252 X509* peer = SSL_get_peer_certificate( m_ssl );
00253 if( peer )
00254 {
00255 char peer_CN[256];
00256 X509_NAME_get_text_by_NID( X509_get_issuer_name( peer ), NID_commonName, peer_CN, sizeof( peer_CN ) );
00257 m_certInfo.issuer = peer_CN;
00258 X509_NAME_get_text_by_NID( X509_get_subject_name( peer ), NID_commonName, peer_CN, sizeof( peer_CN ) );
00259 m_certInfo.server = peer_CN;
00260 m_certInfo.date_from = openSSLTime2UnixTime( (char*) (peer->cert_info->validity->notBefore->data) );
00261 m_certInfo.date_to = openSSLTime2UnixTime( (char*) (peer->cert_info->validity->notAfter->data) );
00262 std::string p( peer_CN );
00263 std::transform( p.begin(), p.end(), p.begin(), tolower );
00264 if( p != m_server )
00265 m_certInfo.status |= CertWrongPeer;
00266
00267 if( ASN1_UTCTIME_cmp_time_t( X509_get_notBefore( peer ), time( 0 ) ) != -1 )
00268 m_certInfo.status |= CertNotActive;
00269
00270 if( ASN1_UTCTIME_cmp_time_t( X509_get_notAfter( peer ), time( 0 ) ) != 1 )
00271 m_certInfo.status |= CertExpired;
00272 }
00273 else
00274 {
00275 m_certInfo.status = CertInvalid;
00276 }
00277
00278 const char* tmp;
00279 tmp = SSL_get_cipher_name( m_ssl );
00280 if( tmp )
00281 m_certInfo.cipher = tmp;
00282
00283 tmp = SSL_get_cipher_version( m_ssl );
00284 if( tmp )
00285 m_certInfo.protocol = tmp;
00286
00287 tmp = SSL_COMP_get_name( SSL_get_current_compression( m_ssl ) );
00288 if( tmp )
00289 m_certInfo.compression = tmp;
00290
00291 m_valid = true;
00292
00293 m_handler->handleHandshakeResult( this, true, m_certInfo );
00294 return true;
00295 }
00296
00297 void OpenSSLBase::pushFunc()
00298 {
00299 int wantwrite;
00300 size_t wantread;
00301 int frombio;
00302 int tobio;
00303
00304 while( ( wantwrite = BIO_ctrl_pending( m_nbio ) ) > 0 )
00305 {
00306 if( wantwrite > m_bufsize )
00307 wantwrite = m_bufsize;
00308
00309 if( !wantwrite )
00310 break;
00311
00312 frombio = BIO_read( m_nbio, m_buf, wantwrite );
00313
00314 if( m_handler )
00315 m_handler->handleEncryptedData( this, std::string( m_buf, frombio ) );
00316 }
00317
00318 while( ( wantread = BIO_ctrl_get_read_request( m_nbio ) ) > 0 )
00319 {
00320 if( wantread > m_recvBuffer.length() )
00321 wantread = m_recvBuffer.length();
00322
00323 if( !wantread )
00324 break;
00325
00326 tobio = BIO_write( m_nbio, m_recvBuffer.c_str(), wantread );
00327 m_recvBuffer.erase( 0, tobio );
00328 }
00329 }
00330
00331 }
00332
00333 #endif // HAVE_OPENSSL