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

📄 ssh2_svr.c

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

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

#ifdef USE_SSH2

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

/* SSHv2 algorithm names sent to client, in preferred algorithm order.  
   Since we have a fixed algorithm for our public key (determined by the key
   type), we only send a single value for this that's evaluated at runtime,
   so there's no list for this defined.
   
   Note that these tables must match the algoStringXXXTbl values in ssh2.c */

static const FAR_BSS CRYPT_ALGO_TYPE algoKeyexList[] = {
	CRYPT_ALGO_DH, CRYPT_ALGO_NONE };
static const FAR_BSS char *algoStringCoprList = "none";
static const FAR_BSS CRYPT_ALGO_TYPE algoEncrList[] = {
	/* We can't list AES as an option because the peer can pick up anything
	   it wants from the list as its preferred choice, which means that if 
	   we're talking to any non-cryptlib implementation they always go for 
	   AES even though it doesn't currently have the provenance of 3DES.
	   Once AES passes the five-year test this option can be enabled */
	CRYPT_ALGO_3DES, /*CRYPT_ALGO_AES,*/ CRYPT_ALGO_BLOWFISH, 
	CRYPT_ALGO_CAST, CRYPT_ALGO_IDEA, CRYPT_ALGO_RC4, CRYPT_ALGO_NONE };
static const FAR_BSS CRYPT_ALGO_TYPE algoMACList[] = { 
	CRYPT_ALGO_HMAC_SHA, CRYPT_ALGO_HMAC_MD5, CRYPT_ALGO_NONE };
static const FAR_BSS char *algoStringUserauthentList = "password";

/* Encode a list of available algorithms */

static int putAlgoList( BYTE **bufPtrPtr, const CRYPT_ALGO_TYPE algoList[] )
	{
	static const FAR_BSS ALGO_STRING_INFO algoStringMapTbl[] = {
		{ "ssh-rsa", CRYPT_ALGO_RSA },
		{ "ssh-dss", CRYPT_ALGO_DSA },
		{ "3des-cbc", CRYPT_ALGO_3DES },
		{ "aes128-cbc", CRYPT_ALGO_AES },
		{ "blowfish-cbc", CRYPT_ALGO_BLOWFISH },
		{ "cast128-cbc", CRYPT_ALGO_CAST },
		{ "idea-cbc", CRYPT_ALGO_IDEA },
		{ "arcfour", CRYPT_ALGO_RC4 },
		{ "diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1", CRYPT_ALGO_DH },
		{ "diffie-hellman-group1-sha1", CRYPT_ALGO_DH },
		{ "hmac-sha1", CRYPT_ALGO_HMAC_SHA },
		{ "hmac-md5", CRYPT_ALGO_HMAC_MD5 },
		{ "none", CRYPT_ALGO_NONE },
		};
	const char *availableAlgos[ 16 ];
	int noAlgos = 0, length = 0, algoIndex;

	/* Walk down the list of algorithms remembering the encoded name of each 
	   one that's available for use */
	for( algoIndex = 0; algoList[ algoIndex ] != CRYPT_ALGO_NONE; algoIndex++ )
		if( algoAvailable( algoList[ algoIndex ] ) )
			{
			int i;

			for( i = 0; algoStringMapTbl[ i ].algo != CRYPT_ALGO_NONE && \
						algoStringMapTbl[ i ].algo != algoList[ algoIndex ]; i++ );
			assert( algoStringMapTbl[ i ].algo != CRYPT_ALGO_NONE );
			availableAlgos[ noAlgos++ ] = algoStringMapTbl[ i ].name;
			length += strlen( algoStringMapTbl[ i ].name );
			if( noAlgos > 1 )
				length++;			/* Room for comma delimiter */
			}

	/* Encode the list of available algorithms into a comma-separated string */
	if( bufPtrPtr != NULL )
		{
		BYTE *bufPtr = *bufPtrPtr;

		mputLong( bufPtr, length );
		for( algoIndex = 0; algoIndex < noAlgos; algoIndex++ )
			{
			const int algoLen = strlen( availableAlgos[ algoIndex ] );

			if( algoIndex > 0 )
				*bufPtr++ = ',';	/* Add comma delimiter */
			memcpy( bufPtr, availableAlgos[ algoIndex ], algoLen );
			bufPtr += algoLen;
			}

		*bufPtrPtr = bufPtr;
		}
	return( LENGTH_SIZE + length );
	}

/* Process a channel open */

int getAddressAndPort( SESSION_INFO *sessionInfoPtr, const BYTE *data,
					   const int dataLength )
	{
	char portBuffer[ 16 ];
	long port;
	int length = dataLength, stringLength, portLength;

	/* Get the host and port and convert it into string form for the user to 
	   read:

		string	host
		uint32	port */
	stringLength = ( int ) mgetLong( data );
	if( stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE - 4 || \
		length < ( LENGTH_SIZE + stringLength ) + UINT_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid port forwarding host name length %d", 
				stringLength );
	memcpy( sessionInfoPtr->sshPortForward, data, stringLength );
	data += stringLength;
	port = mgetLong( data );
	length -= ( LENGTH_SIZE + stringLength ) + UINT_SIZE;
	portBuffer[ 0 ] = ':';
	portLength = sprintf( portBuffer + 1, "%ld", port ) + 1;
	if( stringLength + portLength <= CRYPT_MAX_TEXTSIZE )
		{
		memcpy( sessionInfoPtr->sshPortForward + stringLength,
				portBuffer, portLength );
		stringLength += portLength;
		}
	sessionInfoPtr->sshPortForwardLength = stringLength;
	return( CRYPT_OK );
	}

