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

📄 ssl_rw.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*				cryptlib SSL v3/TLS Session Read/Write Routines				*
*					   Copyright Peter Gutmann 1998-2004					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "misc_rw.h"
  #include "session.h"
  #include "ssl.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../misc/misc_rw.h"
  #include "session.h"
  #include "ssl.h"
#else
  #include "crypt.h"
  #include "misc/misc_rw.h"
  #include "session/session.h"
  #include "session/ssl.h"
#endif /* Compiler-specific includes */

#ifdef USE_SSL

/****************************************************************************
*																			*
*								Legacy SSLv2 Functions						*
*																			*
****************************************************************************/

/* Handle a legacy SSLv2 client hello:

	uint16	length code = { 0x80, len }
	byte	type = SSL_HAND_CLIENT_HELLO
	byte[2]	vers = { 0x03, 0x0n } */

static int handleSSLv2Header( SESSION_INFO *sessionInfoPtr, 
							  SSL_HANDSHAKE_INFO *handshakeInfo, 
							  const BYTE *bufPtr )
	{
	STREAM stream;
	int length, value, status;

	assert( bufPtr[ 0 ] == SSL_MSG_V2HANDSHAKE );

	/* Make sure that the length is in order.  Beyond the header we need at 
	   least the three 16-bit field lengths, one 24-bit cipher suite, and at 
	   least 16 bytes of nonce */
	bufPtr++;			/* Skip SSLv2 length ID, already checked by caller */
	length = *bufPtr++;
	if( length < ID_SIZE + VERSIONINFO_SIZE + \
				 ( UINT16_SIZE * 3 ) + 3 + 16 || \
		length > sessionInfoPtr->receiveBufSize )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid legacy SSLv2 hello packet length %d", length );

	/* Due to the different ordering of header fields in SSLv2, the type and 
	   version is regarded as part of the payload that needs to be 
	   hashed, rather than the header as for SSLv3 */
	sMemConnect( &stream, bufPtr, ID_SIZE + VERSIONINFO_SIZE );
	dualMacData( handshakeInfo, &stream, TRUE );
	value = sgetc( &stream );
	if( value != SSL_HAND_CLIENT_HELLO )
		{
		sMemDisconnect( &stream );
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Unexpected legacy SSLv2 packet type %d, should be %d", 
				value, SSL_HAND_CLIENT_HELLO );
		}
	status = processVersionInfo( sessionInfoPtr, &stream, 
								 &handshakeInfo->clientOfferedVersion );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}
	length -= stell( &stream );
	sMemDisconnect( &stream );

	/* Read the packet payload */
	status = sread( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer, 
					length );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}
	if( status < length )
		/* If we timed out during the handshake phase, treat it as a hard 
		   timeout error */
		retExt( sessionInfoPtr, CRYPT_ERROR_TIMEOUT,
				"Timeout during legacy SSLv2 hello packet read, only got "
				"%d of %d bytes", status, length );
	sessionInfoPtr->receiveBufPos = 0;
	sessionInfoPtr->receiveBufEnd = length;
	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
	dualMacData( handshakeInfo, &stream, TRUE );
	sMemDisconnect( &stream );

	/* SSLv2 puts the version info in the header, so we set the SSLv2 flag 
	   in the handshake info to ensure that it doesn't get confused with a 
	   normal SSL packet type */
	handshakeInfo->isSSLv2 = TRUE;

	return( length );
	}

/****************************************************************************
*																			*
*							Read Packet Utility Functions					*
*																			*
****************************************************************************/

/* Process version information */

int processVersionInfo( SESSION_INFO *sessionInfoPtr, STREAM *stream,
						int *clientVersion )
	{
	int version;

	/* Clear return value */
	if( clientVersion != NULL )
		*clientVersion = CRYPT_ERROR;

	/* Check the major version number */
	version = sgetc( stream );
	if( version != SSL_MAJOR_VERSION )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid major version number %d, should be 3", version );

	/* Check the minor version number.  If we've already got the version
	   established, make sure that it matches the existing one, otherwise
	   determine which version we'll be using */
	version = sgetc( stream );
	if( clientVersion == NULL )
		{
		if( version != sessionInfoPtr->version )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid version number 3.%d, should be 3.%d", 
					version, sessionInfoPtr->version );
		return( CRYPT_OK );
		}
	switch( version )
		{
		case SSL_MINOR_VERSION_SSL:
			/* If the other side can't do TLS, fall back to SSL */
			if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
				sessionInfoPtr->version = SSL_MINOR_VERSION_SSL;
			break;

		case SSL_MINOR_VERSION_TLS:
			/* If the other side can't do TLS 1.1, fall back to TLS 1.0 */
			if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS11 )
				sessionInfoPtr->version = SSL_MINOR_VERSION_TLS;
			break;

		case SSL_MINOR_VERSION_TLS11:
			/* If the other side can't do post-TLS 1.1, fall back to 
			   TLS 1.1 */
			if( sessionInfoPtr->version > SSL_MINOR_VERSION_TLS11 )
				sessionInfoPtr->version = SSL_MINOR_VERSION_TLS11;
			break;

		default:
			/* If we're the server and the client has offered a vaguely 
			   sensible version, fall back to the highest version that we
			   support */
			if( ( sessionInfoPtr->flags && SESSION_ISSERVER ) && \
				version <= 5 )
				{
				sessionInfoPtr->version = SSL_MINOR_VERSION_TLS11;
				break;
				}

			/* It's nothing that we can handle */
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid protocol version 3.%d", version );
		}

	*clientVersion = version;
	return( CRYPT_OK );
	}

