gloox  0.9.9.12
tlsgnutlsclient.cpp
1 /*
2  Copyright (c) 2005-2008 by Jakob Schroeter <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  init();
28  }
29 
31  {
32  }
33 
35  {
37  init();
38  }
39 
40  void GnuTLSClient::init()
41  {
42  const int protocolPriority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
43  const int kxPriority[] = { GNUTLS_KX_RSA, 0 };
44  const int cipherPriority[] = { GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_128_CBC,
45  GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0 };
46  const int compPriority[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
47  const int macPriority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
48 
49  if( gnutls_global_init() != 0 )
50  {
51  m_valid = false;
52  return;
53  }
54 
55  if( gnutls_certificate_allocate_credentials( &m_credentials ) < 0 )
56  {
57  m_valid = false;
58  return;
59  }
60 
61  if( gnutls_init( m_session, GNUTLS_CLIENT ) != 0 )
62  {
63  gnutls_certificate_free_credentials( m_credentials );
64  m_valid = false;
65  return;
66  }
67 
68  gnutls_protocol_set_priority( *m_session, protocolPriority );
69  gnutls_cipher_set_priority( *m_session, cipherPriority );
70  gnutls_compression_set_priority( *m_session, compPriority );
71  gnutls_kx_set_priority( *m_session, kxPriority );
72  gnutls_mac_set_priority( *m_session, macPriority );
73  gnutls_credentials_set( *m_session, GNUTLS_CRD_CERTIFICATE, m_credentials );
74 
75  gnutls_transport_set_ptr( *m_session, (gnutls_transport_ptr_t)this );
76  gnutls_transport_set_push_function( *m_session, pushFunc );
77  gnutls_transport_set_pull_function( *m_session, pullFunc );
78  }
79 
80  void GnuTLSClient::setCACerts( const StringList& cacerts )
81  {
82  m_cacerts = cacerts;
83 
84  StringList::const_iterator it = m_cacerts.begin();
85  for( ; it != m_cacerts.end(); ++it )
86  gnutls_certificate_set_x509_trust_file( m_credentials, (*it).c_str(), GNUTLS_X509_FMT_PEM );
87  }
88 
89  void GnuTLSClient::setClientCert( const std::string& clientKey, const std::string& clientCerts )
90  {
91  m_clientKey = clientKey;
92  m_clientCerts = clientCerts;
93 
94  if( !m_clientKey.empty() && !m_clientCerts.empty() )
95  {
96  gnutls_certificate_set_x509_key_file( m_credentials, m_clientCerts.c_str(),
97  m_clientKey.c_str(), GNUTLS_X509_FMT_PEM );
98  }
99  }
100 
101  void GnuTLSClient::getCertInfo()
102  {
103  unsigned int status;
104  bool error = false;
105 
106  gnutls_certificate_free_ca_names( m_credentials );
107 
108  if( gnutls_certificate_verify_peers2( *m_session, &status ) < 0 )
109  error = true;
110 
111  m_certInfo.status = 0;
112  if( status & GNUTLS_CERT_INVALID )
113  m_certInfo.status |= CertInvalid;
114  if( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
115  m_certInfo.status |= CertSignerUnknown;
116  if( status & GNUTLS_CERT_REVOKED )
117  m_certInfo.status |= CertRevoked;
118  if( status & GNUTLS_CERT_SIGNER_NOT_CA )
119  m_certInfo.status |= CertSignerNotCa;
120  const gnutls_datum_t* certList = 0;
121  unsigned int certListSize;
122  if( !error && ( ( certList = gnutls_certificate_get_peers( *m_session, &certListSize ) ) == 0 ) )
123  error = true;
124 
125  gnutls_x509_crt_t *cert = new gnutls_x509_crt_t[certListSize+1];
126  for( unsigned int i=0; !error && ( i<certListSize ); ++i )
127  {
128  if( !error && ( gnutls_x509_crt_init( &cert[i] ) < 0
129  || gnutls_x509_crt_import( cert[i], &certList[i], GNUTLS_X509_FMT_DER ) < 0 ) )
130  error = true;
131  }
132 
133  if( ( gnutls_x509_crt_check_issuer( cert[certListSize-1], cert[certListSize-1] ) > 0 )
134  && certListSize > 0 )
135  certListSize--;
136 
137  bool chain = true;
138  for( unsigned int i=1; !error && ( i<certListSize ); ++i )
139  {
140  chain = error = !verifyAgainst( cert[i-1], cert[i] );
141  }
142  if( !chain )
143  m_certInfo.status |= CertInvalid;
144  m_certInfo.chain = chain;
145 
146  m_certInfo.chain = verifyAgainstCAs( cert[certListSize], 0 /*CAList*/, 0 /*CAListSize*/ );
147 
148  int t = (int)gnutls_x509_crt_get_activation_time( cert[0] );
149  if( t == -1 )
150  error = true;
151  else if( t > time( 0 ) )
152  m_certInfo.status |= CertNotActive;
153  m_certInfo.date_from = t;
154 
155  t = (int)gnutls_x509_crt_get_expiration_time( cert[0] );
156  if( t == -1 )
157  error = true;
158  else if( t < time( 0 ) )
159  m_certInfo.status |= CertExpired;
160  m_certInfo.date_to = t;
161 
162  char name[64];
163  size_t nameSize = sizeof( name );
164  gnutls_x509_crt_get_issuer_dn( cert[0], name, &nameSize );
165  m_certInfo.issuer = name;
166 
167  nameSize = sizeof( name );
168  gnutls_x509_crt_get_dn( cert[0], name, &nameSize );
169  m_certInfo.server = name;
170 
171  const char* info;
172  info = gnutls_compression_get_name( gnutls_compression_get( *m_session ) );
173  if( info )
174  m_certInfo.compression = info;
175 
176  info = gnutls_mac_get_name( gnutls_mac_get( *m_session ) );
177  if( info )
178  m_certInfo.mac = info;
179 
180  info = gnutls_cipher_get_name( gnutls_cipher_get( *m_session ) );
181  if( info )
182  m_certInfo.cipher = info;
183 
184  info = gnutls_protocol_get_name( gnutls_protocol_get_version( *m_session ) );
185  if( info )
186  m_certInfo.protocol = info;
187 
188  if( !gnutls_x509_crt_check_hostname( cert[0], m_server.c_str() ) )
189  m_certInfo.status |= CertWrongPeer;
190 
191  for( unsigned int i=0; i<certListSize; ++i )
192  gnutls_x509_crt_deinit( cert[i] );
193 
194  delete[] cert;
195 
196  m_valid = true;
197  }
198 
199  static bool verifyCert( gnutls_x509_crt_t cert, unsigned result )
200  {
201  return ! ( ( result & GNUTLS_CERT_INVALID )
202  || gnutls_x509_crt_get_expiration_time( cert ) < time( 0 )
203  || gnutls_x509_crt_get_activation_time( cert ) > time( 0 ) );
204  }
205 
206  bool GnuTLSClient::verifyAgainst( gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer )
207  {
208  unsigned int result;
209  gnutls_x509_crt_verify( cert, &issuer, 1, 0, &result );
210  return verifyCert( cert, result );
211  }
212 
213  bool GnuTLSClient::verifyAgainstCAs( gnutls_x509_crt_t cert, gnutls_x509_crt_t *CAList, int CAListSize )
214  {
215  unsigned int result;
216  gnutls_x509_crt_verify( cert, CAList, CAListSize, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &result );
217  return verifyCert( cert, result );
218  }
219 
220 }
221 
222 #endif // HAVE_GNUTLS