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

📄 ssl.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:
	if( cryptStatusError( status ) || !isInitiator )
		return( status );
	return( readHandshakeCompletionData( sessionInfoPtr, responderHashes ) );
	}

/****************************************************************************
*																			*
*								Init/Shutdown Functions						*
*																			*
****************************************************************************/

/* Close a previously-opened SSL session */

static void shutdownFunction( SESSION_INFO *sessionInfoPtr )
	{
	sendCloseAlert( sessionInfoPtr, FALSE );
	sNetDisconnect( &sessionInfoPtr->stream );
	}

/* Connect to an SSL server/client */

static int abortStartup( SESSION_INFO *sessionInfoPtr,
						 SSL_HANDSHAKE_INFO *handshakeInfo,
						 const BOOLEAN cleanupSecurityContexts,
						 const int status )
	{
	sendHandshakeFailAlert( sessionInfoPtr );
	if( cleanupSecurityContexts )
		destroySecurityContextsSSL( sessionInfoPtr );
	if( handshakeInfo != NULL )
		destroyHandshakeInfo( handshakeInfo );
	sNetDisconnect( &sessionInfoPtr->stream );
	return( status );
	}

static int commonStartup( SESSION_INFO *sessionInfoPtr,
						  const BOOLEAN isServer )
	{
	SSL_HANDSHAKE_INFO handshakeInfo;
	BOOLEAN resumedSession = FALSE;
	int status;

	/* Initialise the handshake info and begin the handshake */
	status = initHandshakeInfo( sessionInfoPtr, &handshakeInfo, isServer );
	if( cryptStatusOK( status ) )
		status = handshakeInfo.beginHandshake( sessionInfoPtr, 
											   &handshakeInfo );
	if( status == OK_SPECIAL )
		resumedSession = TRUE;
	else
		if( cryptStatusError( status ) )
			return( abortStartup( sessionInfoPtr, &handshakeInfo, FALSE, 
								  status ) );

	/* Exchange keys with the server */
	if( !resumedSession )
		{
		status = handshakeInfo.exchangeKeys( sessionInfoPtr, 
											 &handshakeInfo );
		if( cryptStatusError( status ) )
			return( abortStartup( sessionInfoPtr, &handshakeInfo, TRUE, 
								  status ) );
		}

	/* Complete the handshake */
	status = completeHandshake( sessionInfoPtr, &handshakeInfo, !isServer, 
								resumedSession );
	destroyHandshakeInfo( &handshakeInfo );
	if( cryptStatusError( status ) )
		return( abortStartup( sessionInfoPtr, NULL, TRUE, status ) );

	return( CRYPT_OK );
	}

static int clientStartup( SESSION_INFO *sessionInfoPtr )
	{
	/* Complete the handshake using the common client/server code */
	return( commonStartup( sessionInfoPtr, FALSE ) );
	}

static int serverStartup( SESSION_INFO *sessionInfoPtr )
	{
#if 0	/* Old PSK mechanism */
	/* Clear any user name/password information that may be present from
	   a previous session or from the manual addition of keys to the session
	   cache */
	resetSessionAttribute( sessionInfoPtr->attributeList, 
						   CRYPT_SESSINFO_USERNAME );
	resetSessionAttribute( sessionInfoPtr->attributeList, 
						   CRYPT_SESSINFO_PASSWORD );
#endif /* 0 */

	/* Complete the handshake using the common client/server code */
	return( commonStartup( sessionInfoPtr, TRUE ) );
	}

/****************************************************************************
*																			*
*						Control Information Management Functions			*
*																			*
****************************************************************************/

