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

📄 cryptses.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
			   no-op packet was read and the caller should try again without 
			   changing the read timeout value.
			4. A byte count if a complete packet was read and processed */
		status = tryRead( sessionInfoPtr, &readInfo );
		if( cryptStatusError( status ) && status != OK_SPECIAL )
			{
			/* If there's an error reading data, only return an error status
			   if we haven't already returned existing/earlier data.  This 
			   ensures that the caller can drain out any remaining data from 
			   the session buffer before they start getting error returns */
			if( bytesCopied <= 0 )
				{
				bytesCopied = status;
				if( readInfo == READINFO_FATAL )
					sessionInfoPtr->readErrorState = status;
				}
			else
				/* If it's a fatal error, save the pending error state for 
				   later while returning the read byte count to the caller.
				   Note that this results in non-fatal errors being quietly 
				   dropped if data is otherwise available, the alternative 
				   would be to save it as a pending (specially-marked) non-
				   fatal error, however since this error type by definition 
				   can be resumed it may already have resolved itself by the 
				   next time we're called, so this is safe to do */
				if( readInfo == READINFO_FATAL )
					sessionInfoPtr->pendingErrorState = status;
			break;
			}
		if( status == 0 )
			/* We got nothing, exit */
			break;
		if( status == OK_SPECIAL )
			{
			/* If we read a partial packet and there's room for the rest of 
			   the packet in the buffer, set a minimum timeout to try and 
			   get the rest of the packet.  This is safe because tryRead() 
			   could have behaved in only one of two ways:

				1. Blocking read, in which case we waited for the full 
				   timeout period anyway and a small additional timeout 
				   won't be noticed.
				2. Nonblocking read, in which case waiting for a nonzero 
				   time could potentially have retrieved more data */
			assert( readInfo == READINFO_PARTIAL || \
					readInfo == READINFO_NOOP );
			if( readInfo == READINFO_PARTIAL && \
				sessionInfoPtr->pendingPacketRemaining <= \
				sessionInfoPtr->receiveBufSize - sessionInfoPtr->receiveBufEnd )
				sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL, 1 );
			}
		else
			{
			/* Make the stream nonblocking if it was blocking before.  This is 
			   necessary to avoid having the stream always block for the set 
			   timeout value on the last read */
			assert( status > 0 );
			sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL, 0 );
			}

		assert( sessionInfoPtr->receiveBufEnd <= \
				sessionInfoPtr->receiveBufSize );
		assert( sessionInfoPtr->receiveBufPos <= \
				sessionInfoPtr->receiveBufEnd );
		}

	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL,
			savedTimeout );
	return( bytesCopied );
	}

/* Send data to the remote system.  Session buffer management is handled as
   follows: The startOfs index points to the start of the payload space in 
   the buffer (everything before this is header data).  The maxPos index 
   points to the end of the payload space relative to the start of the buffer.
   This is needed for cases where the packet size is smaller than the buffer
   size:

	<- hdr->|<-- payload -->|
	+-------+---------------+---+
	|		|///////////////|	|
	+-------+---------------+---+
			^				^
			|				|
		startOfs		  maxPos

   The bPos index moves from startsOfs to maxPos, after which the data is
   flushed and the bPos index reset */

static int putData( SESSION_INFO *sessionInfoPtr, const void *data,
					const int length )
	{
	const PROTOCOL_INFO *protocolInfoPtr = sessionInfoPtr->protocolInfo;
	BYTE *dataPtr = ( BYTE * ) data;
	int dataLength = length;

	assert( sessionInfoPtr->sendBufPos >= sessionInfoPtr->sendBufStartOfs && \
			sessionInfoPtr->sendBufPos <= protocolInfoPtr->sendBufMaxPos );

	/* If it's a flush, send the data through to the server and restart at
	   the start of the buffer payload space */
	if( dataLength <= 0 )
		{
		int status;

		if( sessionInfoPtr->sendBufPos <= sessionInfoPtr->sendBufStartOfs )
			return( CRYPT_OK );	/* There's no data to flush, exit */
		status = sessionInfoPtr->writeDataFunction( sessionInfoPtr );
		sessionInfoPtr->sendBufPos = sessionInfoPtr->sendBufStartOfs;
		if( cryptStatusError( status ) )
			sessionInfoPtr->writeErrorState = status;
		return( status );
		}

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

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

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

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

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

	return( length );
	}

/* Read a fixed-size packet header, called by the secure data session 
   routines to read the fixed header on a data packet.  This is an atomic 
   read of out-of-band data that isn't part of the packet payload, so we 
   have to make sure that we've got the entire header before we can 
   continue:

		| <- hdrSize ->	|
	----+---------------+--------
	////|				|
	----+---------------+--------
		^		^
		|		|
	  bEnd	partialHdr 

   The data is read into the read buffer starting at the end of the last 
   payload packet bEnd (this is safe because this function causes a 
   pipeline stall so no more data can be read until the header has been
   read), the function returns CRYPT_ERROR_TIMEOUT until partialHdr reaches 
   the full header size */

