⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cryptses.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*						cryptlib Secure Session Routines					*
*						Copyright Peter Gutmann 1998-2002					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
  #include "stream.h"
  #include "session.h"
#else
  #include "keymgmt/stream.h"
  #include "session/session.h"
#endif /* Compiler-specific includes */

/* Some session types aren't supported on some platforms so we alias the 
   calls out */

#ifndef NET_TCP
  #define setAccessMethodSSL( x )		CRYPT_ARGERROR_NUM1
  #define setAccessMethodSSH( x )		CRYPT_ARGERROR_NUM1
  #define setAccessMethodCMP( x )		CRYPT_ARGERROR_NUM1
  #define setAccessMethodOCSP( x )		CRYPT_ARGERROR_NUM1
  #define setAccessMethodTSP( x )		CRYPT_ARGERROR_NUM1
#endif /* NET_TCP */

/****************************************************************************
*																			*
*								Get/Put Data Functions						*
*																			*
****************************************************************************/

/* Common code to read and write data over the secure connection.  This
   is called by the protocol-specific handlers, which supply three functions:

	readHeaderFunction()	- Reads the header for a packet and sets up
							  length information.
	processBodyFunction()	- Processes the body of a packet.
	writeDataFunction()		- Wraps and sends a packet.
   
   The read data code uses a help function which either reads everything 
   which is available or to the end of the current packet.  If it runs out 
   of data before reading the end of the packet it returns 0, otherwise it 
   returns a positive value to indicate that it's read a complete packet and 
   should be called again to try for further packets.
   
   Buffer management is handled as follows: The bPos index always points to
   the end of the decoded data (ie data which can be used by the user), if
   there's no partial packet present this index is the same as bEnd:

	----+------------------------
	////|
	----+------------------------
		^
		|
	  bEnd/bPos

   If there's a partial packet present, bEnd points to the end of the 
   received data, and is advanced as more data is read:

	----+-----+-------------+----
	////| hdr |/////////////|....
	----+-----+-------------+----
		^					^
		|					|
	  bPos				  bEnd

   Once the complete packet is read, it's decrypted and moved down to bPos, 
   and bPos and bEnd are adjusted to point to the end of the new data */

static int tryRead( SESSION_INFO *sessionInfoPtr )
	{
	int status;

	/* If there's no pending packet information present, try and read it */
	if( !sessionInfoPtr->pendingPacketLength )
		{
		status = sessionInfoPtr->readHeaderFunction( sessionInfoPtr );
		if( status <= 0 ) 
			{
			/* Some protocols treat the header information for a secured 
			   data packet as part of the data to be secured and some don't.  
			   When we read the header and don't want it to be processed as 
			   part of the packet, we indicate this by returning OK_SPECIAL */
			if( status != OK_SPECIAL )
				return( status );
			}
		else
			{
			sessionInfoPtr->receiveBufEnd += status;
			sessionInfoPtr->pendingPacketPartialLength = status;
			sessionInfoPtr->pendingPacketRemaining -= status;
			}
		}

	/* If there's not enough room in the receive buffer to read at least 1K 
	   of packet data, don't try anything until the user has emptied more 
	   data from the buffer */
	if( sessionInfoPtr->receiveBufSize - sessionInfoPtr->receiveBufEnd < \
		min( sessionInfoPtr->pendingPacketRemaining, 1024 ) )
		return( 0 );

	/* Try and read more of the packet */
	status = sread( &sessionInfoPtr->stream, 
					sessionInfoPtr->receiveBuffer + sessionInfoPtr->receiveBufEnd, 
					sessionInfoPtr->pendingPacketRemaining );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream, 
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}
	if( status == 0 )
		/* Nothing read, try again later */
		return( 0 );
	sessionInfoPtr->receiveBufEnd += status;
	sessionInfoPtr->pendingPacketRemaining -= status;
	if( sessionInfoPtr->pendingPacketRemaining > 0 )
		/* We got some but not all of the data, try again later */
		return( 0 );

	/* We've got a complete packet in the buffer, process it */
	return( sessionInfoPtr->processBodyFunction( sessionInfoPtr ) );
	}

/* Get data from the remote system */

static int getData( SESSION_INFO *sessionInfoPtr, void *data, 
					const int length )
	{
	int bytesToCopy = length, remainder, timeout, savedTimeout, status;

	/* If there's an error pending and we've exhausted what was still present
	   from earlier reads, set the current error state to the pending state
	   and return */
	if( cryptStatusError( sessionInfoPtr->pendingErrorState ) && \
		!sessionInfoPtr->receiveBufPos )
		return( sessionInfoPtr->pendingErrorState );

	/* Set the stream to the appropriate timeout value (usually zero so we 
	   can see whether there's anything there without blocking, but kul 
	   takhira fi'khira) and see if there's any more data available to 
	   return to the user.  We save the previous value around the access in 
	   case other administrative code needs to perform reads without being 
	   affected by a user-set timeout */
	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_GETTIMEOUT, 
			&savedTimeout, 0 );
	krnlSendMessage( sessionInfoPtr->ownerHandle, 
					 RESOURCE_IMESSAGE_GETATTRIBUTE, &timeout, 
					 CRYPT_OPTION_NET_TIMEOUT );
	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL, timeout );

	do
		{
		status = tryRead( sessionInfoPtr );
		if( status > 0 )
			/* If we've got some data to return to the caller, reset the 
			   stream to be nonblocking.  This is necessary to avoid having
			   the stream always block for the set timeout value on the last
			   read */
			sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL, 0 );
		}
	while( status > 0 );
	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL, 
			savedTimeout );
	if( cryptStatusError( status ) )
		{
		/* If there's an error reading data, only return an error status if
		   there's no further data in the buffer which can be returned, this
		   lets the caller drain out any remaining data from the session
		   buffer before they start getting error returns */
		sessionInfoPtr->pendingErrorState = status;
		if( sessionInfoPtr->receiveBufPos <= 0 )
			return( status );
		}

	/* Adjust the data to copy length by the amount we have available */
	if( bytesToCopy > sessionInfoPtr->receiveBufPos )
		bytesToCopy = sessionInfoPtr->receiveBufPos;

	/* Copy the data across and move any remaining data down to the start of 
	   the receive buffer */
	memcpy( data, sessionInfoPtr->receiveBuffer, bytesToCopy );
	remainder = sessionInfoPtr->receiveBufEnd - bytesToCopy;
	if( remainder )
		memmove( sessionInfoPtr->receiveBuffer, 
				 sessionInfoPtr->receiveBuffer + bytesToCopy, remainder );
	sessionInfoPtr->receiveBufPos -= bytesToCopy;
	sessionInfoPtr->receiveBufEnd = remainder;
	
	return( bytesToCopy );
	}