static int getAttributeFunction( SESSION_INFO *sessionInfoPtr,
								 void *data, const CRYPT_ATTRIBUTE_TYPE type )
	{
	CRYPT_CERTIFICATE *certPtr = ( CRYPT_CERTIFICATE * ) data;
	CRYPT_CERTIFICATE iCryptCert = \
		( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
		sessionInfoPtr->iKeyexAuthContext : sessionInfoPtr->iKeyexCryptContext;

	assert( type == CRYPT_SESSINFO_RESPONSE );

	/* If we didn't get a client/server cert there's nothing to return */
	if( iCryptCert == CRYPT_ERROR )
		return( CRYPT_ERROR_NOTFOUND );

	/* Return the information to the caller */
	krnlSendNotifier( iCryptCert, IMESSAGE_INCREFCOUNT );
	*certPtr = iCryptCert;
	return( CRYPT_OK );
	}

#if 0	/* Old PSK mechanism */

static int setAttributeFunction( SESSION_INFO *sessionInfoPtr,
								 const void *data,
								 const CRYPT_ATTRIBUTE_TYPE type )
	{
	const ATTRIBUTE_LIST *userNamePtr = \
				findSessionAttribute( sessionInfoPtr->attributeList,
									  CRYPT_SESSINFO_USERNAME );
	BYTE premasterSecret[ ( UINT16_SIZE + CRYPT_MAX_TEXTSIZE ) * 2 + 8 ];
	BYTE sessionID[ SESSIONID_SIZE + 8 ];
	int uniqueID, premasterSecretLength, status;

	assert( type == CRYPT_SESSINFO_USERNAME || \
			type == CRYPT_SESSINFO_PASSWORD );

	/* At the moment only the server maintains a true session cache, so if 
	   it's a client session we return without any further checking, there
	   can never be a duplicate entry in this case */
	if( !( sessionInfoPtr->flags & SESSION_ISSERVER ) )
		return( CRYPT_OK );

	/* If we're setting the password, we have to have a session ID present to
	   set it for */
	if( type == CRYPT_SESSINFO_PASSWORD && userNamePtr == NULL )
		{
		setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_USERNAME, 
					  CRYPT_ERRTYPE_ATTR_ABSENT );
		return( CRYPT_ERROR_NOTINITED );
		}

	/* Wait for any async network driver binding to complete.  This is 
	   required because the session cache is initialised as part of the 
	   asynchronous startup (since it's tied to the session object class
	   rather than a particular session object), so we have to wait until 
	   this has completed before we can access it */
	krnlWaitSemaphore( SEMAPHORE_DRIVERBIND );

	/* Format the session ID in the appropriate manner and check whether it's
	   present in the cache */
	memset( sessionID, 0, SESSIONID_SIZE );
	memcpy( sessionID, userNamePtr->value, 
			min( userNamePtr->valueLength, SESSIONID_SIZE ) );
	uniqueID = findSessionCacheEntryID( sessionID, SESSIONID_SIZE );

	/* If we're adding or deleting a user name, check whether something
	   identified by the name is present in the cache */
	if( type == CRYPT_SESSINFO_USERNAME )
		{
		if( data != NULL )
			{
			/* User name add, presence is an error */
			if( uniqueID )
				{
				setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_USERNAME, 
							  CRYPT_ERRTYPE_ATTR_PRESENT );
				return( CRYPT_ERROR_INITED );
				}
			}
		else
			{
			/* User name delete, absence is an error */
			if( !uniqueID )
				{
				setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_USERNAME, 
							  CRYPT_ERRTYPE_ATTR_ABSENT );
				return( CRYPT_ERROR_NOTINITED );
				}
			deleteSessionCacheEntry( uniqueID );
			}
		return( CRYPT_OK );
		}

	/* Create the premaster secret from the user-supplied password */
	status = createSharedPremasterSecret( premasterSecret, 
										  &premasterSecretLength, 
										  sessionInfoPtr );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, status, 
				"Couldn't create SSL master secret from shared "
				"secret/password value" );

	/* Add the entry to the session cache */
	addSessionCacheEntry( sessionID, SESSIONID_SIZE, premasterSecret, 
						  premasterSecretLength, TRUE );
	zeroise( premasterSecret, SSL_SECRET_SIZE );
	return( CRYPT_OK );
	}
