gloox  1.1-svn
tlsschannelclient.cpp
1 /*
2  * Copyright (c) 2007-2009 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 #include "tlsschannelclient.h"
14 
15 #ifdef HAVE_WINTLS
16 
17 // #include <stdio.h> // just for debugging output
18 
19 namespace gloox
20 {
21  SChannelClient::SChannelClient( TLSHandler* th, const std::string& server )
22  : SChannelBase( th, server )
23  {
24  //printf(">> SChannelClient::SChannelClient()\n");
25  }
26 
28  {
29  m_handler = 0;
30  cleanup();
31  //printf(">> SChannelClient::~SChannelClient()\n");
32  }
33 
35  {
36  if( !m_handler )
37  return false;
38 
39  if( m_haveCredentialsHandle )
40  {
41  handshakeStage();
42  return true;
43  }
44 
45 // printf(">> SChannelClient::handshake()\n");
46  SECURITY_STATUS error;
47  ULONG return_flags;
48  TimeStamp t;
49  SecBuffer obuf[1];
50  SecBufferDesc obufs;
51  SCHANNEL_CRED tlscred;
52  ULONG request = ISC_REQ_ALLOCATE_MEMORY
53  | ISC_REQ_CONFIDENTIALITY
54  | ISC_REQ_EXTENDED_ERROR
55  | ISC_REQ_INTEGRITY
56  | ISC_REQ_REPLAY_DETECT
57  | ISC_REQ_SEQUENCE_DETECT
58  | ISC_REQ_STREAM
59  | ISC_REQ_MANUAL_CRED_VALIDATION;
60 
61  /* initialize TLS credential */
62  memset( &tlscred, 0, sizeof( SCHANNEL_CRED ) );
63  tlscred.dwVersion = SCHANNEL_CRED_VERSION;
64  tlscred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
65  /* acquire credentials */
66  error = AcquireCredentialsHandle( 0,
67  UNISP_NAME,
68  SECPKG_CRED_OUTBOUND,
69  0,
70  &tlscred,
71  0,
72  0,
73  &m_credHandle,
74  &t );
75 // print_error(error, "SChannelClient::handshake() ~ AcquireCredentialsHandle()");
76  if( error != SEC_E_OK )
77  {
78  cleanup();
79  m_handler->handleHandshakeResult( this, false, m_certInfo );
80  return false;
81  }
82  else
83  {
84  /* initialize buffers */
85  obuf[0].cbBuffer = 0;
86  obuf[0].pvBuffer = 0;
87  obuf[0].BufferType = SECBUFFER_TOKEN;
88  /* initialize buffer descriptors */
89  obufs.ulVersion = SECBUFFER_VERSION;
90  obufs.cBuffers = 1;
91  obufs.pBuffers = obuf;
92  /* negotiate security */
93  SEC_CHAR* hname = const_cast<char*>( m_server.c_str() );
94 
95  error = InitializeSecurityContextA( &m_credHandle,
96  0,
97  hname,
98  request,
99  0,
100  0,
101  0,
102  0,
103  &m_context,
104  &obufs,
105  &return_flags,
106  0 );
107 // print_error(error, "SChannelClient::handshake() ~ InitializeSecurityContext()");
108 
109  if( error == SEC_I_CONTINUE_NEEDED )
110  {
111  m_cleanedup = false;
112  //std::cout << "obuf[1].cbBuffer: " << obuf[0].cbBuffer << "\n";
113  std::string senddata( static_cast<char*>( obuf[0].pvBuffer ), obuf[0].cbBuffer );
114  FreeContextBuffer( obuf[0].pvBuffer );
115  m_haveCredentialsHandle = true;
116  m_handler->handleEncryptedData( this, senddata );
117  return true;
118  }
119  else
120  {
121  cleanup();
122  m_handler->handleHandshakeResult( this, false, m_certInfo );
123  return false;
124  }
125  }
126  }
127 
128  void SChannelClient::handshakeStage()
129  {
130 // printf(" >> SChannelClient::handshakeStage\n");
131 
132  SECURITY_STATUS error;
133  ULONG a;
134  TimeStamp t;
135  SecBuffer ibuf[2], obuf[1];
136  SecBufferDesc ibufs, obufs;
137  ULONG request = ISC_REQ_ALLOCATE_MEMORY
138  | ISC_REQ_CONFIDENTIALITY
139  | ISC_REQ_EXTENDED_ERROR
140  | ISC_REQ_INTEGRITY
141  | ISC_REQ_REPLAY_DETECT
142  | ISC_REQ_SEQUENCE_DETECT
143  | ISC_REQ_STREAM
144  | ISC_REQ_MANUAL_CRED_VALIDATION;
145 
146  SEC_CHAR* hname = const_cast<char*>( m_server.c_str() );
147 
148  do
149  {
150  /* initialize buffers */
151  ibuf[0].cbBuffer = static_cast<unsigned long>( m_buffer.size() );
152  ibuf[0].pvBuffer = static_cast<void*>( const_cast<char*>( m_buffer.c_str() ) );
153  //std::cout << "Size: " << m_buffer.size() << "\n";
154  ibuf[1].cbBuffer = 0;
155  ibuf[1].pvBuffer = 0;
156  obuf[0].cbBuffer = 0;
157  obuf[0].pvBuffer = 0;
158 
159  ibuf[0].BufferType = SECBUFFER_TOKEN;
160  ibuf[1].BufferType = SECBUFFER_EMPTY;
161  obuf[0].BufferType = SECBUFFER_EMPTY;
162  /* initialize buffer descriptors */
163  ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
164  ibufs.cBuffers = 2;
165  obufs.cBuffers = 1;
166  ibufs.pBuffers = ibuf;
167  obufs.pBuffers = obuf;
168 
169  /*
170  * std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
171  * std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
172  * std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
173  */
174 
175  /* negotiate security */
176  error = InitializeSecurityContextA( &m_credHandle,
177  &m_context,
178  hname,
179  request,
180  0,
181  0,
182  &ibufs,
183  0,
184  0,
185  &obufs,
186  &a,
187  &t );
188 // print_error(error, "SChannelClient::handshakeStage() ~ InitializeSecurityContext()");
189  if( error == SEC_E_OK )
190  {
191  // EXTRA STUFF??
192  if( ibuf[1].BufferType == SECBUFFER_EXTRA )
193  {
194  m_buffer.erase( 0, m_buffer.size() - ibuf[1].cbBuffer );
195  }
196  else
197  {
198  m_buffer = EmptyString;
199  }
200  setSizes();
201  setCertinfos();
202 
203  m_secure = true;
204  m_handler->handleHandshakeResult( this, true, m_certInfo );
205  break;
206  }
207  else if( error == SEC_I_CONTINUE_NEEDED )
208  {
209  /*
210  * std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
211  * std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
212  * std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
213  */
214 
215  // STUFF TO SEND??
216  if( obuf[0].cbBuffer != 0 && obuf[0].pvBuffer != 0 )
217  {
218  std::string senddata( static_cast<char*>(obuf[0].pvBuffer), obuf[0].cbBuffer );
219  FreeContextBuffer( obuf[0].pvBuffer );
220  m_handler->handleEncryptedData( this, senddata );
221  }
222  // EXTRA STUFF??
223  if( ibuf[1].BufferType == SECBUFFER_EXTRA )
224  {
225  m_buffer.erase( 0, m_buffer.size() - ibuf[1].cbBuffer );
226  // Call again if we aren't sending anything (otherwise the server will not send anything back
227  // and this function won't get called again to finish the processing). This is needed for
228  // NT4.0 which does not seem to process the entire buffer the first time around
229  if( obuf[0].cbBuffer == 0 )
230  handshakeStage();
231  }
232  else
233  {
234  m_buffer = EmptyString;
235  }
236  return;
237  }
238  else if( error == SEC_I_INCOMPLETE_CREDENTIALS )
239  {
240  handshakeStage();
241  }
242  else if( error == SEC_E_INCOMPLETE_MESSAGE )
243  {
244  break;
245  }
246  else
247  {
248  cleanup();
249  m_handler->handleHandshakeResult( this, false, m_certInfo );
250  break;
251  }
252  }
253  while( true );
254  }
255 
256 }
257 
258 #endif // HAVE_WINTLS