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 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 , 0 );
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