#endif /* 0 */

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

/* Read/write data over the SSL link */

static int readHeaderFunction( SESSION_INFO *sessionInfoPtr, 
							   READSTATE_INFO *readInfo )
	{
	STREAM stream;
	const BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
						 sessionInfoPtr->receiveBufEnd;
	int length, status;

	/* Clear return value */
	*readInfo = READINFO_NONE;

	/* Read the SSL packet header data */
	status = length = readFixedHeader( sessionInfoPtr, 
									   sessionInfoPtr->receiveBufStartOfs );
	if( status <= 0 )
		return( status );
	assert( status == sessionInfoPtr->receiveBufStartOfs );

	/* Since data errors are always fatal, we make all errors fatal until 
	   we've finished handling the header */
	*readInfo = READINFO_FATAL;

	/* Check for an SSL alert message */
	if( bufPtr[ 0 ] == SSL_MSG_ALERT )
		{
		*readInfo = READINFO_FATAL;
		return( processAlert( sessionInfoPtr, bufPtr, length ) );
		}

	/* Process the header data */
	sMemConnect( &stream, bufPtr, length );
	status = length = checkPacketHeaderSSL( sessionInfoPtr, &stream );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}

	/* Determine how much data we'll be expecting */
	sessionInfoPtr->pendingPacketLength = \
		sessionInfoPtr->pendingPacketRemaining = length;

	/* Indicate that we got the header */
	*readInfo = READINFO_NOOP;
	return( OK_SPECIAL );
	}

static int processBodyFunction( SESSION_INFO *sessionInfoPtr,
								READSTATE_INFO *readInfo )
	{
	STREAM stream;
	int length;

	assert( sessionInfoPtr->pendingPacketLength > 0 );
	assert( sessionInfoPtr->receiveBufPos + \
				sessionInfoPtr->pendingPacketLength <= \
			sessionInfoPtr->receiveBufEnd );
	assert( sessionInfoPtr->receiveBufEnd <= sessionInfoPtr->receiveBufSize );

	/* All errors processing the payload are fatal */
	*readInfo = READINFO_FATAL;

	/* Unwrap the payload */
	sMemConnect( &stream, sessionInfoPtr->receiveBuffer + \
						  sessionInfoPtr->receiveBufPos, 
				 sessionInfoPtr->pendingPacketLength );
	length = unwrapPacketSSL( sessionInfoPtr, &stream, 
							  SSL_MSG_APPLICATION_DATA );
	sMemDisconnect( &stream );
	if( cryptStatusError( length ) )
		return( length );

	/* Adjust the data size indicators to account for the stripped padding
	   and MAC info */
	sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos + length;
	sessionInfoPtr->receiveBufPos = sessionInfoPtr->receiveBufEnd;
	sessionInfoPtr->pendingPacketLength = 0;
	assert( sessionInfoPtr->receiveBufEnd <= sessionInfoPtr->receiveBufSize );

	/* If we only got a partial packet, let the caller know that they should 
	   try again */
	if( length < 1 )
		{
		*readInfo = READINFO_PARTIAL;
		return( OK_SPECIAL );
		}
	*readInfo = READINFO_NONE;
	return( length );
	}

