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

📄 cryptses.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						cryptlib Secure Session Routines					*
*						Copyright Peter Gutmann 1998-2003					*
*																			*
****************************************************************************/

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

#ifdef USE_SESSIONS

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Exit after setting extended error information */

static int exitError( SESSION_INFO *sessionInfoPtr,
					  const CRYPT_ATTRIBUTE_TYPE errorLocus,
					  const CRYPT_ERRTYPE_TYPE errorType, const int status )
	{
	setErrorInfo( sessionInfoPtr, errorLocus, errorType );
	return( status );
	}

static int exitErrorInited( SESSION_INFO *sessionInfoPtr,
							const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( sessionInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_PRESENT,
					   CRYPT_ERROR_INITED ) );
	}

static int exitErrorNotInited( SESSION_INFO *sessionInfoPtr,
							   const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( sessionInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
					   CRYPT_ERROR_NOTINITED ) );
	}

static int exitErrorNotFound( SESSION_INFO *sessionInfoPtr,
							  const CRYPT_ATTRIBUTE_TYPE errorLocus )
	{
	return( exitError( sessionInfoPtr, errorLocus, CRYPT_ERRTYPE_ATTR_ABSENT,
					   CRYPT_ERROR_NOTFOUND ) );
	}

/* Exit after saving a detailed error message.  This is used by lower-level 
   session code to provide more information to the caller than a basic error 
   code */

int retExtFnSession( SESSION_INFO *sessionInfoPtr, const int status, 
					 const char *format, ... )
	{
	va_list argPtr;

	va_start( argPtr, format );
	vsprintf( sessionInfoPtr->errorMessage, format, argPtr ); 
	va_end( argPtr );
	assert( !cryptArgError( status ) );	/* Catch leaks */
	return( cryptArgError( status ) ? CRYPT_ERROR_FAILED : status );
	}

/* Initialise network connection information based on the contents of the 
   session object */

void initSessionNetConnectInfo( const SESSION_INFO *sessionInfoPtr,
								NET_CONNECT_INFO *connectInfo )
	{
	initNetConnectInfo( connectInfo, sessionInfoPtr->ownerHandle, 
				sessionInfoPtr->timeout, sessionInfoPtr->connectTimeout, 
				( sessionInfoPtr->transportSession != CRYPT_ERROR ) ? \
					NET_OPTION_TRANSPORTSESSION : \
				( sessionInfoPtr->networkSocket != CRYPT_ERROR ) ? \
					NET_OPTION_NETWORKSOCKET : \
					NET_OPTION_HOSTNAME );
	if( sessionInfoPtr->serverName[ 0 ] )
		connectInfo->name = sessionInfoPtr->serverName;
	connectInfo->port = sessionInfoPtr->serverPort;
	connectInfo->iCryptSession = sessionInfoPtr->transportSession;
	connectInfo->networkSocket = sessionInfoPtr->networkSocket;
	}