/* Check that the header of an SSL packet is in order:

	byte	type
	byte[2]	vers = { 0x03, 0x0n }
	uint16	length
  [ byte[]	iv	- TLS 1.1 ]

  If this is the initial hello packet we request a dummy version info read 
  since the peer's version isn't known yet at this point.  The actual 
  version info is taken from the hello packet data, not from the SSL 
  wrapper */

static int checkPacketHeader( SESSION_INFO *sessionInfoPtr, STREAM *stream,
							  const int packetType, const int minLength )
	{
	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
	const int expectedPacketType = \
					( packetType == SSL_MSG_FIRST_HANDSHAKE ) ? \
					SSL_MSG_HANDSHAKE : packetType;
	int value, status;

	/* Check the packet type */
	value = sgetc( stream );
	if( value != expectedPacketType )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Unexpected packet type %d, expected %d", 
				value, expectedPacketType );
	status = processVersionInfo( sessionInfoPtr, stream, 
				( packetType == SSL_MSG_FIRST_HANDSHAKE ) ? &value : NULL );
	if( cryptStatusError( status ) )
		return( status );

	/* Check the packet length */
	value = readUint16( stream );
	if( sessionInfoPtr->flags & SESSION_ISSECURE_READ )
		{
		if( value < sslInfo->ivSize + minLength + \
					sessionInfoPtr->authBlocksize || \
			value > sslInfo->ivSize + MAX_PACKET_SIZE + \
					sessionInfoPtr->authBlocksize + 256 || \
			value > sessionInfoPtr->receiveBufSize )
			status = CRYPT_ERROR_BADDATA;
		}
	else
		if( value < minLength || value > MAX_PACKET_SIZE || \
			value > sessionInfoPtr->receiveBufSize )
			status = CRYPT_ERROR_BADDATA;
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid packet length %d for packet type %d", 
				value, packetType );

	/* Load the TLS 1.1 explicit IV if necessary */
	if( ( sessionInfoPtr->flags & SESSION_ISSECURE_READ ) && \
		sslInfo->ivSize > 0 )
		{
		const int offset = stell( stream );

		status = loadExplicitIV( sessionInfoPtr, stream );
		value -= stell( stream ) - offset;
		}

	return( value );
	}

/* Check that the header of an SSL packet and SSL handshake packet is in 
   order */

int checkPacketHeaderSSL( SESSION_INFO *sessionInfoPtr, STREAM *stream )
	{
	return( checkPacketHeader( sessionInfoPtr, stream, 
							   SSL_MSG_APPLICATION_DATA, 0 ) );
	}

int checkHSPacketHeader( SESSION_INFO *sessionInfoPtr, STREAM *stream,
						 const int packetType, const int minSize )
	{
	int type, length;

	/*	byte		ID = type
		uint24		length */
	type = sgetc( stream );
	if( type != packetType )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid handshake packet type %d, expected %d", 
				type, packetType );
	length = readUint24( stream );
	if( length < minSize || length > MAX_PACKET_SIZE || \
		length > sMemDataLeft( stream ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid length %d for handshake packet type %d", 
				length, type );
	return( length );
	}

/****************************************************************************
*																			*
*								Read/Unwrap a Packet						*
*																			*
****************************************************************************/

/* Unwrap an SSL data packet:

				------				MAC'd
				==================  Encrypted
	[ hdr | IV | data | MAC | pad ]
			   +------------------+
			   |		|
			 buffer	 length 

   This decrypts and removes the padding, checks and removes the MAC, and
   returns the payload length.  Processing of the header and IV have already 
   been performed during the packet header read */

int unwrapPacketSSL( SESSION_INFO *sessionInfoPtr, STREAM *stream, 
					 const int packetType )
	{
	const int totaLength = sMemDataLeft( stream );
	BYTE *bufPtr = sMemBufPtr( stream );
	BOOLEAN badDecrypt = FALSE;
	int length, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( sessionInfoPtr->flags & SESSION_ISSECURE_READ );
	assert( stell( stream ) == 0 );
	assert( totaLength >= sessionInfoPtr->authBlocksize && \

⌨️ 快捷键说明

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