gloox  1.0.20
tlsgnutlsclient.cpp
1 /*
2  Copyright (c) 2005-2017 by Jakob Schröter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 
14 
15 #include "tlsgnutlsclient.h"
16 
17 #ifdef HAVE_GNUTLS
18 
19 #include <errno.h>
20 
21 namespace gloox
22 {
23 
24  GnuTLSClient::GnuTLSClient( TLSHandler* th, const std::string& server )
25  : GnuTLSBase( th, server )
26  {
27  }
28 
30  {
31  }
32 
34  {
36  if( m_credentials )
37  gnutls_certificate_free_credentials( m_credentials );
38  init();
39  }
40 
41  bool GnuTLSClient::init( const std::string& /*clientKey*/,
42  const std::string& /*clientCerts*/,
43  const StringList& /*cacerts*/ )
44  {
45  if( m_initLib && gnutls_global_init() != 0 )
46  return false;
47 
48  if( gnutls_certificate_allocate_credentials( &m_credentials ) < 0 )
49  return false;
50 
51  if( gnutls_init( m_session, GNUTLS_CLIENT ) != 0 )
52  {
53  gnutls_certificate_free_credentials( m_credentials );
54  return false;
55  }
56 
57 #if GNUTLS_VERSION_NUMBER >= 0x020600
58  int ret = gnutls_priority_set_direct( *m_session, "SECURE128:+PFS:+COMP-ALL:+VERS-TLS-ALL:-VERS-SSL3.0:+SIGN-ALL:+CURVE-ALL", 0 );
59  if( ret != GNUTLS_E_SUCCESS )
60  return false;
61 #else
62  const int protocolPriority[] = {
63 #ifdef GNUTLS_TLS1_2
64  GNUTLS_TLS1_2,
65 #endif
66  GNUTLS_TLS1_1, GNUTLS_TLS1, 0 };
67  const int kxPriority[] = { GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_DHE_DSS, 0 };
68  const int cipherPriority[] = { GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_128_CBC,
69  GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0 };
70  const int compPriority[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
71  const int macPriority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
72  gnutls_protocol_set_priority( *m_session, protocolPriority );
73  gnutls_cipher_set_priority( *m_session, cipherPriority );
74  gnutls_compression_set_priority( *m_session, compPriority );
75  gnutls_kx_set_priority( *m_session, kxPriority );
76  gnutls_mac_set_priority( *m_session, macPriority );
77 #endif
78 
79  gnutls_credentials_set( *m_session, GNUTLS_CRD_CERTIFICATE, m_credentials );
80 
81  gnutls_transport_set_ptr( *m_session, static_cast<gnutls_transport_ptr_t>( this ) );
82  gnutls_transport_set_push_function( *m_session, pushFunc );
83  gnutls_transport_set_pull_function( *m_session, pullFunc );
84 
85  m_valid = true;
86  return true;
87  }
88 
89  void GnuTLSClient::setCACerts( const StringList& cacerts )
90  {
91  m_cacerts = cacerts;
92 
93  StringList::const_iterator it = m_cacerts.begin();
94  for( ; it != m_cacerts.end(); ++it )
95  gnutls_certificate_set_x509_trust_file( m_credentials, (*it).c_str(), GNUTLS_X509_FMT_PEM );
96  }
97 
98  void GnuTLSClient::setClientCert( const std::string& clientKey, const std::string& clientCerts )
99  {
100  m_clientKey = clientKey;
101  m_clientCerts = clientCerts;
102 
103  if( !m_clientKey.empty() && !m_clientCerts.empty() )
104  {
105  gnutls_certificate_set_x509_key_file( m_credentials, m_clientCerts.c_str(),
106  m_clientKey.c_str(), GNUTLS_X509_FMT_PEM );
107  }
108  }
109 
110  void GnuTLSClient::getCertInfo()
111  {
112  unsigned int status;
113  bool error = false;
114 
115  gnutls_certificate_free_ca_names( m_credentials );
116 
117  if( gnutls_certificate_verify_peers2( *m_session, &status ) < 0 )
118  error = true;
119 
120  m_certInfo.status = 0;
121  if( status & GNUTLS_CERT_INVALID )
122  m_certInfo.status |= CertInvalid;
123  if( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
124  m_certInfo.status |= CertSignerUnknown;
125  if( status & GNUTLS_CERT_REVOKED )
126  m_certInfo.status |= CertRevoked;
127  if( status & GNUTLS_CERT_SIGNER_NOT_CA )
128  m_certInfo.status |= CertSignerNotCa;
129 
130  const gnutls_datum_t* certList = 0;
131  unsigned int certListSize = 0;
132  if( !error && ( ( certList = gnutls_certificate_get_peers( *m_session, &certListSize ) ) == 0 ) )
133  error = true;
134 
135  unsigned int certListSizeFull = certListSize;
136 
137  gnutls_x509_crt_t* cert = new gnutls_x509_crt_t[certListSize];
138  for( unsigned int i=0; !error && ( i<certListSize ); ++i )
139  {
140  if( gnutls_x509_crt_init( &cert[i] ) < 0
141  || gnutls_x509_crt_import( cert[i], &certList[i], GNUTLS_X509_FMT_DER ) < 0 )
142  error = true;
143  }
144 
145  if( certListSize > 1 && ( gnutls_x509_crt_check_issuer( cert[certListSize-1], cert[certListSize-1] ) > 0 ) )
146  certListSize--;
147 
148  bool chain = true;
149  for( unsigned int i=1; !error && ( i<certListSize ); ++i )
150  {
151  chain = error = !verifyAgainst( cert[i-1], cert[i] );
152  }
153  if( !chain )
154  m_certInfo.status |= CertInvalid;
155  m_certInfo.chain = chain;
156 
157  m_certInfo.chain = verifyAgainstCAs( cert[certListSize-1], 0 /*CAList*/, 0 /*CAListSize*/ );
158 
159  time_t t = gnutls_x509_crt_get_activation_time( cert[0] );
160  if( t == -1 )
161  error = true;
162  else if( t > time( 0 ) )
163  m_certInfo.status |= CertNotActive;
164  m_certInfo.date_from = static_cast<int>( t );
165 
166  t = gnutls_x509_crt_get_expiration_time( cert[0] );
167  if( t == -1 )
168  error = true;
169  else if( t < time( 0 ) )
170  m_certInfo.status |= CertExpired;
171  m_certInfo.date_to = static_cast<int>( t );
172 
173  char name[64];
174  size_t nameSize = sizeof( name );
175  gnutls_x509_crt_get_issuer_dn( cert[0], name, &nameSize );
176  m_certInfo.issuer = name;
177 
178  nameSize = sizeof( name );
179  gnutls_x509_crt_get_dn( cert[0], name, &nameSize );
180  m_certInfo.server = name;
181 
182  const char* info;
183  info = gnutls_compression_get_name( gnutls_compression_get( *m_session ) );
184  if( info )
185  m_certInfo.compression = info;
186 
187  info = gnutls_mac_get_name( gnutls_mac_get( *m_session ) );
188  if( info )
189  m_certInfo.mac = info;
190 
191  info = gnutls_cipher_get_name( gnutls_cipher_get( *m_session ) );
192  if( info )
193  m_certInfo.cipher = info;
194 
195  info = gnutls_protocol_get_name( gnutls_protocol_get_version( *m_session ) );
196  if( info )
197  m_certInfo.protocol = info;
198 
199  if( !gnutls_x509_crt_check_hostname( cert[0], m_server.c_str() ) )
200  m_certInfo.status |= CertWrongPeer;
201 
202  for( unsigned int i = 0; i < certListSizeFull; ++i )
203  gnutls_x509_crt_deinit( cert[i] );
204 
205  delete[] cert;
206 
207  m_valid = true;
208  }
209 
210  static bool verifyCert( gnutls_x509_crt_t cert, unsigned result )
211  {
212  return ! ( ( result & GNUTLS_CERT_INVALID )
213  || gnutls_x509_crt_get_expiration_time( cert ) < time( 0 )
214  || gnutls_x509_crt_get_activation_time( cert ) > time( 0 ) );
215  }
216 
217  bool GnuTLSClient::verifyAgainst( gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer )
218  {
219  unsigned int result;
220  gnutls_x509_crt_verify( cert, &issuer, 1, 0, &result );
221  return verifyCert( cert, result );
222  }
223 
224  bool GnuTLSClient::verifyAgainstCAs( gnutls_x509_crt_t cert, gnutls_x509_crt_t* CAList, int CAListSize )
225  {
226  unsigned int result;
227  gnutls_x509_crt_verify( cert, CAList, CAListSize, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &result );
228  return verifyCert( cert, result );
229  }
230 
231 }
232 
233 #endif // HAVE_GNUTLS
std::list< std::string > StringList
Definition: gloox.h:1251
virtual void cleanup()
bool chain
Definition: gloox.h:992
std::string cipher
Definition: gloox.h:1002
virtual bool init(const std::string &clientKey=EmptyString, const std::string &clientCerts=EmptyString, const StringList &cacerts=StringList())
std::string issuer
Definition: gloox.h:993
std::string server
Definition: gloox.h:994
std::string mac
Definition: gloox.h:1003
The namespace for the gloox library.
Definition: adhoc.cpp:27
int date_from
Definition: gloox.h:995
This is the common base class for (stream) encryption using GnuTLS.
Definition: tlsgnutlsbase.h:38
std::string protocol
Definition: gloox.h:1001
GnuTLSClient(TLSHandler *th, const std::string &server)
virtual void setCACerts(const StringList &cacerts)
virtual void setClientCert(const std::string &clientKey, const std::string &clientCerts)
virtual void cleanup()
An interface that allows for interacting with TLS implementations derived from TLSBase.
Definition: tlshandler.h:34
std::string compression
Definition: gloox.h:1004