/* Activate the network connection for a session */

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

	/* Make sure that everything is set up ready to go */
	if( sessionInfoPtr->flags & SESSION_ISSERVER )
		{
		/* Check server-specific required values */
		if( ( sessionInfoPtr->serverReqAttrFlags & \
			  SESSION_NEEDS_PRIVATEKEY ) && \
			sessionInfoPtr->privateKey == CRYPT_ERROR )
			{
			/* There's no private key present, see if we can use a username
			   and password as an alternative.  In the special case of
			   password-based SSL this isn't completely foolproof since the
			   passwords are entered into a pool from which they can be
			   deleted explicitly if the session is aborted in a non-
			   resumable manner or implicitly over time as they are displaced 
			   by other entries, however this is an extremely unlikely case 
			   and it's too tricky trying to track what is and isn't still 
			   active to handle this fully */
			if( !( sessionInfoPtr->serverReqAttrFlags & \
				   SESSION_NEEDS_KEYORPASSWORD ) || \
				sessionInfoPtr->requiredPasswordStatus <= 0 )
				return( exitErrorNotInited( sessionInfoPtr,
											CRYPT_SESSINFO_PRIVATEKEY ) );
			}
		if( ( sessionInfoPtr->serverReqAttrFlags & \
			  SESSION_NEEDS_KEYSET ) && \
			sessionInfoPtr->cryptKeyset == CRYPT_ERROR )
			return( exitErrorNotInited( sessionInfoPtr,
										CRYPT_SESSINFO_KEYSET ) );
		}
	else
		{
		/* Check client-specific required values */
		if( sessionInfoPtr->transportSession == CRYPT_ERROR && \
			sessionInfoPtr->networkSocket == CRYPT_ERROR && \
			!sessionInfoPtr->serverName[ 0 ] )
			return( exitErrorNotInited( sessionInfoPtr,
										CRYPT_SESSINFO_SERVER_NAME ) );
		if( ( sessionInfoPtr->clientReqAttrFlags & \
			  SESSION_NEEDS_USERID ) && \
			sessionInfoPtr->userNameLength <= 0 )
			return( exitErrorNotInited( sessionInfoPtr,
										CRYPT_SESSINFO_USERNAME ) );
		if( ( sessionInfoPtr->clientReqAttrFlags & \
			  SESSION_NEEDS_PASSWORD ) && \
			sessionInfoPtr->passwordLength <= 0 )
			{
			/* There's no password present, see if we can use a private
			   key as an alternative */
			if( !( sessionInfoPtr->clientReqAttrFlags & \
				   SESSION_NEEDS_KEYORPASSWORD ) || \
				sessionInfoPtr->privateKey == CRYPT_ERROR )
				return( exitErrorNotInited( sessionInfoPtr,
											CRYPT_SESSINFO_PASSWORD ) );
			}
		if( ( sessionInfoPtr->clientReqAttrFlags & \
			  SESSION_NEEDS_PRIVATEKEY ) && \
			sessionInfoPtr->privateKey == CRYPT_ERROR )
			{
			/* There's no private key present, see if we can use a password 
			   as an alternative */
			if( !( sessionInfoPtr->clientReqAttrFlags & \
				   SESSION_NEEDS_KEYORPASSWORD ) || \
				sessionInfoPtr->passwordLength <= 0 )
				return( exitErrorNotInited( sessionInfoPtr,
											CRYPT_SESSINFO_PRIVATEKEY ) );
			}
		if( ( sessionInfoPtr->clientReqAttrFlags & \
			  SESSION_NEEDS_REQUEST ) && \
			sessionInfoPtr->iCertRequest == CRYPT_ERROR )
			return( exitErrorNotInited( sessionInfoPtr,
										CRYPT_SESSINFO_REQUEST ) );
		}

	/* Allocate the send and receive buffers if necessary.  The send buffer 
	   isn't used for request-response session types that use the receive 
	   buffer for both outgoing and incoming data, so we only allocate it if 
	   necessary */
	if( sessionInfoPtr->sendBuffer == NULL )
		{
		assert( sessionInfoPtr->receiveBufSize >= MIN_BUFFER_SIZE && \
				( sessionInfoPtr->sendBufSize >= MIN_BUFFER_SIZE || \
				  sessionInfoPtr->sendBufSize == CRYPT_UNUSED ) );

		if( ( sessionInfoPtr->receiveBuffer = \
						clAlloc( "activateConnection", \
								 sessionInfoPtr->receiveBufSize ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		if( sessionInfoPtr->sendBufSize != CRYPT_UNUSED )
			{
			/* When allocating the send buffer we use the size for the 
			   receive buffer since the user may have overridden the default 
			   buffer size */
			if( ( sessionInfoPtr->sendBuffer = \
						clAlloc( "activateConnection", \
								 sessionInfoPtr->receiveBufSize ) ) == NULL )
				{
				clFree( "activateConnection", sessionInfoPtr->receiveBuffer );
				sessionInfoPtr->receiveBuffer = NULL;
				return( CRYPT_ERROR_MEMORY );
				}
			sessionInfoPtr->sendBufSize = sessionInfoPtr->receiveBufSize;
			}
		}
	assert( ( sessionInfoPtr->flags & SESSION_ISSERVER ) || \
			strlen( sessionInfoPtr->serverName ) || \
			sessionInfoPtr->networkSocket != CRYPT_ERROR );
	assert( sessionInfoPtr->serverPort );
	assert( sessionInfoPtr->receiveBuffer != NULL );

	/* Set timeouts if they're not set yet */
	if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
		{
		int timeout;

		status = krnlSendMessage( sessionInfoPtr->ownerHandle, 
								  IMESSAGE_GETATTRIBUTE, &timeout, 
								  CRYPT_OPTION_NET_CONNECTTIMEOUT );
		sessionInfoPtr->connectTimeout = cryptStatusOK( status ) ? \
										 timeout : 30;
		}
	if( sessionInfoPtr->timeout == CRYPT_ERROR )
		{
		int timeout;

		status = krnlSendMessage( sessionInfoPtr->ownerHandle, 
								  IMESSAGE_GETATTRIBUTE, &timeout, 
								  CRYPT_OPTION_NET_TIMEOUT );
		sessionInfoPtr->timeout = cryptStatusOK( status ) ? timeout : 30;
		}

	/* Wait for any async driver binding to complete.  We can delay this 
	   until this very late stage because no networking functionality is 
	   used until this point */
	waitSemaphore( SEMAPHORE_DRIVERBIND );

	/* Activate the session */
	status = sessionInfoPtr->connectFunction( sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );

	/* If it's a secure data transport session, complete the session state 
	   setup.  Note that some sessions dynamically change the protocol info
	   during the handshake to accommodate parameters negotiated during the
	   handshake, so we can only access the protocol info after the handshake
	   has completed */
	if( !sessionInfoPtr->protocolInfo->isReqResp )
		{
		/* Complete the session handshake to set up the secure state */
		status = sessionInfoPtr->transactFunction( sessionInfoPtr );
		if( cryptStatusError( status ) )
			return( status );

		/* Notify the kernel that the session key context is attached to the 
		   session object.  Note that we increment its reference count even
		   though it's an internal object used only by the session, because 
		   otherwise it'll be automatically destroyed by the kernel as a 
		   zero-reference dependent object when the session object is 
		   destroyed (but before the session object itself, since it's a 
		   dependent object).  This can cause problems for lower-level 
		   session management code that tries to work with the (apparently 
		   still-valid) handle, for example protocols that need to encrypt a 
		   close-channel message on shutdown */
		krnlSendMessage( sessionInfoPtr->objectHandle, IMESSAGE_SETDEPENDENT,
						 &sessionInfoPtr->iCryptInContext,
						 SETDEP_OPTION_INCREF );

		/* Set up the buffer management variables.  Since the handshake has
		   now completed, we can access the protocol info */
		sessionInfoPtr->receiveBufPos = sessionInfoPtr->receiveBufEnd = 0;
		sessionInfoPtr->sendBufPos = sessionInfoPtr->sendBufStartOfs;
		}

	/* Remember that the session has been successfully established */
	sessionInfoPtr->flags |= SESSION_ISOPEN;

	return( CRYPT_OK );
	}

/* Activate a session */

static int activateSession( SESSION_INFO *sessionInfoPtr )
	{
	int streamState, status;

	/* Activate the connection if necessary */
	if( !( sessionInfoPtr->flags & SESSION_ISOPEN ) )
		{
		status = activateConnection( sessionInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If it's a secure data transport session, it's up to the caller to 
	   move data over it, and we're done */
	if( !sessionInfoPtr->protocolInfo->isReqResp )
		return( CRYPT_OK );

	/* Clean up data from the preceding session activation if necessary */
	if( ( sessionInfoPtr->flags & SESSION_ISSERVER ) && \
		sessionInfoPtr->iCertRequest != CRYPT_ERROR )
		{
		krnlSendNotifier( sessionInfoPtr->iCertRequest, 
						  IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iCertRequest = CRYPT_ERROR;
		}
	if( sessionInfoPtr->iCertResponse != CRYPT_ERROR )
		{
		krnlSendNotifier( sessionInfoPtr->iCertResponse, 
						  IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iCertResponse = CRYPT_ERROR;
		}

	/* Carry out the transaction for the request-response connection */
	status = sessionInfoPtr->transactFunction( sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );

	/* Check whether the other side has indicated that they're closing the
	   stream and if it has, shut down our side as well and record the fact 
	   that the session is now closed */
	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONNSTATE, 
			&streamState, 0 );
	if( !streamState )
		{
		sessionInfoPtr->flags &= ~SESSION_ISOPEN;
		sessionInfoPtr->shutdownFunction( sessionInfoPtr );
		}
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Default Session Handlers						*
*																			*
****************************************************************************/

/* Default init/shutdown functions used when no session-specific ones are 
   provided */

static int defaultClientStartupFunction( SESSION_INFO *sessionInfoPtr )
	{
	const PROTOCOL_INFO *protocolInfoPtr = sessionInfoPtr->protocolInfo;
	NET_CONNECT_INFO connectInfo;
	int status;

	/* Connect to the server */
	initSessionNetConnectInfo( sessionInfoPtr, &connectInfo );
	if( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT )
		status = sNetConnect( &sessionInfoPtr->stream,

⌨️ 快捷键说明

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