/* Send data to the remote system */

static int putData( SESSION_INFO *sessionInfoPtr, const void *data,
					const int length )
	{
	BYTE *dataPtr = ( BYTE * ) data;
	int dataLength = length;

	assert( sessionInfoPtr->sendBufPos >= 4 && \
			sessionInfoPtr->sendBufPos <= sessionInfoPtr->sendBufSize );

	/* If it's a flush, send the data through to the server */
	if( !dataLength )
		return( sessionInfoPtr->writeDataFunction( sessionInfoPtr ) );

	/* If there's too much data to fit in the buffer, send it through to the
	   host */
	while( dataLength >= sessionInfoPtr->sendBufSize - \
						 sessionInfoPtr->sendBufPos )
		{
		const int bytesToCopy = sessionInfoPtr->sendBufSize - \
								sessionInfoPtr->sendBufPos;
		int status;

		assert( bytesToCopy >= 0 && bytesToCopy <= dataLength );

		/* Copy in as much data as we have room for and send it through */
		memcpy( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufPos,
				dataPtr, bytesToCopy );
		dataPtr += bytesToCopy;
		dataLength -= bytesToCopy;
		status = sessionInfoPtr->writeDataFunction( sessionInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If there's anything left, it'll fit in the buffer, just copy it in */
	if( dataLength > 0 )
		{
		assert( dataLength < sessionInfoPtr->sendBufSize - \
							 sessionInfoPtr->sendBufPos );

		memcpy( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufPos, 
				dataPtr, dataLength );
		sessionInfoPtr->sendBufPos += dataLength;
		}

	return( length );
	}

/****************************************************************************
*																			*
*							General Session API Functions					*
*																			*
****************************************************************************/

/* Handle data sent to or read from a session object */

static int processGetAttribute( SESSION_INFO *sessionInfoPtr,
								void *messageDataPtr, const int messageValue )
	{
	int *valuePtr = ( int * ) messageDataPtr;

	/* Handle the various information types */
	switch( messageValue )
		{
		case CRYPT_ATTRIBUTE_ERRORTYPE:
			*valuePtr = sessionInfoPtr->errorType;
			return( CRYPT_OK );

		case CRYPT_ATTRIBUTE_ERRORLOCUS:
			*valuePtr = sessionInfoPtr->errorLocus;
			return( CRYPT_OK );

		case CRYPT_ATTRIBUTE_BUFFERSIZE:
			*valuePtr = sessionInfoPtr->receiveBufSize;
			return( CRYPT_OK );

		case CRYPT_ATTRIBUTE_INT_ERRORCODE:
			*valuePtr = sessionInfoPtr->errorCode;
			return( CRYPT_OK );

		case CRYPT_SESSINFO_ACTIVE:
			*valuePtr = sessionInfoPtr->sessionOpen;
			return( CRYPT_OK );

		case CRYPT_SESSINFO_SERVER_PORT:
			*valuePtr = sessionInfoPtr->serverPort;
			return( CRYPT_OK );

		case CRYPT_SESSINFO_CLIENT_PORT:
			if( !sessionInfoPtr->clientPort )
				return( CRYPT_ERROR_NOTINITED );
			*valuePtr = sessionInfoPtr->clientPort;
			return( CRYPT_OK );

		case CRYPT_SESSINFO_PROTOCOLVERSION:
			*valuePtr = sessionInfoPtr->version;
			return( CRYPT_OK );
		}

	assert( NOTREACHED );
	return( CRYPT_ERROR );	/* Get rid of compiler warning */
	}

static int processSetAttribute( SESSION_INFO *sessionInfoPtr,
								void *messageDataPtr, const int messageValue )
	{
	const int value = *( int * ) messageDataPtr;
	int status;

	/* Handle the various information types */
	switch( messageValue )
		{
		case CRYPT_ATTRIBUTE_BUFFERSIZE:
			assert( !sessionInfoPtr->sessionOpen );
			sessionInfoPtr->receiveBufSize = value;
			return( CRYPT_OK );

		case CRYPT_SESSINFO_ACTIVE:
			assert( !sessionInfoPtr->sessionOpen );
			if( value == FALSE )
				return( CRYPT_OK );	/* Noop */

			/* Make sure everything is set up ready to go */
			if( !sessionInfoPtr->serverPort )
				{
				setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_SERVER_PORT, 
							  CRYPT_ERRTYPE_ATTR_ABSENT );
				return( CRYPT_ERROR_NOTINITED );
				}
			if( sessionInfoPtr->flags & SESSION_ISSERVER )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -