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

📄 ssh2_rw.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
				expectedType = SSH2_MSG_KEXDH_GEX_REQUEST_NEW;
			break;
		}
	if( packetType != expectedType )
		{
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Invalid handshake packet type %d, expected %d", 
				  packetType, expectedType ) );
		}

	return( length );
	}

/****************************************************************************
*																			*
*								Write/Wrap a Packet							*
*																			*
****************************************************************************/

/* Unlike SSL, SSH only hashes portions of the handshake, and even then not
   complete packets but arbitrary bits and pieces.  In order to handle this
   we have to be able to break out bits and pieces of data from the stream
   buffer in order to hash them.  The following function extracts a block
   of data from a given position in the stream buffer */

int streamBookmarkComplete( STREAM *stream, void **dataPtrPtr, int *length, 
							const int position )
	{
	const int dataLength = stell( stream ) - position;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( dataPtrPtr, sizeof( void * ) ) );
	assert( isWritePtr( length, sizeof( int ) ) );
	assert( position >= 0 );
	assert( dataLength > 0 || dataLength < stell( stream ) );

	/* Clear return values */
	*dataPtrPtr = NULL;
	*length = 0;

	/* Sanity-check the state */
	if( position < 0 || dataLength <= 0 || dataLength >= stell( stream ) )
		retIntError();

	*length = dataLength;
	return( sMemGetDataBlockAbs( stream, position, dataPtrPtr, dataLength ) );
	}

/* Open a stream to write an SSH2 packet or continue an existing stream to
   write further packets.  This opens the stream (if it's an open), skips
   the storage for the packet header, and writes the packet type */

int openPacketStreamSSH( 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 + SSH2_HEADER_SIZE;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( sessionInfoPtr->sendBuffer, streamSize ) );
	assert( streamSize > SSH2_HEADER_SIZE && \
			streamSize <= sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE );

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

	sMemOpen( stream, sessionInfoPtr->sendBuffer, streamSize );
	swrite( stream, "\x00\x00\x00\x00\x00", SSH2_HEADER_SIZE );
	return( sputc( stream, packetType ) );
	}

int continuePacketStreamSSH( STREAM *stream, const int packetType,
							 int *packetOffset )
	{
	const int offset = stell( stream );
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( stell( stream ) == 0 || stell( stream ) > SSH2_HEADER_SIZE + 1 );
	assert( isWritePtr( packetOffset, sizeof( int ) ) );

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

	swrite( stream, "\x00\x00\x00\x00\x00", SSH2_HEADER_SIZE );
	status = sputc( stream, packetType );
	if( cryptStatusError( status ) )
		return( status );
	*packetOffset = offset;

	return( CRYPT_OK );
	}

/* Send an SSHv2 packet.  During the handshake phase we may be sending
   multiple packets at once, however unlike SSL, SSH requires that each
   packet in a multi-packet group be individually gift-wrapped so we have to
   provide a facility for separately wrapping and sending packets to handle
   this:

	sendBuffer	bStartPtr	
		|			|
		v			v	|<-- payloadLen --->|<-eLen->
		+-----------+---+-------------------+---+---+
		|///////////|hdr|		data		|pad|MAC|
		+-----------+---+-------------------+---+---+
					^<------- length ------>^	|
					|						|	|
				 offset					  stell(s)
					|<------- totalLen -------->| */

