gloox  1.1-svn
tlsschannelbase.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 "tlsschannelbase.h"
14 #include "gloox.h"
15 
16 #ifdef HAVE_WINTLS
17 
18 #include <stdio.h> // just for debugging output
19 
20 namespace gloox
21 {
22  SChannelBase::SChannelBase( TLSHandler* th, const std::string& server )
23  : TLSBase( th, server ), m_cleanedup( true ), m_haveCredentialsHandle( false ),
24  m_store( 0 ), m_cert( 0 )
25  {
26  //printf(">> SChannelBase::SChannelBase()\n");
27  }
28 
30  {
31  m_handler = 0;
32  cleanup();
33  //printf(">> SChannelBase::~SChannelBase()\n");
34  }
35 
36  bool SChannelBase::init( const std::string& /*clientKey*/,
37  const std::string& /*clientCerts*/,
38  const StringList& /*cacerts*/ )
39  {
40  memset( &m_tlsCred, 0, sizeof( SCHANNEL_CRED ) );
41  m_tlsCred.dwVersion = SCHANNEL_CRED_VERSION;
42  m_tlsCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
43 
44  if( !m_subject.empty() )
45  {
46  m_store = CertOpenSystemStore( 0, "MY" );
47  if( !m_store )
48  return false;
49 
50  int length = MultiByteToWideChar( CP_UTF8, 0, m_subject.c_str(), m_subject.length(), 0, 0 );
51  LPWSTR wsubject = new WCHAR[length+1];
52  wsubject[length] = L'\0';
53  length = MultiByteToWideChar( CP_UTF8, 0, m_subject.c_str(), m_subject.length(), wsubject, length );
54  m_cert = CertFindCertificateInStore( m_store, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
55  0, CERT_FIND_SUBJECT_STR, wsubject, 0 );
56  delete[] wsubject;
57 
58  if( !m_cert )
59  return false;
60  }
61 
62  m_tlsCred.cCreds = 1;
63  m_tlsCred.paCred = &m_cert;
64 
65  m_valid = true;
66  return true;
67  }
68 
69  bool SChannelBase::encrypt( const std::string& data )
70  {
71  if( !m_handler || !m_valid )
72  return false;
73 
74  //printf(">> SChannelBase::encrypt()\n");
75  size_t currentPos = 0;
76  const size_t inputSize = data.size();
77 
78  SecBuffer buffer[4];
79  SecBufferDesc buffer_desc;
80  DWORD cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
81 
82  PBYTE e_iobuffer = static_cast<PBYTE>( LocalAlloc( LMEM_FIXED, cbIoBufferLength ) );
83 
84  if( !e_iobuffer )
85  {
86  //printf("**** Out of memory (2)\n");
87  cleanup();
88  if( !m_secure )
89  m_handler->handleHandshakeResult( this, false, m_certInfo );
90  return false;
91  }
92  PBYTE e_message = e_iobuffer + m_sizes.cbHeader;
93  do
94  {
95  const size_t size = ( ( inputSize - currentPos ) > m_sizes.cbMaximumMessage )
96  ? m_sizes.cbMaximumMessage
97  : ( inputSize - currentPos );
98  memcpy( e_message, data.data() + currentPos, size );
99  currentPos += size;
100 
101 
102  buffer[0].pvBuffer = e_iobuffer;
103  buffer[0].cbBuffer = m_sizes.cbHeader;
104  buffer[0].BufferType = SECBUFFER_STREAM_HEADER;
105 
106  buffer[1].pvBuffer = e_message;
107  buffer[1].cbBuffer = size;
108  buffer[1].BufferType = SECBUFFER_DATA;
109 
110  buffer[2].pvBuffer = static_cast<char*>( buffer[1].pvBuffer ) + buffer[1].cbBuffer;
111  buffer[2].cbBuffer = m_sizes.cbTrailer;
112  buffer[2].BufferType = SECBUFFER_STREAM_TRAILER;
113 
114  buffer[3].BufferType = SECBUFFER_EMPTY;
115 
116  buffer_desc.ulVersion = SECBUFFER_VERSION;
117  buffer_desc.cBuffers = 4;
118  buffer_desc.pBuffers = buffer;
119 
120  SECURITY_STATUS e_status = EncryptMessage( &m_context, 0, &buffer_desc, 0 );
121  if( SUCCEEDED( e_status ) )
122  {
123  std::string encrypted( reinterpret_cast<const char*>( e_iobuffer ),
124  buffer[0].cbBuffer + buffer[1].cbBuffer + buffer[2].cbBuffer );
125  m_handler->handleEncryptedData( this, encrypted );
126  }
127  else
128  {
129  LocalFree( e_iobuffer );
130  if( !m_secure )
131  m_handler->handleHandshakeResult( this, false, m_certInfo );
132 
133  cleanup();
134  return false;
135  }
136  }
137  while( currentPos < inputSize - 1 );
138 
139  LocalFree( e_iobuffer );
140  return true;
141  }
142 
143  int SChannelBase::decrypt( const std::string& data )
144  {
145 
146  if( !m_handler || !m_valid )
147  return 0;
148 
149  //printf(">> SChannelBase::decrypt()\n");
150  m_buffer += data;
151 
152  if( !m_secure )
153  {
154  handshake();
155  return 0;
156  }
157 
158 // printf( "-------------------------m_buffer size is now %d\n", m_buffer.length());
159 
160  SecBuffer buffer[4];
161  SecBufferDesc buffer_desc;
162  DWORD cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
163  bool wantNewBufferSize = false;
164 
165  PBYTE e_iobuffer = static_cast<PBYTE>( LocalAlloc( LMEM_FIXED, cbIoBufferLength ) );
166  if( !e_iobuffer )
167  {
168  //printf("**** Out of memory (2)\n");
169  cleanup();
170  if( !m_secure )
171  m_handler->handleHandshakeResult( this, false, m_certInfo );
172  return 0;
173  }
174  SECURITY_STATUS e_status;
175 
176  do
177  {
178  if( wantNewBufferSize )
179  {
180 // printf( "reallocating to %d byts\n", cbIoBufferLength );
181  e_iobuffer = static_cast<PBYTE>( LocalReAlloc( e_iobuffer, cbIoBufferLength, 0 ) );
182  wantNewBufferSize = false;
183  }
184 
185  // copy data chunk from tmp string into encryption memory buffer
186  memcpy( e_iobuffer, m_buffer.data(), m_buffer.size() >
187  cbIoBufferLength ? cbIoBufferLength : m_buffer.size() );
188 
189  buffer[0].pvBuffer = e_iobuffer;
190  buffer[0].cbBuffer = static_cast<unsigned long>( m_buffer.size() > cbIoBufferLength
191  ? cbIoBufferLength
192  : m_buffer.size() );
193  buffer[0].BufferType = SECBUFFER_DATA;
194  buffer[1].cbBuffer = buffer[2].cbBuffer = buffer[3].cbBuffer = 0;
195  buffer[1].BufferType = buffer[2].BufferType = buffer[3].BufferType = SECBUFFER_EMPTY;
196 
197  buffer_desc.ulVersion = SECBUFFER_VERSION;
198  buffer_desc.cBuffers = 4;
199  buffer_desc.pBuffers = buffer;
200 
201  unsigned long processed_data = buffer[0].cbBuffer;
202 // printf("feeding %d of %d bytes to DecryptMessage()\n", buffer[0].cbBuffer, m_buffer.size() );
203  e_status = DecryptMessage( &m_context, &buffer_desc, 0, 0 );
204 // print_error(e_status, "SChannelBase::decrypt() ~ DecryptMessage()");
205 
206  // print_error(e_status, "decrypt() ~ DecryptMessage()");
207  // for (int n=0; n<4; n++)
208  // printf("buffer[%d].cbBuffer: %d \t%d\n", n, buffer[n].cbBuffer, buffer[n].BufferType);
209 
210  // Locate data and (optional) extra buffers.
211  SecBuffer* pDataBuffer = 0;
212  SecBuffer* pExtraBuffer = 0;
213  for( int i = 1; i < 4; i++ )
214  {
215  if( !pDataBuffer && buffer[i].BufferType == SECBUFFER_DATA )
216  {
217  pDataBuffer = &buffer[i];
218  //printf("buffer[%d].BufferType = SECBUFFER_DATA\n",i);
219  }
220  if( !pExtraBuffer && buffer[i].BufferType == SECBUFFER_EXTRA )
221  {
222  pExtraBuffer = &buffer[i];
223  }
224  }
225  if( e_status == SEC_E_OK )
226  {
227  std::string decrypted( reinterpret_cast<const char*>( pDataBuffer->pvBuffer ),
228  pDataBuffer->cbBuffer );
229  m_handler->handleDecryptedData( this, decrypted );
230  if( pExtraBuffer )
231  {
232 // printf("got extra, removing first %d - %d = %d bytes\n", processed_data, pExtraBuffer->cbBuffer, processed_data - pExtraBuffer->cbBuffer );
233  //std::cout << "m_buffer.size() = " << pExtraBuffer->cbBuffer << std::endl;
234  m_buffer.erase( 0, processed_data - pExtraBuffer->cbBuffer );
235  //std::cout << "m_buffer.size() = " << m_buffer.size() << std::endl;
236  }
237  else
238  {
239 // printf( "no extra in buffer\n");
240  m_buffer.erase( 0, processed_data );
241  }
242 
243  cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
244  wantNewBufferSize = true;
245  }
246  else if( e_status == SEC_E_INCOMPLETE_MESSAGE )
247  {
248  if( cbIoBufferLength < 200000 && m_buffer.size() > cbIoBufferLength )
249  {
250  cbIoBufferLength += 1000;
251  wantNewBufferSize = true;
252  }
253  else
254  {
255  cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
256  wantNewBufferSize = true;
257  break;
258  }
259  }
260  else
261  {
262  //std::cout << "decrypt !!!ERROR!!!\n";
263  if( !m_secure )
264  m_handler->handleHandshakeResult( this, false, m_certInfo );
265 
266  cleanup();
267  break;
268  }
269  }
270  while( m_buffer.size() != 0 );
271  LocalFree( e_iobuffer );
272 
273  //printf("<< SChannelBase::decrypt()\n");
274  return 0;
275  }
276 
278  {
279  if( !m_mutex.trylock() )
280  return;
281 
282  m_buffer = EmptyString;
283  if( !m_cleanedup )
284  {
285  m_valid = false;
286  m_secure = false;
287  m_cleanedup = true;
288  DeleteSecurityContext( &m_context );
289  FreeCredentialsHandle( &m_credHandle );
290  }
291 
292  privateCleanup();
293 
294  m_mutex.unlock();
295  }
296 
297  void SChannelBase::setSizes()
298  {
299  if( QueryContextAttributes( &m_context, SECPKG_ATTR_STREAM_SIZES, &m_sizes ) != SEC_E_OK )
300  {
301  cleanup();
302  m_handler->handleHandshakeResult( this, false, m_certInfo );
303  }
304  }
305 
306  int SChannelBase::filetime2int( FILETIME t )
307  {
308  SYSTEMTIME stUTC;
309  FileTimeToSystemTime( &t, &stUTC );
310  std::tm ts;
311  ts.tm_year = stUTC.wYear - 1900;
312  ts.tm_mon = stUTC.wMonth - 1;
313  ts.tm_mday = stUTC.wDay;
314  ts.tm_hour = stUTC.wHour;
315  ts.tm_min = stUTC.wMinute;
316  ts.tm_sec = stUTC.wSecond;
317 
318  time_t unixtime;
319  if ( ( unixtime = mktime( &ts ) ) == -1 )
320  unixtime = 0;
321  return (int)unixtime;
322  }
323 
324  void SChannelBase::validateCert()
325  {
326  bool valid = false;
327  HTTPSPolicyCallbackData policyHTTPS;
328  CERT_CHAIN_POLICY_PARA policyParameter;
329  CERT_CHAIN_POLICY_STATUS policyStatus;
330 
331  PCCERT_CONTEXT remoteCertContext = 0;
332  PCCERT_CHAIN_CONTEXT chainContext = 0;
333  CERT_CHAIN_PARA chainParameter;
334  PSTR serverName = const_cast<char*>( m_server.c_str() );
335 
336  PWSTR uServerName = 0;
337  DWORD csizeServerName;
338 
339  LPSTR Usages[] = {
340  szOID_PKIX_KP_SERVER_AUTH,
341  szOID_SERVER_GATED_CRYPTO,
342  szOID_SGC_NETSCAPE
343  };
344  DWORD cUsages = sizeof( Usages ) / sizeof( LPSTR );
345 
346  do
347  {
348  // Get server's certificate.
349  if( QueryContextAttributes( &m_context, SECPKG_ATTR_REMOTE_CERT_CONTEXT,
350  (PVOID)&remoteCertContext ) != SEC_E_OK )
351  {
352  //printf("Error querying remote certificate\n");
353  // !!! THROW SOME ERROR
354  break;
355  }
356 
357  // unicode conversation
358  // calculating unicode server name size
359  csizeServerName = MultiByteToWideChar( CP_ACP, 0, serverName, -1, 0, 0 );
360  uServerName = reinterpret_cast<WCHAR *>( LocalAlloc( LMEM_FIXED,
361  csizeServerName * sizeof( WCHAR ) ) );
362  if( !uServerName )
363  {
364  //printf("SEC_E_INSUFFICIENT_MEMORY ~ Not enough memory!!!\n");
365  break;
366  }
367 
368  // convert into unicode
369  csizeServerName = MultiByteToWideChar( CP_ACP, 0, serverName, -1, uServerName, csizeServerName );
370  if( !csizeServerName )
371  {
372  //printf("SEC_E_WRONG_PRINCIPAL\n");
373  break;
374  }
375 
376  // create the chain
377  ZeroMemory( &chainParameter, sizeof( chainParameter ) );
378  chainParameter.cbSize = sizeof( chainParameter );
379  chainParameter.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
380  chainParameter.RequestedUsage.Usage.cUsageIdentifier = cUsages;
381  chainParameter.RequestedUsage.Usage.rgpszUsageIdentifier = Usages;
382 
383  if( !CertGetCertificateChain( 0, remoteCertContext, 0, remoteCertContext->hCertStore,
384  &chainParameter, 0, 0, &chainContext ) )
385  {
386 // DWORD status = GetLastError();
387 // printf("Error 0x%x returned by CertGetCertificateChain!!!\n", status);
388  break;
389  }
390 
391  // validate the chain
392  ZeroMemory( &policyHTTPS, sizeof( HTTPSPolicyCallbackData ) );
393  policyHTTPS.cbStruct = sizeof( HTTPSPolicyCallbackData );
394  policyHTTPS.dwAuthType = AUTHTYPE_SERVER;
395  policyHTTPS.fdwChecks = 0;
396  policyHTTPS.pwszServerName = uServerName;
397 
398  memset( &policyParameter, 0, sizeof( policyParameter ) );
399  policyParameter.cbSize = sizeof( policyParameter );
400  policyParameter.pvExtraPolicyPara = &policyHTTPS;
401 
402  memset( &policyStatus, 0, sizeof( policyStatus ) );
403  policyStatus.cbSize = sizeof( policyStatus );
404 
405  if( !CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, chainContext, &policyParameter,
406  &policyStatus ) )
407  {
408 // DWORD status = GetLastError();
409 // printf("Error 0x%x returned by CertVerifyCertificateChainPolicy!!!\n", status);
410  break;
411  }
412 
413  if( policyStatus.dwError )
414  {
415  //printf("Trust Error!!!}n");
416  break;
417  }
418  valid = true;
419  }
420  while( false );
421  // cleanup
422  if( chainContext ) CertFreeCertificateChain( chainContext );
423  m_certInfo.chain = valid;
424  }
425 
426  void SChannelBase::connectionInfos()
427  {
428  SecPkgContext_ConnectionInfo conn_info;
429 
430  memset( &conn_info, 0, sizeof( conn_info ) );
431 
432  if( QueryContextAttributes( &m_context, SECPKG_ATTR_CONNECTION_INFO, &conn_info ) == SEC_E_OK )
433  {
434  switch( conn_info.dwProtocol )
435  {
436  case SP_PROT_TLS1_CLIENT:
437  case SP_PROT_TLS1_SERVER:
438  m_certInfo.protocol = "TLSv1";
439  break;
440  case SP_PROT_SSL3_CLIENT:
441  case SP_PROT_SSL3_SERVER:
442  m_certInfo.protocol = "SSLv3";
443  break;
444  default:
445  m_certInfo.protocol = "unknown";
446  }
447 
448  switch( conn_info.aiCipher )
449  {
450  case CALG_3DES:
451  m_certInfo.cipher = "3DES";
452  break;
453  case CALG_AES_128:
454  m_certInfo.cipher = "AES_128";
455  break;
456  case CALG_AES_256:
457  m_certInfo.cipher = "AES_256";
458  break;
459  case CALG_DES:
460  m_certInfo.cipher = "DES";
461  break;
462  case CALG_RC2:
463  m_certInfo.cipher = "RC2";
464  break;
465  case CALG_RC4:
466  m_certInfo.cipher = "RC4";
467  break;
468  default:
469  m_certInfo.cipher = EmptyString;
470  }
471 
472  switch( conn_info.aiHash )
473  {
474  case CALG_MD5:
475  m_certInfo.mac = "MD5";
476  break;
477  case CALG_SHA:
478  m_certInfo.mac = "SHA";
479  break;
480  default:
481  m_certInfo.mac = EmptyString;
482  }
483  }
484  }
485 
486  void SChannelBase::certData()
487  {
488  PCCERT_CONTEXT remoteCertContext = 0;
489  CHAR certString[1000];
490  m_certInfo.status = CertOk;
491 
492  // getting server's certificate
493  if( QueryContextAttributes( &m_context, SECPKG_ATTR_REMOTE_CERT_CONTEXT,
494  (PVOID)&remoteCertContext ) != SEC_E_OK )
495  {
496  m_certInfo.status |= CertInvalid;
497  return;
498  }
499 
500  // setting certificate's lifespan
501  m_certInfo.date_from = filetime2int( remoteCertContext->pCertInfo->NotBefore );
502  if( m_certInfo.date_from > time( 0 ) )
503  m_certInfo.status |= CertNotActive;
504 
505  m_certInfo.date_to = filetime2int( remoteCertContext->pCertInfo->NotAfter );
506  if( m_certInfo.date_to < time( 0 ) )
507  m_certInfo.status |= CertExpired;
508 
509  if( !CertNameToStrA( remoteCertContext->dwCertEncodingType,
510  &remoteCertContext->pCertInfo->Subject,
511  /*CERT_X500_NAME_STR |*/ CERT_NAME_STR_NO_PLUS_FLAG,
512  certString, sizeof( certString ) ) )
513  {
514  m_certInfo.status |= CertInvalid;
515  return;
516  }
517  m_certInfo.server = certString;
518 
519  if( certString != m_server )
520  m_certInfo.status |= CertInvalid;
521 
522  if( !CertNameToStrA( remoteCertContext->dwCertEncodingType,
523  &remoteCertContext->pCertInfo->Issuer,
524  /*CERT_X500_NAME_STR |*/ CERT_NAME_STR_NO_PLUS_FLAG,
525  certString, sizeof( certString ) ) )
526  {
527  m_certInfo.status |= CertInvalid;
528  return;
529  }
530  m_certInfo.issuer = certString;
531  }
532 
533  void SChannelBase::setCertinfos()
534  {
535  validateCert();
536  connectionInfos();
537  certData();
538  }
539 
540 #if 0
541  void SChannelBase::print_error( int errorcode, const char* place )
542  {
543  if( errorcode != SEC_E_OK )
544  printf( "Win error at %s.\n", place );
545  switch( errorcode )
546  {
547  case SEC_E_OK:
548 // printf( "\tValue:\tSEC_E_OK\n" );
549 // printf( "\tDesc:\tNot really an error. Everything is fine.\n" );
550  break;
551  case SEC_E_MESSAGE_ALTERED:
552  printf( "\tValue:\tSEC_E_MESSAGE_ALTERED\n" );
553  printf( "\tDesc:\tThe message has been altered.\n" );
554  break;
555  case SEC_E_INSUFFICIENT_MEMORY:
556  printf( "\tValue:\tSEC_E_INSUFFICIENT_MEMORY\n" );
557  printf( "\tDesc:\tThere is not enough memory available to complete the requested action.\n" );
558  break;
559  case SEC_E_INTERNAL_ERROR:
560  printf( "\tValue:\tSEC_E_INTERNAL_ERROR\n" );
561  printf( "\tDesc:\tAn error occurred that did not map to an SSPI error code.\n" );
562  break;
563  case SEC_E_NO_CREDENTIALS:
564  printf( "\tValue:\tSEC_E_NO_CREDENTIALS\n" );
565  printf( "\tDesc:\tNo credentials are available in the security package.\n" );
566  break;
567  case SEC_E_NOT_OWNER:
568  printf( "\tValue:\tSEC_E_NOT_OWNER\n" );
569  printf( "\tDesc:\tThe caller of the function does not have the necessary credentials.\n" );
570  break;
571  case SEC_E_SECPKG_NOT_FOUND:
572  printf( "\tValue:\tSEC_E_SECPKG_NOT_FOUND\n" );
573  printf( "\tDesc:\tThe requested security package does not exist. \n" );
574  break;
575  case SEC_E_UNKNOWN_CREDENTIALS:
576  printf( "\tValue:\tSEC_E_UNKNOWN_CREDENTIALS\n" );
577  printf( "\tDesc:\tThe credentials supplied to the package were not recognized.\n" );
578  break;
579  case SEC_E_INCOMPLETE_MESSAGE:
580  printf( "\tValue:\tSEC_E_INCOMPLETE_MESSAGE\n" );
581  printf( "\tDesc:\tData for the whole message was not read from the wire.\n" );
582  break;
583  case SEC_E_INVALID_HANDLE:
584  printf( "\tValue:\tSEC_E_INVALID_HANDLE\n" );
585  printf( "\tDesc:\tThe handle passed to the function is invalid.\n" );
586  break;
587  case SEC_E_INVALID_TOKEN:
588  printf( "\tValue:\tSEC_E_INVALID_TOKEN\n" );
589  printf( "\tDesc:\tThe error is due to a malformed input token, such as a token "
590  "corrupted in transit...\n" );
591  break;
592  case SEC_E_LOGON_DENIED:
593  printf( "\tValue:\tSEC_E_LOGON_DENIED\n" );
594  printf( "\tDesc:\tThe logon failed.\n" );
595  break;
596  case SEC_E_NO_AUTHENTICATING_AUTHORITY:
597  printf( "\tValue:\tSEC_E_NO_AUTHENTICATING_AUTHORITY\n" );
598  printf( "\tDesc:\tNo authority could be contacted for authentication...\n" );
599  break;
600  case SEC_E_TARGET_UNKNOWN:
601  printf( "\tValue:\tSEC_E_TARGET_UNKNOWN\n" );
602  printf( "\tDesc:\tThe target was not recognized.\n" );
603  break;
604  case SEC_I_CONTEXT_EXPIRED:
605  printf( "\tValue:\tSEC_E_CONTEXT_EXPIRED\n" );
606  printf( "\tDesc:\tThe message sender has finished using the connection and has initiated "
607  "a shutdown.\n" );
608  break;
609  case SEC_E_UNSUPPORTED_FUNCTION:
610  printf( "\tValue:\tSEC_E_UNSUPPORTED_FUNCTION\n" );
611  printf( "\tDesc:\tAn invalid context attribute flag (ISC_REQ_DELEGATE or "
612  "ISC_REQ_PROMPT_FOR_CREDS)...\n" );
613  break;
614  case SEC_E_WRONG_PRINCIPAL:
615  printf( "\tValue:\tSEC_E_WRONG_PRINCIPAL\n" );
616  printf( "\tDesc:\tThe principal that received the authentication request "
617  "is not the same as the...\n" );
618  break;
619  case SEC_E_OUT_OF_SEQUENCE:
620  printf( "\tValue:\tSEC_E_OUT_OF_SEQUENCE\n" );
621  printf( "\tDesc:\tThe message was not received in the correct sequence.\n" );
622  break;
623  case SEC_I_COMPLETE_AND_CONTINUE:
624  printf( "\tValue:\tSEC_I_COMPLETE_AND_CONTINUE\n" );
625  printf( "\tDesc:\tThe client must call CompleteAuthToken and then pass the output...\n" );
626  break;
627  case SEC_I_COMPLETE_NEEDED:
628  printf( "\tValue:\tSEC_I_COMPLETE_NEEDED\n" );
629  printf( "\tDesc:\tThe client must finish building the message and then "
630  "call the CompleteAuthToken function.\n" );
631  break;
632  case SEC_I_RENEGOTIATE:
633  printf( "\tValue:\tSEC_I_RENEGOTIATE\n" );
634  printf( "\tDesc:\tThe remote party requires a new handshake sequence or the "
635  "application has just initiated a shutdown.\n" );
636  break;
637  case SEC_I_CONTINUE_NEEDED:
638  printf( "\tValue:\tSEC_I_CONTINUE_NEEDED\n" );
639  printf( "\tDesc:\tThe client must send the output token to the server "
640  "and wait for a return token...\n" );
641  break;
642  case SEC_I_INCOMPLETE_CREDENTIALS:
643  printf( "\tValue:\tSEC_I_INCOMPLETE_CREDENTIALS\n" );
644  printf( "\tDesc:\tThe server has requested client authentication, "
645  "and the supplied credentials either...\n" );
646  break;
647  default:
648  printf( "\tValue:\t%d\n", errorcode );
649  printf( "\tDesc:\tUnknown error code.\n" );
650  }
651  }
652 #endif
653 
654 }
655 
656 #endif // HAVE_WINTLS