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