gloox
1.0
|
00001 /* 00002 Copyright (c) 2005-2009 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 } 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 /*CAList*/, 0 /*CAListSize*/ ); 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