int processChannelOpen( SESSION_INFO *sessionInfoPtr, const BYTE *data,
						const int dataLength )
	{
	BYTE *bufPtr;
	BOOLEAN isPortForwarding = FALSE;
	long maxPacketSize;
	int length = dataLength, stringLength;

	/* Read the channel open request.  The ID byte has already been read by
	   the caller:

	  [	byte	type = SSH2_MSG_CHANNEL_OPEN ]
		string	channel_type = "session" | "direct-tcpip"
		uint32	sender_channel
		uint32	initial_window_size
		uint32	max_packet_size
	  [ string	host_to_connect		- For port-forwarding
		uint32	port_to_connect
		string	originator_IP_address
		uint32	originator_port ]
	
	   Some clients open a standard (non-forwarded) channel when they connect
	   for general comms and then later open a forwarded channel when client 
	   -> server forwarding is being used and a forwarded connection arrives, 
	   we interpret this to mean that the forwarded channel should supersede 
	   the original non-forwarded one, performed by simply copying the new 
	   channel info over the top of the existing info */
	stringLength = ( int ) mgetLong( data );
	if( stringLength <= 0 || \
		length < ( LENGTH_SIZE + stringLength ) + \
				 UINT_SIZE + UINT_SIZE + UINT_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid channel open packet length %d, string length %d",
				length, stringLength );
	if( stringLength != 7 || memcmp( data, "session", 7 ) )
		{
		/* It's not a normal channel open, see if the caller is trying to
		   do port forwarding */
		if( stringLength != 12 || memcmp( data, "direct-tcpip", 12 ) )
			{
			char stringBuffer[ CRYPT_MAX_TEXTSIZE + 1 ];

			/* It's something else, report it as an error */
			stringLength = min( stringLength, CRYPT_MAX_TEXTSIZE );
			memcpy( stringBuffer, data, stringLength );
			stringBuffer[ stringLength ] = '\0';
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid channel open channel type '%'", stringBuffer );
			}
		isPortForwarding = TRUE;
		}
	data += stringLength;
	length -= ( LENGTH_SIZE + stringLength );
	sessionInfoPtr->sshChannel = mgetLong( data );
	data += UINT_SIZE;					/* Skip window size */
	length -= UINT_SIZE + UINT_SIZE;
	sessionInfoPtr->sshWindowCount = 0;	/* New window, reset count */
	maxPacketSize = mgetLong( data );
	if( maxPacketSize < 16 || maxPacketSize > 0x100000L )
		/* General sanity check to make sure that the packet size is in the 
		   range 16 bytes ... 16MB */
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid maximum packet size %d", maxPacketSize );
	length -= UINT_SIZE;
	if( isPortForwarding )
		{
		int status;

		/* Get the source and destination host information */
		if( length < ( LENGTH_SIZE + 1 ) + UINT_SIZE + \
					 ( LENGTH_SIZE + 1 ) + UINT_SIZE )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid port forwarding channel open data length %d", 
					length );
		status = getAddressAndPort( sessionInfoPtr, data, length );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		/* If it's a straight channel open, there shouldn't be any more 
		   data */
		if( length != 0 )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid additional %d data bytes in channel open", 
					length );

	/* Send back the open confirmation:

		byte	type = SSH2_MSG_CHANNEL_OPEN_CONFIRMATION
		uint32	recipient_channel = prev. sender_channel
		uint32	sender_channel
		uint32	initial_window_size = MAX_WINDOW_SIZE
		uint32	max_packet_size = bufSize

	   The SSHv2 spec doesn't really explain the semantics of the server's 
	   response to the channel open command, in particular whether the 
	   returned data size parameters are merely a confirmation of the 
	   client's requested values or whether the server is allowed to further 
	   modify them to suit its own requirements (or perhaps one is for send 
	   and the other for receive?).  In the absence of any further guidance, 
	   we try and comply with a client's request for smaller data 
	   quantities, but also return a smaller-than-requested data size value 
	   if they ask for too much data.

	   See the comments in the client-handshake code for the reason for the 
	   window size */
	bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
	*bufPtr++ = SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
	mputLong( bufPtr, sessionInfoPtr->sshChannel );		/* Recip.channel */
	mputLong( bufPtr, sessionInfoPtr->sshChannel );		/* Sender channel */
	mputLong( bufPtr, MAX_WINDOW_SIZE );				/* Window size */
	maxPacketSize = min( maxPacketSize, \
						 sessionInfoPtr->receiveBufSize - EXTRA_PACKET_SIZE );
	mputLong( bufPtr, maxPacketSize );
	return( sendPacketSSH2( sessionInfoPtr,
				bufPtr - ( sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE ),
				FALSE ) );
	}

/****************************************************************************
*																			*
*							Server-side Connect Functions					*
*																			*
****************************************************************************/

/* Perform the initial part of the handshake with the client */

static int beginServerHandshake( SESSION_INFO *sessionInfoPtr,
								 SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	static const FAR_BSS ALGO_STRING_INFO algoStringPubkeyRSATbl[] = {
		{ "ssh-rsa", CRYPT_ALGO_RSA },
		{ NULL, CRYPT_ALGO_NONE }

⌨️ 快捷键说明

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