static int preparePacketFunction( SESSION_INFO *sessionInfoPtr )
	{
	STREAM stream;
	int status;

	assert( sessionInfoPtr->sendBufPos - \
			sessionInfoPtr->sendBufStartOfs > 0 && \
			sessionInfoPtr->sendBufPos - \
			sessionInfoPtr->sendBufStartOfs <= MAX_PACKET_SIZE );
	assert( !( sessionInfoPtr->flags & SESSION_SENDCLOSED ) );
	assert( !( sessionInfoPtr->protocolFlags & SSL_PFLAG_ALERTSENT ) );

	/* Wrap up the payload ready for sending.  Since this is wrapping in-
	   place data we first open a write stream to add the header, then open 
	   a read stream covering the full buffer in preparation for wrapping 
	   the packet.  Note that we connect the stream to the full send buffer
	   (bufSize) even though we only advance the current stream position to 
	   the end of the stream contents (bufPos), since the packet-wrapping 
	   process adds further data to the stream that exceeds the current 
	   stream position */
	openPacketStreamSSL( &stream, sessionInfoPtr, 0, 
						 SSL_MSG_APPLICATION_DATA );
	sMemDisconnect( &stream );
	sMemConnect( &stream, sessionInfoPtr->sendBuffer, 
				 sessionInfoPtr->sendBufSize );
	sSkip( &stream, sessionInfoPtr->sendBufPos );
	status = wrapPacketSSL( sessionInfoPtr, &stream, 0 );
	if( cryptStatusOK( status ) )
		status = stell( &stream );
	sMemDisconnect( &stream );

	return( status );
	}

/****************************************************************************
*																			*
*							Session Access Routines							*
*																			*
****************************************************************************/

int setAccessMethodSSL( SESSION_INFO *sessionInfoPtr )
	{
	static const ALTPROTOCOL_INFO altProtocolInfo = {
		/* SSL tunnelled via an HTTP proxy.  This is a special case in that
		   the initial connection is made using HTTP, but subsequent
		   communications are via a direct TCP/IP connection that goes
		   through the proxy */
		STREAM_PROTOCOL_TCPIP,		/* Alt.protocol type */
		"https://",					/* Alt.protocol URI type */
		80,							/* Alt.protocol port */
		0,							/* Protocol flags to replace */
		SESSION_USEHTTPTUNNEL		/* Alt.protocol flags */
		};
	static const PROTOCOL_INFO protocolInfo = {
		/* General session information */
		FALSE,						/* Request-response protocol */
		SESSION_NONE,				/* Flags */
		SSL_PORT,					/* SSL port */
		SESSION_NEEDS_PRIVKEYSIGN,	/* Client attributes */
			/* The client private key is optional but if present, it has to 
			   be signature-capable */
		SESSION_NEEDS_PRIVATEKEY |	/* Server attributes */
			SESSION_NEEDS_PRIVKEYCRYPT | \
			SESSION_NEEDS_PRIVKEYCERT | \
			SESSION_NEEDS_KEYORPASSWORD,
		SSL_MINOR_VERSION_TLS,		/* TLS 1.0 */
			SSL_MINOR_VERSION_SSL, SSL_MINOR_VERSION_TLS11,
			/* We default to TLS 1.0 rather than TLS 1.1 because it's likely
			   that support for the latter will be hit-and-miss for some 
			   time */
		NULL, NULL,					/* Content-type */
	
		/* Protocol-specific information */
		EXTRA_PACKET_SIZE + \
			MAX_PACKET_SIZE,		/* Send/receive buffer size */
		SSL_HEADER_SIZE,			/* Payload data start */
			/* This may be adjusted during the handshake if we're talking 
			   TLS 1.1, which prepends extra data in the form of an IV to
			   the payload */
		MAX_PACKET_SIZE,			/* (Default) maximum packet size */
		&altProtocolInfo			/* Alt.transport protocol */
		};

	/* Set the access method pointers */
	sessionInfoPtr->protocolInfo = &protocolInfo;
	sessionInfoPtr->shutdownFunction = shutdownFunction;
	sessionInfoPtr->transactFunction = \
			( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
			serverStartup : clientStartup;
	sessionInfoPtr->getAttributeFunction = getAttributeFunction;
	sessionInfoPtr->readHeaderFunction = readHeaderFunction;
	sessionInfoPtr->processBodyFunction = processBodyFunction;
	sessionInfoPtr->preparePacketFunction = preparePacketFunction;

	return( CRYPT_OK );
	}
#endif /* USE_SSL */

⌨️ 快捷键说明

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