📄 tlsschannel.cpp
字号:
/* * Copyright (c) 2007-2008 by Jakob Schroeter <js@camaya.net> * This file is part of the gloox library. http://camaya.net/gloox * * This software is distributed under a license. The full license * agreement can be found in the file LICENSE in this distribution. * This software may not be copied, modified, sold or distributed * other than expressed in the named license agreement. * * This software is distributed without any warranty. */#include "tlsschannel.h"#ifdef HAVE_WINTLS#include <stdio.h> // just for debugging output#include <iostream>namespace gloox{ SChannel::SChannel( TLSHandler* th, const std::string& server ) : TLSBase( th, server ), m_cleanedup( true ) { //printf(">> SChannel::SChannel()\n"); } SChannel::~SChannel() { m_handler = 0; cleanup(); //printf(">> SChannel::~SChannel()\n"); } bool SChannel::encrypt( const std::string& data ) { if( !m_handler ) return false; //printf(">> SChannel::encrypt()\n"); std::string data_copy = data; SecBuffer buffer[4]; SecBufferDesc buffer_desc; DWORD cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer; PBYTE e_iobuffer = static_cast<PBYTE>( LocalAlloc( LMEM_FIXED, cbIoBufferLength ) ); if( e_iobuffer == NULL ) { //printf("**** Out of memory (2)\n"); cleanup(); if( !m_secure ) m_handler->handleHandshakeResult( this, false, m_certInfo ); return false; } PBYTE e_message = e_iobuffer + m_sizes.cbHeader; do { const int size = data_copy.size() > m_sizes.cbMaximumMessage ? m_sizes.cbMaximumMessage : data_copy.size(); memcpy( e_message, data_copy.data(), size ); if( data_copy.size() > m_sizes.cbMaximumMessage ) data_copy.erase( 0, m_sizes.cbMaximumMessage ); else data_copy = ""; buffer[0].pvBuffer = e_iobuffer; buffer[0].cbBuffer = m_sizes.cbHeader; buffer[0].BufferType = SECBUFFER_STREAM_HEADER; buffer[1].pvBuffer = e_message; buffer[1].cbBuffer = size; buffer[1].BufferType = SECBUFFER_DATA; buffer[2].pvBuffer = static_cast<char*>(buffer[1].pvBuffer) + buffer[1].cbBuffer; buffer[2].cbBuffer = m_sizes.cbTrailer; buffer[2].BufferType = SECBUFFER_STREAM_TRAILER; buffer[3].BufferType = SECBUFFER_EMPTY; buffer_desc.ulVersion = SECBUFFER_VERSION; buffer_desc.cBuffers = 4; buffer_desc.pBuffers = buffer; SECURITY_STATUS e_status = EncryptMessage( &m_context, 0, &buffer_desc, 0 ); if( SUCCEEDED( e_status ) ) { std::string encrypted( reinterpret_cast<const char*>(e_iobuffer), buffer[0].cbBuffer + buffer[1].cbBuffer + buffer[2].cbBuffer ); m_handler->handleEncryptedData( this, encrypted ); //if (data_copy.size() <= m_sizes.cbMaximumMessage) data_copy = ""; } else { LocalFree( e_iobuffer ); cleanup(); if( !m_secure ) m_handler->handleHandshakeResult( this, false, m_certInfo ); return false; } } while( data_copy.size() > 0 ); LocalFree( e_iobuffer ); return true; } int SChannel::decrypt( const std::string& data ) { if( !m_handler ) return 0; //printf(">> SChannel::decrypt()\n"); if( m_secure ) { m_buffer += data; SecBuffer buffer[4]; SecBufferDesc buffer_desc; DWORD cbIoBufferLength = m_sizes.cbHeader + m_sizes.cbMaximumMessage + m_sizes.cbTrailer; PBYTE e_iobuffer = static_cast<PBYTE>( LocalAlloc( LMEM_FIXED, cbIoBufferLength ) ); if( e_iobuffer == NULL ) { //printf("**** Out of memory (2)\n"); cleanup(); if( !m_secure ) m_handler->handleHandshakeResult( this, false, m_certInfo ); return 0; } SECURITY_STATUS e_status; // copy data chunk from tmp string into encryption memory buffer do { memcpy( e_iobuffer, m_buffer.data(), m_buffer.size() > cbIoBufferLength ? cbIoBufferLength : m_buffer.size() ); buffer[0].pvBuffer = e_iobuffer; buffer[0].cbBuffer = m_buffer.size() > cbIoBufferLength ? cbIoBufferLength : m_buffer.size(); buffer[0].BufferType = SECBUFFER_DATA; buffer[1].cbBuffer = buffer[2].cbBuffer = buffer[3].cbBuffer = 0; buffer[1].BufferType = buffer[2].BufferType = buffer[3].BufferType = SECBUFFER_EMPTY; buffer_desc.ulVersion = SECBUFFER_VERSION; buffer_desc.cBuffers = 4; buffer_desc.pBuffers = buffer; unsigned long processed_data = buffer[0].cbBuffer; e_status = DecryptMessage( &m_context, &buffer_desc, 0, 0 ); // print_error(e_status, "decrypt() ~ DecryptMessage()"); // for (int n=0; n<4; n++) // printf("buffer[%d].cbBuffer: %d \t%d\n", n, buffer[n].cbBuffer, buffer[n].BufferType); // Locate data and (optional) extra buffers. SecBuffer* pDataBuffer = NULL; SecBuffer* pExtraBuffer = NULL; for( int i = 1; i < 4; i++ ) { if( pDataBuffer == NULL && buffer[i].BufferType == SECBUFFER_DATA ) { pDataBuffer = &buffer[i]; //printf("buffer[%d].BufferType = SECBUFFER_DATA\n",i); } if( pExtraBuffer == NULL && buffer[i].BufferType == SECBUFFER_EXTRA ) { pExtraBuffer = &buffer[i]; } } if( e_status == SEC_E_OK ) { std::string decrypted( reinterpret_cast<const char*>( pDataBuffer->pvBuffer ), pDataBuffer->cbBuffer ); m_handler->handleDecryptedData( this, decrypted ); if( pExtraBuffer == NULL ) { m_buffer.erase( 0, processed_data ); } else { //std::cout << "m_buffer.size() = " << pExtraBuffer->cbBuffer << std::endl; m_buffer.erase( 0, m_buffer.size() - pExtraBuffer->cbBuffer ); //std::cout << "m_buffer.size() = " << m_buffer.size() << std::endl; } } else if( e_status == SEC_E_INCOMPLETE_MESSAGE ) { break; } else { //std::cout << "decrypt !!!ERROR!!!\n"; cleanup(); if( !m_secure ) m_handler->handleHandshakeResult( this, false, m_certInfo ); break; } } while( m_buffer.size() != 0 ); LocalFree( e_iobuffer ); } else { handshakeStage( data ); } //printf("<< SChannel::decrypt()\n"); return 0; } void SChannel::cleanup() { m_buffer = ""; if( !m_cleanedup ) { m_valid = false; m_secure = false; m_cleanedup = true; DeleteSecurityContext( &m_context ); FreeCredentialsHandle( &m_credHandle ); } } bool SChannel::handshake() { if( !m_handler ) return false; //printf(">> SChannel::handshake()\n"); SECURITY_STATUS error; ULONG return_flags; TimeStamp t; SecBuffer obuf[1]; SecBufferDesc obufs; SCHANNEL_CRED tlscred; ULONG request = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_EXTENDED_ERROR | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_MANUAL_CRED_VALIDATION; /* initialize TLS credential */ memset( &tlscred, 0, sizeof( SCHANNEL_CRED ) ); tlscred.dwVersion = SCHANNEL_CRED_VERSION; tlscred.grbitEnabledProtocols = SP_PROT_TLS1; /* acquire credentials */ error = AcquireCredentialsHandle( 0, UNISP_NAME, SECPKG_CRED_OUTBOUND, 0, &tlscred, 0, 0, &m_credHandle, &t ); //print_error(error, "handshake() ~ AcquireCredentialsHandle()"); if( error != SEC_E_OK ) { cleanup(); m_handler->handleHandshakeResult( this, false, m_certInfo ); return false; } else { /* initialize buffers */ obuf[0].cbBuffer = 0; obuf[0].pvBuffer = 0; obuf[0].BufferType = SECBUFFER_TOKEN; /* initialize buffer descriptors */ obufs.ulVersion = SECBUFFER_VERSION; obufs.cBuffers = 1; obufs.pBuffers = obuf; /* negotiate security */ SEC_CHAR* hname = const_cast<char*>( m_server.c_str() ); error = InitializeSecurityContext( &m_credHandle, 0, hname, request, 0, SECURITY_NETWORK_DREP, 0, 0, &m_context, &obufs, &return_flags, NULL ); //print_error(error, "handshake() ~ InitializeSecurityContext()"); if( error == SEC_I_CONTINUE_NEEDED ) { m_cleanedup = false; //std::cout << "obuf[1].cbBuffer: " << obuf[0].cbBuffer << "\n"; std::string senddata( static_cast<char*>(obuf[0].pvBuffer), obuf[0].cbBuffer ); FreeContextBuffer( obuf[0].pvBuffer ); m_handler->handleEncryptedData( this, senddata ); return true; } else { cleanup(); m_handler->handleHandshakeResult( this, false, m_certInfo ); return false; } } return true; } void SChannel::handshakeStage( const std::string& data ) { //printf(" >> handshake_stage\n"); m_buffer += data; SECURITY_STATUS error; ULONG a; TimeStamp t; SecBuffer ibuf[2], obuf[1]; SecBufferDesc ibufs, obufs; ULONG request = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_EXTENDED_ERROR | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_MANUAL_CRED_VALIDATION; SEC_CHAR* hname = const_cast<char*>( m_server.c_str() ); do { /* initialize buffers */ ibuf[0].cbBuffer = m_buffer.size(); ibuf[0].pvBuffer = static_cast<void*>( const_cast<char*>( m_buffer.c_str() ) ); //std::cout << "Size: " << m_buffer.size() << "\n"; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = 0; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = 0; ibuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; obuf[0].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* * std::cout << "obuf[0].cbBuffer: " << obuf[0].cbBuffer << "\t" << obuf[0].BufferType << "\n"; * std::cout << "ibuf[0].cbBuffer: " << ibuf[0].cbBuffer << "\t" << ibuf[0].BufferType << "\n"; * std::cout << "ibuf[1].cbBuffer: " << ibuf[1].cbBuffer << "\t" << ibuf[1].BufferType << "\n"; */ /* negotiate security */ error = InitializeSecurityContext( &m_credHandle, &m_context, hname, request, 0, 0, &ibufs, 0, 0, &obufs, &a, &t ); //print_error(error, "handshake() ~ InitializeSecurityContext()"); if( error == SEC_E_OK ) { // EXTRA STUFF?? if( ibuf[1].BufferType == SECBUFFER_EXTRA ) { m_buffer.erase( 0, m_buffer.size() - ibuf[1].cbBuffer ); } else { m_buffer = ""; } setSizes();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -