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

📄 ssl_rw.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
	if( sessionInfoPtr->cryptBlocksize > 1 && \
		( dataMaxLength % sessionInfoPtr->cryptBlocksize ) )
		{
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Invalid encrypted packet length %d relative to cipher "
				  "block size %d for packet type %d", dataMaxLength, 
				  sessionInfoPtr->cryptBlocksize, packetType ) );
		}

	/* Decrypt the packet in the buffer.  We allow zero-length blocks (once
	   the padding is stripped) because some versions of OpenSSL send these 
	   as a kludge to work around pre-TLS 1.1 chosen-IV attacks */
	status = decryptData( sessionInfoPtr, data, dataMaxLength, &length );
	if( cryptStatusError( status ) )
		{
		/* If there's a padding error, don't exit immediately but record 
		   that there was a problem for after we've done the MAC'ing.  
		   Delaying the error reporting until then helps prevent timing 
		   attacks of the kind described by Brice Canvel, Alain Hiltgen,
		   Serge Vaudenay, and Martin Vuagnoux in "Password Interception 
		   in a SSL/TLS Channel", Crypto'03, LNCS No.2729, p.583.  These 
		   are close to impossible in most cases because we delay sending 
		   the close notify over a much longer period than the MAC vs.non-
		   MAC time difference and because it requires repeatedly connecting
		   with a fixed-format secret such as a password at the same location
		   in the packet (which MS Outlook does however manage to do), but 
		   we take this step anyway just to be safe */
		if( status == CRYPT_ERROR_BADDATA )
			{
			badDecrypt = TRUE;
			length = dataMaxLength;
			}
		else
			return( status );
		}
	payloadLength = length - sessionInfoPtr->authBlocksize;
	if( payloadLength < 0 || payloadLength > MAX_PACKET_SIZE )
		{
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Invalid packet payload length %d for packet type %d", 
				  payloadLength, packetType ) );
		}

	/* MAC the decrypted data.  The badDecrypt flag suppresses the reporting
	   of a MAC error due to an earlier bad decrypt, which has already been
	   reported by decryptData() */
	if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
		status = checkMacSSL( sessionInfoPtr, data, length, payloadLength, 
							  packetType, badDecrypt );
	else
		status = checkMacTLS( sessionInfoPtr, data, length, payloadLength, 
							  packetType, badDecrypt );
	if( badDecrypt )
		{
		/* Report the delayed decrypt error, held to this point to make 
		   timing attacks more difficult */
		return( CRYPT_ERROR_BADDATA );
		}
	if( cryptStatusError( status ) )
		return( status );

	*dataLength = payloadLength;
	return( CRYPT_OK );
	}

/* Read an SSL handshake packet.  Since the data transfer phase has its own 
   read/write code we can perform some special-case handling based on this */

int readHSPacketSSL( SESSION_INFO *sessionInfoPtr,
					 SSL_HANDSHAKE_INFO *handshakeInfo, int *packetLength,
				     const int packetType )
	{
	STREAM stream;
	BYTE headerBuffer[ SSL_HEADER_SIZE + CRYPT_MAX_IVSIZE + 8 ];
	int bytesToRead, length, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( ( handshakeInfo == NULL ) || \
			isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
	assert( isWritePtr( packetLength, sizeof( int ) ) );
	assert( ( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST ) || \
			( packetType == SSL_MSG_FIRST_HANDSHAKE ) );
	assert( sessionInfoPtr->receiveBufStartOfs >= SSL_HEADER_SIZE && \
			sessionInfoPtr->receiveBufStartOfs < \
				SSL_HEADER_SIZE + CRYPT_MAX_IVSIZE );

	/* Sanity-check the state */
	if( sessionInfoPtr->receiveBufStartOfs < SSL_HEADER_SIZE || \
		sessionInfoPtr->receiveBufStartOfs >= \
			SSL_HEADER_SIZE + CRYPT_MAX_IVSIZE )
		retIntError();

	/* Clear return value */
	*packetLength = 0;

	/* Read and process the header */
	status = readFixedHeaderAtomic( sessionInfoPtr, headerBuffer,
									sessionInfoPtr->receiveBufStartOfs );
	if( cryptStatusError( status ) )
		return( status );

	/* Check for an SSL alert message */
	if( headerBuffer[ 0 ] == SSL_MSG_ALERT )
		return( processAlert( sessionInfoPtr, headerBuffer, 
							  sessionInfoPtr->receiveBufStartOfs ) );

	/* Decode and process the SSL packet header */
	if( packetType == SSL_MSG_FIRST_HANDSHAKE && \
		headerBuffer[ 0 ] == SSL_MSG_V2HANDSHAKE )
		{
#if 0	/* 28/01/08 Disabled since it's now finally been removed from MSIE 
		   and Firefox */
		/* It's an SSLv2 handshake, handle it specially */
		return( handleSSLv2Header( sessionInfoPtr, handshakeInfo, 
								   headerBuffer ) );
#else
		retExt( CRYPT_ERROR_NOSECURE,
				( CRYPT_ERROR_NOSECURE, SESSION_ERRINFO, 
				  "Client sent obsolete handshake for the insecure SSLv2 "
				  "protocol" ) );
#endif /* 0 */
		}
	sMemConnect( &stream, headerBuffer, sessionInfoPtr->receiveBufStartOfs );
	status = checkPacketHeader( sessionInfoPtr, &stream, &bytesToRead, 
								packetType, 
								( packetType == SSL_MSG_CHANGE_CIPHER_SPEC ) ? \
									1 : MIN_PACKET_SIZE,
								sessionInfoPtr->receiveBufSize ); 
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the payload packet(s) */
	status = length = \
		sread( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer, 
			   bytesToRead );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  &sessionInfoPtr->errorInfo );
		return( status );
		}
	if( length < bytesToRead )
		{
		/* If we timed out during the handshake phase, treat it as a hard 
		   timeout error */
		retExt( CRYPT_ERROR_TIMEOUT,
				( CRYPT_ERROR_TIMEOUT, SESSION_ERRINFO, 
				  "Timed out reading packet data for packet type %d, only "
				  "got %d of %d bytes", packetType, length, bytesToRead ) );
		}
	sessionInfoPtr->receiveBufPos = 0;
	sessionInfoPtr->receiveBufEnd = length;
	if( handshakeInfo != NULL )
		{
		sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
		status = dualMacDataRead( handshakeInfo, &stream );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			return( status );
		}
	*packetLength = length;

	return( CRYPT_OK );
	}

/* Read the next handshake stream packet */

int refreshHSStream( SESSION_INFO *sessionInfoPtr, 
					 SSL_HANDSHAKE_INFO *handshakeInfo )
	{
	STREAM *stream = &handshakeInfo->stream;
	int length, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );

	/* If there's still data present in the stream, there's nothing left
	   to do */
	if( sMemDataLeft( stream ) > 0 )
		return( CRYPT_OK );

	/* Refill the stream */
	sMemDisconnect( stream );
	status = readHSPacketSSL( sessionInfoPtr, handshakeInfo, &length,
							  SSL_MSG_HANDSHAKE );
	if( cryptStatusError( status ) )
		return( status );
	assert( length > 0 );
	sMemConnect( stream, sessionInfoPtr->receiveBuffer, length );

	return( CRYPT_OK );
	}		

/****************************************************************************
*																			*
*							Write Packet Utility Functions					*
*																			*
****************************************************************************/

/* Open and complete an SSL packet:

	 offset										packetEndOfs
		|											|
		v											v
		+---+---+---+----+--------------------------+
		|ID	|Ver|Len|(IV)|							|
		+---+---+---+----+--------------------------+

   An initial openXXX() starts a new packet at the start of a stream and 
   continueXXX() adds another packet after an existing one, or (for the
   xxxHSXXX() variants) adds a handshake sub-packet within an existing 
   packet.  The continueXXX() operations return the start offset of the new 
   packet within the stream, openXXX() always starts at the start of the SSL 
   send buffer so the start offset is an implied 0.  completeXXX() then goes 
   back to the given offset and deposits the appropriate length value in the 
   header that was written earlier.  So typical usage would be:

	// Change-cipher-spec packet
	openPacketStreamSSL( CRYPT_USE_DEFAULT, SSL_MSG_CHANGE_CIPHER_SPEC );
	write( stream, ... );
	completePacketStreamSSL( stream, 0 );

	// Finished handshake sub-packet within a handshake packet
	continuePacketStreamSSL( SSL_MSG_HANDSHAKE );
	offset = continueHSPacketStream( SSL_HAND_FINISHED );
	write( stream, ... );
	completeHSPacketStream( stream, offset );
	// (Packet stream is completed by wrapPacketSSL())

   Errors are propagated and caught at the completeXXX() stage */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int openPacketStream( INOUT STREAM *stream, 
							 const SESSION_INFO *sessionInfoPtr, 
							 const int packetType )
	{
	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );

	/* Write the packet header:

		byte		ID = packetType
		byte[2]		version = { 0x03, 0x0n }
		uint16		len = 0 (placeholder) 
	  [ byte[]		iv	- TLS 1.1 only ] */
	sputc( stream, packetType );
	sputc( stream, SSL_MAJOR_VERSION );
	sputc( stream, sessionInfoPtr->version );
	status = writeUint16( stream, 0 );		/* Placeholder */
	if( ( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE ) && \
		sslInfo->ivSize > 0 )
		{
		MESSAGE_DATA msgData;
		BYTE iv[ CRYPT_MAX_IVSIZE + 8 ];

		setMessageData( &msgData, iv, sslInfo->ivSize );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, 
						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		status = swrite( stream, iv, sslInfo->ivSize );
		}
	return( status );
	}

int openPacketStreamSSL( STREAM *stream, const SESSION_INFO *sessionInfoPtr, 
						 const int bufferSize, const int packetType )
	{
	const int streamSize = ( bufferSize == CRYPT_USE_DEFAULT ) ? \
						   sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE : \
						   bufferSize + sessionInfoPtr->sendBufStartOfs;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) && \
			isWritePtr( sessionInfoPtr->sendBuffer, streamSize ) );
	assert( bufferSize == CRYPT_USE_DEFAULT || \
			( packetType == SSL_MSG_APPLICATION_DATA && bufferSize == 0 ) || \
			bufferSize > 0 );
			/* When wrapping up data packets we only write the implicit-
			   length header so the buffer size is zero */
	assert( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );

	/* Sanity-check the state */
	if( streamSize < sessionInfoPtr->sendBufStartOfs || \
		streamSize > sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE )
		retIntError();

	/* Create the stream */
	sMemOpen( stream, sessionInfoPtr->sendBuffer, streamSize );
	return( openPacketStream( stream, sessionInfoPtr, packetType ) );
	}

int continuePacketStreamSSL( STREAM *stream, 
							  const SESSION_INFO *sessionInfoPtr, 
							  const int packetType )
	{
	const int offset = stell( stream );

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( stell( stream ) >= SSL_HEADER_SIZE );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );

	/* We don't have to check the return value of the continue/open since 
	   it's implicitly communicated via the stream state */
	( void ) openPacketStream( stream, sessionInfoPtr, packetType );
	return( offset );
	}

int completePacketStreamSSL( STREAM *stream, const int offset )
	{
	const int packetEndOffset = stell( stream );
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( ( offset == 0 || offset >= SSL_HEADER_SIZE ) && \
			offset <= packetEndOffset - ( ID_SIZE + VERSIONINFO_SIZE ) );

	/* Sanity-check the state */
	if( ( offset != 0 && offset < SSL_HEADER_SIZE ) || \
		offset > packetEndOffset - ( ID_SIZE + VERSIONINFO_SIZE ) )
		retIntError();

	/* Update the length field at the start of the packet */
	sseek( stream, offset + ID_SIZE + VERSIONINFO_SIZE );
	status = writeUint16( stream, ( packetEndOffset - offset ) - \
								  SSL_HEADER_SIZE );
	sseek( stream, packetEndOffset );
	return( status );
	}

/* Start and complete a handshake packet within an SSL packet.  Since this
   continues an existing packet stream that's been opened using 
   openPacketStreamSSL(), it's denoted as continueXXX() rather than 
   openXXX() */

int continueHSPacketStream( STREAM *stream, const int packetType )
	{
	const int offset = stell( stream );

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( packetType >= SSL_HAND_FIRST && packetType <= SSL_HAND_LAST );

	/* Write the handshake packet header:

		byte		ID = packetType
		uint24		len = 0 (placeholder) */
	sputc( stream, packetType );
	writeUint24( stream, 0 );	/* Placeholder */
	return( offset );
	}

int completeHSPacketStream( STREAM *stream, const int offset )
	{
	const int packetEndOffset = stell( stream );
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( offset >= SSL_HEADER_SIZE && \
			offset <= packetEndOffset - ( ID_SIZE + LENGTH_SIZE ) );
			/* HELLO_DONE has size zero so ofs == pEO - HDR_SIZE */

	/* Sanity-check the state */
	if( offset < SSL_HEADER_SIZE || \
		offset > packetEndOffset - ( ID_SIZE + LENGTH_SIZE ) )
		retIntError();

	/* Update the length field at the start of the packet */
	sseek( stream, offset + ID_SIZE );
	status = writeUint24( stream, packetEndOffset - \
								  ( offset + ID_SIZE + LENGTH_SIZE ) );
	sseek( stream, packetEndOffset );
	return( status );
	}

/****************************************************************************
*																			*
*							Write/wrap a Packet								*
*																			*
****************************************************************************/

/* Wrap an SSL data packet:

	sendBuffer hdrPtr	dataPtr
		|		|			|-------------------			  MAC'd
		v		v			v================================ Encrypted
		+-------+-----+-----+-------------------+-----+-----+
		|///////| hdr | IV	|		data		| MAC | pad |
		+-------+-----+-----+-------------------+-----+-----+
				^<--------->|<- payloadLength ->^			|
				|	  |		 <-------- bMaxLen -|---------->
			 offset sBufStartOfs			stell( stream )

   This MACs the data, adds the IV if necessary, pads and encrypts, and
   updates the header */

int wrapPacketSSL( SESSION_INFO *sessionInfoPtr, STREAM *stream, 
				   const int offset )
	{
	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;

⌨️ 快捷键说明

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