tlsgnutlsclient.cpp

00001 /*
00002   Copyright (c) 2005-2008 by Jakob Schroeter <js@camaya.net>
00003   This file is part of the gloox library. http://camaya.net/gloox
00004 
00005   This software is distributed under a license. The full license
00006   agreement can be found in the file LICENSE in this distribution.
00007   This software may not be copied, modified, sold or distributed
00008   other than expressed in the named license agreement.
00009 
00010   This software is distributed without any warranty.
00011 */
00012 
00013 
00014 
00015 #include "tlsgnutlsclient.h"
00016 
00017 #ifdef HAVE_GNUTLS
00018 
00019 #include <errno.h>
00020 
00021 namespace gloox
00022 {
00023 
00024   GnuTLSClient::GnuTLSClient( TLSHandler *th, const std::string& server )
00025     : GnuTLSBase( th, server )
00026   {
00027     init();
00028   }
00029 
00030   GnuTLSClient::~GnuTLSClient()
00031   {
00032   }
00033 
00034   void GnuTLSClient::cleanup()
00035   {
00036     GnuTLSBase::cleanup();
00037     init();
00038   }
00039 
00040   void GnuTLSClient::init()
00041   {
00042     const int protocolPriority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
00043     const int kxPriority[]       = { GNUTLS_KX_RSA, 0 };
00044     const int cipherPriority[]   = { GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_128_CBC,
00045                                      GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0 };
00046     const int compPriority[]     = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
00047     const int macPriority[]      = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
00048 
00049     if( gnutls_global_init() != 0 )
00050     {
00051       m_valid = false;
00052       return;
00053     }
00054 
00055     if( gnutls_certificate_allocate_credentials( &m_credentials ) < 0 )
00056     {
00057       m_valid = false;
00058       return;
00059     }
00060 
00061     if( gnutls_init( m_session, GNUTLS_CLIENT ) != 0 )
00062     {
00063       gnutls_certificate_free_credentials( m_credentials );
00064       m_valid = false;
00065       return;
00066     }
00067 
00068     gnutls_protocol_set_priority( *m_session, protocolPriority );
00069     gnutls_cipher_set_priority( *m_session, cipherPriority );
00070     gnutls_compression_set_priority( *m_session, compPriority );
00071     gnutls_kx_set_priority( *m_session, kxPriority );
00072     gnutls_mac_set_priority( *m_session, macPriority );
00073     gnutls_credentials_set( *m_session, GNUTLS_CRD_CERTIFICATE, m_credentials );
00074 
00075     gnutls_transport_set_ptr( *m_session, (gnutls_transport_ptr_t)this );
00076     gnutls_transport_set_push_function( *m_session, pushFunc );
00077     gnutls_transport_set_pull_function( *m_session, pullFunc );
00078   }
00079 
00080   void GnuTLSClient::setCACerts( const StringList& cacerts )
00081   {
00082     m_cacerts = cacerts;
00083 
00084     StringList::const_iterator it = m_cacerts.begin();
00085     for( ; it != m_cacerts.end(); ++it )
00086       gnutls_certificate_set_x509_trust_file( m_credentials, (*it).c_str(), GNUTLS_X509_FMT_PEM );
00087   }
00088 
00089   void GnuTLSClient::setClientCert( const std::string& clientKey, const std::string& clientCerts )
00090   {
00091     m_clientKey = clientKey;
00092     m_clientCerts = clientCerts;
00093 
00094     if( !m_clientKey.empty() && !m_clientCerts.empty() )
00095     {
00096       gnutls_certificate_set_x509_key_file( m_credentials, m_clientKey.c_str(),
00097                                             m_clientCerts.c_str(), GNUTLS_X509_FMT_PEM );
00098     }
00099   }
00100 
00101   void GnuTLSClient::getCertInfo()
00102   {
00103     unsigned int status;
00104     bool error = false;
00105 
00106     gnutls_certificate_free_ca_names( m_credentials );
00107 
00108     if( gnutls_certificate_verify_peers2( *m_session, &status ) < 0 )
00109       error = true;
00110 
00111     m_certInfo.status = 0;
00112     if( status & GNUTLS_CERT_INVALID )
00113       m_certInfo.status |= CertInvalid;
00114     if( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
00115       m_certInfo.status |= CertSignerUnknown;
00116     if( status & GNUTLS_CERT_REVOKED )
00117       m_certInfo.status |= CertRevoked;
00118     if( status & GNUTLS_CERT_SIGNER_NOT_CA )
00119       m_certInfo.status |= CertSignerNotCa;
00120     const gnutls_datum_t* certList = 0;
00121     unsigned int certListSize;
00122     if( !error && ( ( certList = gnutls_certificate_get_peers( *m_session, &certListSize ) ) == 0 ) )
00123       error = true;
00124 
00125     gnutls_x509_crt_t *cert = new gnutls_x509_crt_t[certListSize+1];
00126     for( unsigned int i=0; !error && ( i<certListSize ); ++i )
00127     {
00128       if( !error && ( gnutls_x509_crt_init( &cert[i] ) < 0 
00129                    || gnutls_x509_crt_import( cert[i], &certList[i], GNUTLS_X509_FMT_DER ) < 0 ) )
00130           error = true;
00131     }
00132 
00133     if( ( gnutls_x509_crt_check_issuer( cert[certListSize-1], cert[certListSize-1] ) > 0 )
00134          && certListSize > 0 )
00135       certListSize--;
00136 
00137     bool chain = true;
00138     for( unsigned int i=1; !error && ( i<certListSize ); ++i )
00139     {
00140       chain = error = !verifyAgainst( cert[i-1], cert[i] );
00141     }
00142     if( !chain )
00143       m_certInfo.status |= CertInvalid;
00144     m_certInfo.chain = chain;
00145 
00146     m_certInfo.chain = verifyAgainstCAs( cert[certListSize], 0 /*CAList*/, 0 /*CAListSize*/ );
00147 
00148     int t = (int)gnutls_x509_crt_get_activation_time( cert[0] );
00149     if( t == -1 )
00150       error = true;
00151     else if( t > time( 0 ) )
00152       m_certInfo.status |= CertNotActive;
00153     m_certInfo.date_from = t;
00154 
00155     t = (int)gnutls_x509_crt_get_expiration_time( cert[0] );
00156     if( t == -1 )
00157       error = true;
00158     else if( t < time( 0 ) )
00159       m_certInfo.status |= CertExpired;
00160     m_certInfo.date_to = t;
00161 
00162     char name[64];
00163     size_t nameSize = sizeof( name );
00164     gnutls_x509_crt_get_issuer_dn( cert[0], name, &nameSize );
00165     m_certInfo.issuer = name;
00166 
00167     nameSize = sizeof( name );
00168     gnutls_x509_crt_get_dn( cert[0], name, &nameSize );
00169     m_certInfo.server = name;
00170 
00171     const char* info;
00172     info = gnutls_compression_get_name( gnutls_compression_get( *m_session ) );
00173     if( info )
00174       m_certInfo.compression = info;
00175 
00176     info = gnutls_mac_get_name( gnutls_mac_get( *m_session ) );
00177     if( info )
00178       m_certInfo.mac = info;
00179 
00180     info = gnutls_cipher_get_name( gnutls_cipher_get( *m_session ) );
00181     if( info )
00182       m_certInfo.cipher = info;
00183 
00184     info = gnutls_protocol_get_name( gnutls_protocol_get_version( *m_session ) );
00185     if( info )
00186       m_certInfo.protocol = info;
00187 
00188     if( !gnutls_x509_crt_check_hostname( cert[0], m_server.c_str() ) )
00189       m_certInfo.status |= CertWrongPeer;
00190 
00191     for( unsigned int i=0; i<certListSize; ++i )
00192       gnutls_x509_crt_deinit( cert[i] );
00193 
00194     delete[] cert;
00195 
00196     m_valid = true;
00197   }
00198 
00199   static bool verifyCert( gnutls_x509_crt_t cert, unsigned result )
00200   {
00201     return ! ( ( result & GNUTLS_CERT_INVALID )
00202       || gnutls_x509_crt_get_expiration_time( cert ) < time( 0 )
00203       || gnutls_x509_crt_get_activation_time( cert ) > time( 0 ) );
00204   }
00205 
00206   bool GnuTLSClient::verifyAgainst( gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer )
00207   {
00208     unsigned int result;
00209     gnutls_x509_crt_verify( cert, &issuer, 1, 0, &result );
00210     return verifyCert( cert, result );
00211   }
00212 
00213   bool GnuTLSClient::verifyAgainstCAs( gnutls_x509_crt_t cert, gnutls_x509_crt_t *CAList, int CAListSize )
00214   {
00215     unsigned int result;
00216     gnutls_x509_crt_verify( cert, CAList, CAListSize, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &result );
00217     return verifyCert( cert, result );
00218   }
00219 
00220 }
00221 
00222 #endif // HAVE_GNUTLS

Generated on Mon Dec 7 13:28:19 2009 for gloox by  doxygen 1.6.1