1 /*
2  * Copyright (c) 2007-2019 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 #include "tlsschannel.h"
14 
15 #ifdef HAVE_WINTLS
16 
17 #include <stdio.h> // just for debugging output
18 
19 namespace gloox
20 {
SChannel(TLSHandler * th,const std::string & server)21   SChannel::SChannel( TLSHandler* th, const std::string& server )
22     : TLSBase( th, server ), m_cleanedup( true )
23   {
24     //printf(">> SChannel::SChannel()\n");
25   }
26 
~SChannel()27   SChannel::~SChannel()
28   {
29     m_handler = 0;
30     cleanup();
31     //printf(">> SChannel::~SChannel()\n");
32   }
33 
encrypt(const std::string & data)34   bool SChannel::encrypt( const std::string& data )
35   {
36     if( !m_handler )
37       return false;
38 
39     //printf(">> SChannel::encrypt()\n");
40     std::string data_copy = data;
41 
42     SecBuffer buffer[4];
43     SecBufferDesc buffer_desc;
44     DWORD cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
45 
46     PBYTE e_iobuffer = static_cast<PBYTE>( malloc( cbIoBufferLength ) );
47 
48     if( e_iobuffer == NULL )
49     {
50       //printf("**** Out of memory (2)\n");
51       cleanup();
52       if( !m_secure )
53         m_handler->handleHandshakeResult( this, false, m_certInfo );
54       return false;
55     }
56     PBYTE e_message = e_iobuffer + m_sizes.cbHeader;
57     do
58     {
59       const size_t size = ( data_copy.size() > m_sizes.cbMaximumMessage )
60                          ? m_sizes.cbMaximumMessage
61                          : data_copy.size();
62       memcpy( e_message, data_copy.data(), size );
63       if( data_copy.size() > m_sizes.cbMaximumMessage )
64         data_copy.erase( 0, m_sizes.cbMaximumMessage );
65       else
66         data_copy = EmptyString;
67 
68       buffer[0].pvBuffer     = e_iobuffer;
69       buffer[0].cbBuffer     = m_sizes.cbHeader;
70       buffer[0].BufferType   = SECBUFFER_STREAM_HEADER;
71 
72       buffer[1].pvBuffer     = e_message;
73       buffer[1].cbBuffer     = size;
74       buffer[1].BufferType   = SECBUFFER_DATA;
75 
76       buffer[2].pvBuffer     = static_cast<char*>(buffer[1].pvBuffer) + buffer[1].cbBuffer;
77       buffer[2].cbBuffer     = m_sizes.cbTrailer;
78       buffer[2].BufferType   = SECBUFFER_STREAM_TRAILER;
79 
80       buffer[3].BufferType   = SECBUFFER_EMPTY;
81 
82       buffer_desc.ulVersion       = SECBUFFER_VERSION;
83       buffer_desc.cBuffers        = 4;
84       buffer_desc.pBuffers        = buffer;
85 
86       SECURITY_STATUS e_status = EncryptMessage( &m_context, 0, &buffer_desc, 0 );
87       if( SUCCEEDED( e_status ) )
88       {
89         std::string encrypted( reinterpret_cast<const char*>(e_iobuffer),
90                                buffer[0].cbBuffer + buffer[1].cbBuffer + buffer[2].cbBuffer );
91         m_handler->handleEncryptedData( this, encrypted );
92         //if (data_copy.size() <= m_sizes.cbMaximumMessage) data_copy = EmptyString;
93       }
94       else
95       {
96         free( e_iobuffer );
97         e_iobuffer = 0;
98         if( !m_secure )
99           m_handler->handleHandshakeResult( this, false, m_certInfo );
100         cleanup();
101         return false;
102       }
103     }
104     while( data_copy.size() > 0 );
105     free( e_iobuffer );
106     e_iobuffer = 0;
107     return true;
108   }
109 
decrypt(const std::string & data)110   int SChannel::decrypt( const std::string& data )
111   {
112 
113     if( !m_handler )
114       return 0;
115 
116     //printf(">> SChannel::decrypt()\n");
117     if( m_secure )
118     {
119       m_buffer += data;
120 
121       SecBuffer buffer[4];
122       SecBufferDesc buffer_desc;
123       DWORD cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
124       bool wantNewBufferSize = false;
125 
126       PBYTE e_iobuffer = static_cast<PBYTE>( malloc( cbIoBufferLength ) );
127       if( e_iobuffer == NULL )
128       {
129         //printf("**** Out of memory (2)\n");
130         cleanup();
131         if( !m_secure )
132           m_handler->handleHandshakeResult( this, false, m_certInfo );
133         return 0;
134       }
135       SECURITY_STATUS e_status;
136 
137       do
138       {
139         if( wantNewBufferSize )
140         {
141           void* tmp = realloc( e_iobuffer, cbIoBufferLength );
142           if( tmp )
143           {
144             e_iobuffer = static_cast<PBYTE>( tmp );
145             wantNewBufferSize = false;
146           }
147           else
148           {
149             //printf("**** Out of memory (2)\n");
150             cleanup();
151             m_handler->handleHandshakeResult( this, false, m_certInfo );
152             return 0;
153           }
154         }
155 
156         // copy data chunk from tmp string into encryption memory buffer
157         memcpy( e_iobuffer, m_buffer.data(), m_buffer.size() >
158                cbIoBufferLength ? cbIoBufferLength : m_buffer.size() );
159 
160         buffer[0].pvBuffer     = e_iobuffer;
161         buffer[0].cbBuffer     = static_cast<unsigned long>( m_buffer.size() > cbIoBufferLength
162                                                                ? cbIoBufferLength
163                                                                : m_buffer.size() );
164         buffer[0].BufferType   = SECBUFFER_DATA;
165         buffer[1].cbBuffer = buffer[2].cbBuffer = buffer[3].cbBuffer = 0;
166         buffer[1].BufferType = buffer[2].BufferType = buffer[3].BufferType  = SECBUFFER_EMPTY;
167 
168         buffer_desc.ulVersion       = SECBUFFER_VERSION;
169         buffer_desc.cBuffers        = 4;
170         buffer_desc.pBuffers        = buffer;
171 
172         unsigned long processed_data = buffer[0].cbBuffer;
173         e_status = DecryptMessage( &m_context, &buffer_desc, 0, 0 );
174 
175         // print_error(e_status, "decrypt() ~ DecryptMessage()");
176         // for (int n=0; n<4; n++)
177         //     printf("buffer[%d].cbBuffer: %d   \t%d\n", n, buffer[n].cbBuffer, buffer[n].BufferType);
178 
179         // Locate data and (optional) extra buffers.
180         SecBuffer* pDataBuffer  = NULL;
181         SecBuffer* pExtraBuffer = NULL;
182         for( int i = 1; i < 4; i++ )
183         {
184           if( pDataBuffer == NULL && buffer[i].BufferType == SECBUFFER_DATA )
185           {
186             pDataBuffer = &buffer[i];
187             //printf("buffer[%d].BufferType = SECBUFFER_DATA\n",i);
188           }
189           if( pExtraBuffer == NULL && buffer[i].BufferType == SECBUFFER_EXTRA )
190           {
191             pExtraBuffer = &buffer[i];
192           }
193         }
194         if( e_status == SEC_E_OK )
195         {
196           std::string decrypted( reinterpret_cast<const char*>( pDataBuffer->pvBuffer ),
197                                  pDataBuffer->cbBuffer );
198           m_handler->handleDecryptedData( this, decrypted );
199           if( pExtraBuffer == NULL )
200           {
201             m_buffer.erase( 0, processed_data );
202           }
203           else
204           {
205             //std::cout << "m_buffer.size() = " << pExtraBuffer->cbBuffer << std::endl;
206             m_buffer.erase( 0, processed_data - pExtraBuffer->cbBuffer );
207             //std::cout << "m_buffer.size() = " << m_buffer.size() << std::endl;
208 
209             cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
210             wantNewBufferSize = true;
211           }
212         }
213         else if( e_status == SEC_E_INCOMPLETE_MESSAGE )
214         {
215           if( cbIoBufferLength < 200000 && m_buffer.size() > cbIoBufferLength )
216           {
217             cbIoBufferLength += 1000;
218             wantNewBufferSize = true;
219           }
220           else
221           {
222             cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer;
223             wantNewBufferSize = true;
224             break;
225           }
226         }
227         else
228         {
229           //std::cout << "decrypt !!!ERROR!!!\n";
230           if( !m_secure )
231             m_handler->handleHandshakeResult( this, false, m_certInfo );
232           cleanup();
233           break;
234         }
235       }
236       while( m_buffer.size() != 0 );
237       free( e_iobuffer );
238     }
239     else
240     {
241       handshakeStage( data );
242     }
243     //printf("<< SChannel::decrypt()\n");
244     return 0;
245   }
246 
cleanup()247   void SChannel::cleanup()
248   {
249     if( !m_mutex.trylock() )
250       return;
251 
252     m_buffer = "";
253     if( !m_cleanedup )
254     {
255       m_valid = false;
256       m_secure = false;
257       m_cleanedup = true;
258       DeleteSecurityContext( &m_context );
259       FreeCredentialsHandle( &m_credHandle );
260     }
261 
262     m_mutex.unlock();
263   }
264 
handshake()265   bool SChannel::handshake()
266   {
267     if( !m_handler )
268       return false;
269 
270     //printf(">> SChannel::handshake()\n");
271     SECURITY_STATUS error;
272     ULONG return_flags;
273     TimeStamp t;
274     SecBuffer obuf[1];
275     SecBufferDesc obufs;
276     SCHANNEL_CRED tlscred;
277     ULONG request = ISC_REQ_ALLOCATE_MEMORY
278                     | ISC_REQ_CONFIDENTIALITY
279                     | ISC_REQ_EXTENDED_ERROR
280                     | ISC_REQ_INTEGRITY
281                     | ISC_REQ_REPLAY_DETECT
282                     | ISC_REQ_SEQUENCE_DETECT
283                     | ISC_REQ_STREAM
284                     | ISC_REQ_MANUAL_CRED_VALIDATION;
285 
286     /* initialize TLS credential */
287     memset( &tlscred, 0, sizeof( SCHANNEL_CRED ) );
288     tlscred.dwVersion = SCHANNEL_CRED_VERSION;
289     tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
290     /* acquire credentials */
291     error = AcquireCredentialsHandle( 0,
292                                       UNISP_NAME,
293                                       SECPKG_CRED_OUTBOUND,
294                                       0,
295                                       &tlscred,
296                                       0,
297                                       0,
298                                       &m_credHandle,
299                                       &t );
300     //print_error(error, "handshake() ~ AcquireCredentialsHandle()");
301     if( error != SEC_E_OK )
302     {
303       cleanup();
304       m_handler->handleHandshakeResult( this, false, m_certInfo );
305       return false;
306     }
307     else
308     {
309       /* initialize buffers */
310       obuf[0].cbBuffer = 0;
311       obuf[0].pvBuffer = 0;
312       obuf[0].BufferType = SECBUFFER_TOKEN;
313       /* initialize buffer descriptors */
314       obufs.ulVersion = SECBUFFER_VERSION;
315       obufs.cBuffers = 1;
316       obufs.pBuffers = obuf;
317       /* negotiate security */
318       SEC_CHAR* hname = const_cast<char*>( m_server.c_str() );
319 
320       error = InitializeSecurityContextA( &m_credHandle,
321                                          0,
322                                          hname,
323                                          request,
324                                          0,
325                                          SECURITY_NETWORK_DREP,
326                                          0,
327                                          0,
328                                          &m_context,
329                                          &obufs,
330                                          &return_flags,
331                                          NULL );
332       //print_error(error, "handshake() ~ InitializeSecurityContext()");
333 
334       if( error == SEC_I_CONTINUE_NEEDED )
335       {
336         m_cleanedup = false;
337         //std::cout << "obuf[1].cbBuffer: " << obuf[0].cbBuffer << "\n";
338         std::string senddata( static_cast<char*>(obuf[0].pvBuffer), obuf[0].cbBuffer );
339         FreeContextBuffer( obuf[0].pvBuffer );
340         m_handler->handleEncryptedData( this, senddata );
341         return true;
342       }
343       else
344       {
345         cleanup();
346         m_handler->handleHandshakeResult( this, false, m_certInfo );
347         return false;
348       }
349     }
350   }
351 
handshakeStage(const std::string & data)352   void SChannel::handshakeStage( const std::string& data )
353   {
354     //printf(" >> handshake_stage\n");
355     m_buffer += data;
356 
357     SECURITY_STATUS error;
358     ULONG a;
359     TimeStamp t;
360     SecBuffer ibuf[2], obuf[1];
361     SecBufferDesc ibufs, obufs;
362     ULONG request = ISC_REQ_ALLOCATE_MEMORY
363                     | ISC_REQ_CONFIDENTIALITY
364                     | ISC_REQ_EXTENDED_ERROR
365                     | ISC_REQ_INTEGRITY
366                     | ISC_REQ_REPLAY_DETECT
367                     | ISC_REQ_SEQUENCE_DETECT
368                     | ISC_REQ_STREAM
369                     | ISC_REQ_MANUAL_CRED_VALIDATION;
370 
371     SEC_CHAR* hname = const_cast<char*>( m_server.c_str() );
372 
373     do
374     {
375       /* initialize buffers */
376       ibuf[0].cbBuffer = static_cast<unsigned long>( m_buffer.size() );
377       ibuf[0].pvBuffer = static_cast<void*>( const_cast<char*>( m_buffer.c_str() ) );
378       //std::cout << "Size: " << m_buffer.size() << "\n";
379       ibuf[1].cbBuffer = 0;
380       ibuf[1].pvBuffer = 0;
381       obuf[0].cbBuffer = 0;
382       obuf[0].pvBuffer = 0;
383 
384       ibuf[0].BufferType = SECBUFFER_TOKEN;
385       ibuf[1].BufferType = SECBUFFER_EMPTY;
386       obuf[0].BufferType = SECBUFFER_EMPTY;
387       /* initialize buffer descriptors */
388       ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
389       ibufs.cBuffers = 2;
390       obufs.cBuffers = 1;
391       ibufs.pBuffers = ibuf;
392       obufs.pBuffers = obuf;
393 
394       /*
395        * std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
396        * std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
397        * std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
398        */
399 
400       /* negotiate security */
401       error = InitializeSecurityContextA( &m_credHandle,
402                                          &m_context,
403                                          hname,
404                                          request,
405                                          0,
406                                          0,
407                                          &ibufs,
408                                          0,
409                                          0,
410                                          &obufs,
411                                          &a,
412                                          &t );
413       //print_error(error, "handshake() ~ InitializeSecurityContext()");
414       if( error == SEC_E_OK )
415       {
416         // EXTRA STUFF??
417         if( ibuf[1].BufferType == SECBUFFER_EXTRA )
418         {
419           m_buffer.erase( 0, m_buffer.size() - ibuf[1].cbBuffer );
420         }
421         else
422         {
423           m_buffer = EmptyString;
424         }
425         setSizes();
426         setCertinfos();
427 
428         m_secure = true;
429         m_handler->handleHandshakeResult( this, true, m_certInfo );
430         break;
431       }
432       else if( error == SEC_I_CONTINUE_NEEDED )
433       {
434         /*
435          * std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n";
436          * std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n";
437          * std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n";
438          */
439 
440         // STUFF TO SEND??
441         if( obuf[0].cbBuffer != 0 && obuf[0].pvBuffer != NULL )
442         {
443           std::string senddata( static_cast<char*>(obuf[0].pvBuffer), obuf[0].cbBuffer );
444           FreeContextBuffer( obuf[0].pvBuffer );
445           m_handler->handleEncryptedData( this, senddata );
446         }
447         // EXTRA STUFF??
448         if( ibuf[1].BufferType == SECBUFFER_EXTRA )
449         {
450           m_buffer.erase( 0, m_buffer.size() - ibuf[1].cbBuffer );
451           // Call again if we aren't sending anything (otherwise the server will not send anything back
452           // and this function won't get called again to finish the processing).  This is needed for
453           // NT4.0 which does not seem to process the entire buffer the first time around
454           if( obuf[0].cbBuffer == 0 )
455             handshakeStage( EmptyString );
456         }
457         else
458         {
459           m_buffer = EmptyString;
460         }
461         return;
462       }
463       else if( error == SEC_I_INCOMPLETE_CREDENTIALS )
464       {
465         handshakeStage( EmptyString );
466       }
467       else if( error == SEC_E_INCOMPLETE_MESSAGE )
468       {
469         break;
470       }
471       else
472       {
473         cleanup();
474         m_handler->handleHandshakeResult( this, false, m_certInfo );
475         break;
476       }
477     }
478     while( true );
479   }
480 
hasChannelBinding() const481   bool SChannel::hasChannelBinding() const
482   {
483 #ifdef HAVE_WINTLS_CHANNEL_BINDING
484     return true;
485 #else
486     return false;
487 #endif
488   }
489 
channelBinding() const490   const std::string SChannel::channelBinding() const
491   {
492 #ifdef HAVE_WINTLS_CHANNEL_BINDING // see ../config.h.win if the following doesn't compile
493     SecPkgContext_Bindings buf;
494     if( QueryContextAttributes( &m_context, SECPKG_ATTR_UNIQUE_BINDINGS, &buf ) == SEC_E_OK )
495     {
496       return std::string( buf->Bindings[buf->Bindings.dwApplicationDataOffset], buf->Bindings.cbApplicationDataLength );
497     }
498 #endif
499     return EmptyString;
500   }
501 
setCACerts(const StringList &)502   void SChannel::setCACerts( const StringList& /*cacerts*/ ) {}
503 
setClientCert(const std::string &,const std::string &)504   void SChannel::setClientCert( const std::string& /*clientKey*/, const std::string& /*clientCerts*/ ) {}
505 
setSizes()506   void SChannel::setSizes()
507   {
508     if( QueryContextAttributes( &m_context, SECPKG_ATTR_STREAM_SIZES, &m_sizes ) == SEC_E_OK )
509     {
510       //std::cout << "set_sizes success\n";
511     }
512     else
513     {
514       //std::cout << "set_sizes no success\n";
515       cleanup();
516       m_handler->handleHandshakeResult( this, false, m_certInfo );
517     }
518   }
519 
filetime2int(FILETIME t)520   int SChannel::filetime2int( FILETIME t )
521   {
522     SYSTEMTIME stUTC;
523     FileTimeToSystemTime(&t, &stUTC);
524     std::tm ts;
525     ts.tm_year = stUTC.wYear - 1900;
526     ts.tm_mon = stUTC.wMonth - 1;
527     ts.tm_mday = stUTC.wDay;
528     ts.tm_hour = stUTC.wHour;
529     ts.tm_min = stUTC.wMinute;
530     ts.tm_sec = stUTC.wSecond;
531 
532     time_t unixtime;
533     if ( (unixtime = mktime(&ts)) == -1 )
534       unixtime = 0;
535     return (int)unixtime;
536   }
537 
validateCert()538   void SChannel::validateCert()
539   {
540     bool valid = false;
541     HTTPSPolicyCallbackData policyHTTPS;
542     CERT_CHAIN_POLICY_PARA policyParameter;
543     CERT_CHAIN_POLICY_STATUS policyStatus;
544 
545     PCCERT_CONTEXT remoteCertContext = NULL;
546     PCCERT_CHAIN_CONTEXT chainContext = NULL;
547     CERT_CHAIN_PARA chainParameter;
548     PSTR serverName = const_cast<char*>( m_server.c_str() );
549 
550     PWSTR uServerName = NULL;
551     DWORD csizeServerName;
552 
553     LPSTR Usages[] = {
554       szOID_PKIX_KP_SERVER_AUTH,
555       szOID_SERVER_GATED_CRYPTO,
556       szOID_SGC_NETSCAPE
557     };
558     DWORD cUsages = sizeof( Usages ) / sizeof( LPSTR );
559 
560     do
561     {
562       // Get server's certificate.
563       if( QueryContextAttributes( &m_context, SECPKG_ATTR_REMOTE_CERT_CONTEXT,
564                                   (PVOID)&remoteCertContext ) != SEC_E_OK )
565       {
566         //printf("Error querying remote certificate\n");
567         // !!! THROW SOME ERROR
568         break;
569       }
570 
571       // unicode conversation
572       // calculating unicode server name size
573       csizeServerName = MultiByteToWideChar( CP_ACP, 0, serverName, -1, NULL, 0 );
574       uServerName = reinterpret_cast<WCHAR *>( malloc( csizeServerName * sizeof( WCHAR ) ) );
575       if( uServerName == NULL )
576       {
577         //printf("SEC_E_INSUFFICIENT_MEMORY ~ Not enough memory!!!\n");
578         break;
579       }
580 
581       // convert into unicode
582       csizeServerName = MultiByteToWideChar( CP_ACP, 0, serverName, -1, uServerName, csizeServerName );
583       if( csizeServerName == 0 )
584       {
585         //printf("SEC_E_WRONG_PRINCIPAL\n");
586         break;
587       }
588 
589       // create the chain
590       ZeroMemory( &chainParameter, sizeof( chainParameter ) );
591       chainParameter.cbSize = sizeof( chainParameter );
592       chainParameter.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
593       chainParameter.RequestedUsage.Usage.cUsageIdentifier     = cUsages;
594       chainParameter.RequestedUsage.Usage.rgpszUsageIdentifier = Usages;
595 
596       if( !CertGetCertificateChain( NULL, remoteCertContext, NULL, remoteCertContext->hCertStore,
597                                     &chainParameter, 0, NULL, &chainContext ) )
598       {
599 //         DWORD status = GetLastError();
600 //         printf("Error 0x%x returned by CertGetCertificateChain!!!\n", status);
601         break;
602       }
603 
604       // validate the chain
605       ZeroMemory( &policyHTTPS, sizeof( HTTPSPolicyCallbackData ) );
606       policyHTTPS.cbStruct           = sizeof( HTTPSPolicyCallbackData );
607       policyHTTPS.dwAuthType         = AUTHTYPE_SERVER;
608       policyHTTPS.fdwChecks          = 0;
609       policyHTTPS.pwszServerName     = uServerName;
610 
611       memset( &policyParameter, 0, sizeof( policyParameter ) );
612       policyParameter.cbSize            = sizeof( policyParameter );
613       policyParameter.pvExtraPolicyPara = &policyHTTPS;
614 
615       memset( &policyStatus, 0, sizeof( policyStatus ) );
616       policyStatus.cbSize = sizeof( policyStatus );
617 
618       if( !CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL, chainContext, &policyParameter,
619                                              &policyStatus ) )
620       {
621 //         DWORD status = GetLastError();
622 //         printf("Error 0x%x returned by CertVerifyCertificateChainPolicy!!!\n", status);
623         break;
624       }
625 
626       if( policyStatus.dwError )
627       {
628         //printf("Trust Error!!!}n");
629         break;
630       }
631       valid = true;
632     }
633     while( false );
634     // cleanup
635     if( chainContext )
636       CertFreeCertificateChain( chainContext );
637     if( uServerName != 0 )
638       free( uServerName );
639     m_certInfo.chain = valid;
640   }
641 
connectionInfos()642   void SChannel::connectionInfos()
643   {
644     SecPkgContext_ConnectionInfo conn_info;
645 
646     memset( &conn_info, 0, sizeof( conn_info ) );
647 
648     if( QueryContextAttributes( &m_context, SECPKG_ATTR_CONNECTION_INFO, &conn_info ) == SEC_E_OK )
649     {
650       switch( conn_info.dwProtocol )
651       {
652         case SP_PROT_TLS1_CLIENT:
653           m_certInfo.protocol = "TLSv1";
654           break;
655         case SP_PROT_SSL3_CLIENT:
656           m_certInfo.protocol = "SSLv3";
657           break;
658         default:
659           m_certInfo.protocol = "unknown";
660       }
661 
662       switch( conn_info.aiCipher )
663       {
664         case CALG_3DES:
665           m_certInfo.cipher = "3DES";
666           break;
667         case CALG_AES_128:
668           m_certInfo.cipher = "AES_128";
669           break;
670         case CALG_AES_256:
671           m_certInfo.cipher = "AES_256";
672           break;
673         case CALG_DES:
674           m_certInfo.cipher = "DES";
675           break;
676         case CALG_RC2:
677           m_certInfo.cipher = "RC2";
678           break;
679         case CALG_RC4:
680           m_certInfo.cipher = "RC4";
681           break;
682         default:
683           m_certInfo.cipher = EmptyString;
684       }
685 
686       switch( conn_info.aiHash )
687       {
688         case CALG_MD5:
689           m_certInfo.mac = "MD5";
690           break;
691         case CALG_SHA:
692           m_certInfo.mac = "SHA";
693           break;
694         default:
695           m_certInfo.mac = EmptyString;
696       }
697     }
698   }
699 
certData()700   void SChannel::certData()
701   {
702     PCCERT_CONTEXT remoteCertContext = NULL;
703     CHAR certString[1000];
704 
705     // getting server's certificate
706     if( QueryContextAttributes( &m_context, SECPKG_ATTR_REMOTE_CERT_CONTEXT,
707                                 (PVOID)&remoteCertContext ) != SEC_E_OK )
708     {
709       return;
710     }
711 
712     // setting certificat's lifespan
713     m_certInfo.date_from = filetime2int( remoteCertContext->pCertInfo->NotBefore );
714     m_certInfo.date_to = filetime2int( remoteCertContext->pCertInfo->NotAfter );
715 
716     if( !CertNameToStrA( remoteCertContext->dwCertEncodingType,
717                         &remoteCertContext->pCertInfo->Subject,
718                         CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
719                         certString, sizeof( certString ) ) )
720     {
721       return;
722     }
723     m_certInfo.server = certString;
724 
725     if( !CertNameToStrA( remoteCertContext->dwCertEncodingType,
726                        &remoteCertContext->pCertInfo->Issuer,
727                        CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
728                        certString, sizeof( certString ) ) )
729     {
730       return;
731     }
732     m_certInfo.issuer = certString;
733   }
734 
setCertinfos()735   void SChannel::setCertinfos()
736   {
737     validateCert();
738     connectionInfos();
739     certData();
740   }
741 
742 #if 0
743   void SChannel::print_error( int errorcode, const char* place )
744   {
745     printf( "Win error at %s.\n", place );
746     switch( errorcode )
747     {
748       case SEC_E_OK:
749         printf( "\tValue:\tSEC_E_OK\n" );
750         printf( "\tDesc:\tNot really an error. Everything is fine.\n" );
751         break;
752       case SEC_E_INSUFFICIENT_MEMORY:
753         printf( "\tValue:\tSEC_E_INSUFFICIENT_MEMORY\n" );
754         printf( "\tDesc:\tThere is not enough memory available to complete the requested action.\n" );
755         break;
756       case SEC_E_INTERNAL_ERROR:
757         printf( "\tValue:\tSEC_E_INTERNAL_ERROR\n" );
758         printf( "\tDesc:\tAn error occurred that did not map to an SSPI error code.\n" );
759         break;
760       case SEC_E_NO_CREDENTIALS:
761         printf( "\tValue:\tSEC_E_NO_CREDENTIALS\n" );
762         printf( "\tDesc:\tNo credentials are available in the security package.\n" );
763         break;
764       case SEC_E_NOT_OWNER:
765         printf( "\tValue:\tSEC_E_NOT_OWNER\n" );
766         printf( "\tDesc:\tThe caller of the function does not have the necessary credentials.\n" );
767         break;
768       case SEC_E_SECPKG_NOT_FOUND:
769         printf( "\tValue:\tSEC_E_SECPKG_NOT_FOUND\n" );
770         printf( "\tDesc:\tThe requested security package does not exist. \n" );
771         break;
772       case SEC_E_UNKNOWN_CREDENTIALS:
773         printf( "\tValue:\tSEC_E_UNKNOWN_CREDENTIALS\n" );
774         printf( "\tDesc:\tThe credentials supplied to the package were not recognized.\n" );
775         break;
776       case SEC_E_INCOMPLETE_MESSAGE:
777         printf( "\tValue:\tSEC_E_INCOMPLETE_MESSAGE\n" );
778         printf( "\tDesc:\tData for the whole message was not read from the wire.\n" );
779         break;
780       case SEC_E_INVALID_HANDLE:
781         printf( "\tValue:\tSEC_E_INVALID_HANDLE\n" );
782         printf( "\tDesc:\tThe handle passed to the function is invalid.\n" );
783         break;
784       case SEC_E_INVALID_TOKEN:
785         printf( "\tValue:\tSEC_E_INVALID_TOKEN\n" );
786         printf( "\tDesc:\tThe error is due to a malformed input token, such as a token "
787                 "corrupted in transit...\n" );
788         break;
789       case SEC_E_LOGON_DENIED:
790         printf( "\tValue:\tSEC_E_LOGON_DENIED\n" );
791         printf( "\tDesc:\tThe logon failed.\n" );
792         break;
793       case SEC_E_NO_AUTHENTICATING_AUTHORITY:
794         printf( "\tValue:\tSEC_E_NO_AUTHENTICATING_AUTHORITY\n" );
795         printf( "\tDesc:\tNo authority could be contacted for authentication...\n" );
796         break;
797       case SEC_E_TARGET_UNKNOWN:
798         printf( "\tValue:\tSEC_E_TARGET_UNKNOWN\n" );
799         printf( "\tDesc:\tThe target was not recognized.\n" );
800         break;
801       case SEC_E_UNSUPPORTED_FUNCTION:
802         printf( "\tValue:\tSEC_E_UNSUPPORTED_FUNCTION\n" );
803         printf( "\tDesc:\tAn invalid context attribute flag (ISC_REQ_DELEGATE or "
804                 "ISC_REQ_PROMPT_FOR_CREDS)...\n" );
805         break;
806       case SEC_E_WRONG_PRINCIPAL:
807         printf( "\tValue:\tSEC_E_WRONG_PRINCIPAL\n" );
808         printf( "\tDesc:\tThe principal that received the authentication request "
809                 "is not the same as the...\n" );
810         break;
811       case SEC_I_COMPLETE_AND_CONTINUE:
812         printf( "\tValue:\tSEC_I_COMPLETE_AND_CONTINUE\n" );
813         printf( "\tDesc:\tThe client must call CompleteAuthToken and then pass the output...\n" );
814         break;
815       case SEC_I_COMPLETE_NEEDED:
816         printf( "\tValue:\tSEC_I_COMPLETE_NEEDED\n" );
817         printf( "\tDesc:\tThe client must finish building the message and then "
818                 "call the CompleteAuthToken function.\n" );
819         break;
820       case SEC_I_CONTINUE_NEEDED:
821         printf( "\tValue:\tSEC_I_CONTINUE_NEEDED\n" );
822         printf( "\tDesc:\tThe client must send the output token to the server "
823                 "and wait for a return token...\n" );
824         break;
825       case SEC_I_INCOMPLETE_CREDENTIALS:
826         printf( "\tValue:\tSEC_I_INCOMPLETE_CREDENTIALS\n" );
827         printf( "\tDesc:\tThe server has requested client authentication, "
828                 "and the supplied credentials either...\n" );
829         break;
830       default:
831         printf( "\tValue:\t%d\n", errorcode );
832         printf( "\tDesc:\tUnknown error code.\n" );
833     }
834   }
835 #endif
836 
837 }
838 
839 #endif // HAVE_WINTLS
840