int wrapPacketSSH2( SESSION_INFO *sessionInfoPtr, STREAM *stream,
					const int offset, const BOOLEAN useQuantisedPadding,
					const BOOLEAN isWriteableStream )
	{
	SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
	const int length = stell( stream ) - offset;
	const int payloadLength = length - SSH2_HEADER_SIZE;
	const int padBlockSize = max( sessionInfoPtr->cryptBlocksize, 8 );
	void *bufStartPtr;
	int extraLength = ( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE ) ? \
					  sessionInfoPtr->authBlocksize : 0;
	int padLength, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( sStatusOK( stream ) );
	assert( offset >= 0 );
	assert( length >= SSH2_HEADER_SIZE );
	assert( payloadLength >= 0 && payloadLength < length && \
			offset + length + extraLength <= sessionInfoPtr->sendBufSize );

	/* Sanity-check the state */
	if( payloadLength < 0 || payloadLength >= length || \
		offset + length + extraLength > sessionInfoPtr->sendBufSize )
		retIntError();

	/* Evaluate the number of padding bytes that we need to add to a packet
	   to make it a multiple of the cipher block size long, with a minimum
	   padding size of SSH2_MIN_PADLENGTH_SIZE bytes.  Note that this padding
	   is required even when there's no encryption being applied(?), although 
	   we set the padding to all zeroes in this case */
	if( useQuantisedPadding )
		{
		/* It's something like a user-authentication packet that (probably) 
		   contains a password, make it fixed-length to hide the length 
		   information */
		for( padLength = 256;
			 ( length + SSH2_MIN_PADLENGTH_SIZE ) > padLength;
			 padLength += 256 );
		padLength -= length;
		}
	else
		{
		padLength = roundUp( length + SSH2_MIN_PADLENGTH_SIZE,
							 padBlockSize ) - length;
		}
	assert( padLength >= SSH2_MIN_PADLENGTH_SIZE && padLength < 256 );
	if( padLength < SSH2_MIN_PADLENGTH_SIZE || padLength >= 256 )
		retIntError();
	extraLength += padLength;

	/* Make sure that there's enough room for the padding and MAC */
	status = sMemGetDataBlockAbs( stream, offset, &bufStartPtr, 
								  length + extraLength );
	if( cryptStatusError( status ) )
		{
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_OVERFLOW );
		}

	/* Add the SSH packet header, padding, and MAC:

		uint32		length (excluding MAC size)
		byte		padLen
	  [	byte[]		data ]
		byte[]		padding
		byte[]		MAC */
	if( isWriteableStream )
		{
		sseek( stream, offset );
		writeUint32( stream, 1 + payloadLength + padLength );
		sputc( stream, padLength );
		sSkip( stream, payloadLength );
		}
	else
		{
		STREAM headerStream;

		/* If it's a non-writeable stream we have to insert the header data
		   directly into the stream buffer */
		assert( offset == 0 && \
				stell( stream ) == SSH2_HEADER_SIZE + payloadLength );
		sMemOpen( &headerStream, bufStartPtr, SSH2_HEADER_SIZE );
		writeUint32( &headerStream, 1 + payloadLength + padLength );
		sputc( &headerStream, padLength );
		sMemDisconnect( &headerStream );
		}
	if( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE )
		{
		MESSAGE_DATA msgData;
		BYTE padding[ 256 + 8 ];
		const int totalLength = SSH2_HEADER_SIZE + payloadLength + padLength;

		/* Append the padding */
		setMessageData( &msgData, padding, padLength );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		if( isWriteableStream )
			status = swrite( stream, padding, padLength );
		else
			{
			STREAM trailerStream;

			assert( stell( stream ) == length );
			sMemOpen( &trailerStream, ( BYTE * ) bufStartPtr + length, 
					  padLength );
			status = swrite( &trailerStream, padding, padLength );
			sMemDisconnect( &trailerStream );
			sSkip( stream, padLength );
			}
		if( cryptStatusError( status ) )
			retIntError();

		/* MAC the data and append the MAC to the stream.  We skip the 
		   length value at the start since this is computed by the MAC'ing 
		   code */
		status = createMacSSH( sessionInfoPtr->iAuthOutContext,
							   sshInfo->writeSeqNo, 
							   ( BYTE * ) bufStartPtr + LENGTH_SIZE,
							   length + extraLength - LENGTH_SIZE, 
							   totalLength - LENGTH_SIZE );
		if( cryptStatusError( status ) )
			return( status );
		sSkip( stream, sessionInfoPtr->authBlocksize );

		/* Encrypt the entire packet except for the MAC */
		status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
								  IMESSAGE_CTX_ENCRYPT, bufStartPtr,
								  totalLength );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		{
		BYTE padding[ 256 + 8 ];

		/* If there's no security in effect yet, the padding is all zeroes */
		assert( isWriteableStream );
		memset( padding, 0, padLength );
		status = swrite( stream, padding, padLength );
		if( cryptStatusError( status ) )
			retIntError();
		}
	sshInfo->writeSeqNo++;

	return( CRYPT_OK );
	}

int sendPacketSSH2( SESSION_INFO *sessionInfoPtr, STREAM *stream,
					const BOOLEAN sendOnly )
	{
	int length = stell( stream );
	void *dataPtr;
	int status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	/* If it's not a pre-assembled packet, wrap up the payload in an SSH
	   packet */
	if( !sendOnly )
		{
		status = wrapPacketSSH2( sessionInfoPtr, stream, 0, FALSE, TRUE );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Send the contents of the stream to the peer */
	length = stell( stream );
	status = sMemGetDataBlockAbs( stream, 0, &dataPtr, length );
	if( cryptStatusOK( status ) )
		status = swrite( &sessionInfoPtr->stream, dataPtr, length );
	if( cryptStatusError( status ) && \
		!( sessionInfoPtr->flags & SESSION_NOREPORTERROR ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  &sessionInfoPtr->errorInfo );
		return( status );
		}
	return( CRYPT_OK );	/* swrite() returns a byte count */
	}
#endif /* USE_SSH */

⌨️ 快捷键说明

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