int readFixedHeader( SESSION_INFO *sessionInfoPtr, const int headerSize )
	{
	BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
				   sessionInfoPtr->receiveBufEnd;
	int status;

	/* If it's the first attempt at reading the header, set the total byte
	   count */
	if( sessionInfoPtr->partialHeaderLength <= 0 )
		sessionInfoPtr->partialHeaderLength = headerSize;
	else
		bufPtr += headerSize - sessionInfoPtr->partialHeaderLength;

	assert( sessionInfoPtr->partialHeaderLength > 0 && \
			sessionInfoPtr->partialHeaderLength <= headerSize );

	/* Clear the first few bytes of returned data to make sure that the 
	   higher-level code always bails out if the read fails for some reason 
	   without returning an error status */
	memset( bufPtr, 0, min( headerSize, 8 ) );

	/* Try and read the remaining header bytes */
	status = sread( &sessionInfoPtr->stream, bufPtr, 
					sessionInfoPtr->partialHeaderLength );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}

	/* If we didn't get the whole header, treat it as a timeout error */
	if( status < sessionInfoPtr->partialHeaderLength )
		{
		/* If we timed out during the handshake phase, treat it as a hard 
		   timeout error */
		if( !( sessionInfoPtr->flags & SESSION_ISOPEN ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_TIMEOUT,
					"Timeout during packet header read, only got %d of %d "
					"bytes", status, headerSize );

		/* We're in the data-processing stage, it's a soft timeout error */
		sessionInfoPtr->partialHeaderLength -= status;
		return( 0 );
		}

	/* We've got the whole header ready to process */
	assert( sessionInfoPtr->partialHeaderLength == status );
	sessionInfoPtr->partialHeaderLength = 0;
	return( headerSize );
	}

/****************************************************************************
*																			*
*				Request/response Session Data Handling Functions			*
*																			*
****************************************************************************/

/* Read/write a PKI (i.e.ASN.1-encoded) datagram */

int readPkiDatagram( SESSION_INFO *sessionInfoPtr )
	{
	int length, status;

	assert( isWritePtr( sessionInfoPtr, SESSION_INFO ) );

	/* Read the datagram */
	sessionInfoPtr->receiveBufEnd = 0;
	status = sread( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer, 
					sessionInfoPtr->receiveBufSize );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}
	if( status < 4 )
		/* Perform a sanity check on the length.  This avoids some 
		   assertions in the debug build, and provides somewhat more 
		   specific information for the caller than the invalid encoding
		   error that we'd get later */
		retExt( sessionInfoPtr, CRYPT_ERROR_UNDERFLOW, 
				"Invalid PKI message length %d", status );

	/* Find out how much data we got and perform a firewall check that
	   everything is OK.  We rely on this rather than the read byte count
	   since checking the ASN.1, which is the data that will actually be
	   processed, avoids any vagaries of server implementation oddities */
	length = checkObjectEncoding( sessionInfoPtr->receiveBuffer, status );
	if( cryptStatusError( length ) )
		retExt( sessionInfoPtr, length, "Invalid PKI message encoding" );
	sessionInfoPtr->receiveBufEnd = length;
	return( CRYPT_OK );
	}

int writePkiDatagram( SESSION_INFO *sessionInfoPtr )
	{
	int status;

	assert( isWritePtr( sessionInfoPtr, SESSION_INFO ) );
	assert( sessionInfoPtr->receiveBufEnd > 4 );

	/* Write the datagram */
	status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer, 
					 sessionInfoPtr->receiveBufEnd );
	if( cryptStatusError( status ) )
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
	sessionInfoPtr->receiveBufEnd = 0;
	return( status );
	}

/****************************************************************************
*																			*
*						Session Attribute Handling 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_OPTION_NET_CONNECTTIMEOUT:
			if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
				return( exitErrorNotInited( sessionInfoPtr,
											CRYPT_ERROR_NOTINITED ) );
			*valuePtr = sessionInfoPtr->connectTimeout;
			return( CRYPT_OK );

		case CRYPT_OPTION_NET_TIMEOUT:
			if( sessionInfoPtr->timeout == CRYPT_ERROR )
				return( exitErrorNotInited( sessionInfoPtr,
											CRYPT_ERROR_NOTINITED ) );
			*valuePtr = sessionInfoPtr->timeout;
			return( CRYPT_OK );

		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:
			/* Only secure transport sessions can be persistently active,
			   request/response sessions are only active while the 
			   transaction is in progress */
			*valuePtr = sessionInfoPtr->iCryptInContext != CRYPT_ERROR && \
						( sessionInfoPtr->flags & SESSION_ISOPEN ) ? \
						TRUE : FALSE;
			return( CRYPT_OK );

		case CRYPT_SESSINFO_CONNECTIONACTIVE:
			*valuePtr = ( sessionInfoPtr->flags & SESSION_ISOPEN ) ? \
						TRUE : FALSE;
			return( CRYPT_OK );

⌨️ 快捷键说明

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