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

📄 ssh2.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
							 padBlockSize ) - length;
	assert( padLength >= SSH2_MIN_PADLENGTH_SIZE && padLength < 256 );

	/* Add the SSH packet header:

		uint32		length
		byte		padLen
		byte[]		data
		byte[]		padding
		byte[]		MAC */
	mputLong( bufPtr, ( long ) ( length - LENGTH_SIZE ) + padLength );
	*bufPtr++ = padLength;
	bufPtr += dataLength;
	if( sessionInfoPtr->flags & SESSION_ISSECURE )
		{
		RESOURCE_DATA msgData;
		BYTE seqBuffer[ 8 ], *seqBufPtr = seqBuffer;
		const int payloadLength = SSH2_HEADER_SIZE + dataLength + padLength;

		/* Append the padding */
		setMessageData( &msgData, bufPtr, padLength );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		bufPtr += padLength;
		assert( bufPtr == bufStartPtr + payloadLength );

		/* MAC the data:

			HMAC( seqNo || payload ) */
		mputLong( seqBufPtr, sessionInfoPtr->writeSeqNo );
		krnlSendMessage( sessionInfoPtr->iAuthOutContext,
						 IMESSAGE_DELETEATTRIBUTE, NULL,
						 CRYPT_CTXINFO_HASHVALUE );
		krnlSendMessage( sessionInfoPtr->iAuthOutContext,
						 IMESSAGE_CTX_HASH, seqBuffer, LENGTH_SIZE );
		krnlSendMessage( sessionInfoPtr->iAuthOutContext,
						 IMESSAGE_CTX_HASH, ( void * ) bufStartPtr,
						 payloadLength );
		krnlSendMessage( sessionInfoPtr->iAuthOutContext,
						 IMESSAGE_CTX_HASH, "", 0 );
		setMessageData( &msgData, bufPtr, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( sessionInfoPtr->iAuthOutContext,
								  IMESSAGE_GETATTRIBUTE_S, &msgData,
								  CRYPT_CTXINFO_HASHVALUE );
		if( cryptStatusError( status ) )
			return( status );

		/* Encrypt the entire packet except for the MAC */
		status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
								  IMESSAGE_CTX_ENCRYPT, ( void * ) bufStartPtr,
								  payloadLength );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		/* If there's no security in effect yet, the padding is all zeroes */
		memset( bufPtr, 0, padLength );
	sessionInfoPtr->writeSeqNo++;

	return( SSH2_HEADER_SIZE + dataLength + padLength + \
			( ( sessionInfoPtr->flags & SESSION_ISSECURE ) ? \
			  sessionInfoPtr->authBlocksize : 0 ) );
	}

int sendPacketSSH2( SESSION_INFO *sessionInfoPtr, const int dataLength,
					const BOOLEAN sendOnly )
	{
	int length = dataLength, status;

	if( !sendOnly )
		{
		length = wrapPacket( sessionInfoPtr, sessionInfoPtr->sendBuffer,
							 dataLength );
		if( cryptStatusError( length ) )
			return( length );
		}
	status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->sendBuffer, 
					 length );
	if( cryptStatusError( status ) )
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
	return( CRYPT_OK );
	}

/* Process a client/server hello packet */

int processHello( SESSION_INFO *sessionInfoPtr, 
				  SSH_HANDSHAKE_INFO *handshakeInfo, int *keyexLength,
				  const BOOLEAN isServer )
	{
	ALGOID_INFO algoIDInfo;
	BYTE *bufPtr;
	BOOLEAN preferredAlgoMismatch = FALSE;
	int length, stringLength, status;

	/* Process the client/server hello:

		byte		type = SSH2_MSG_KEXINIT
		byte[16]	cookie
		string		keyex algorithms
		string		pubkey algorithms
		string		client_crypto algorithms
		string		server_crypto algorithms
		string		client_mac algorithms
		string		server_mac algorithms
		string		client_compression algorithms
		string		server_compression algorithms
		string		client_language
		string		server_language
		boolean		first_keyex_packet_follows
		uint32		reserved

	   The cookie isn't explicitly processed as with SSHv1 since SSHv2
	   hashes the entire server hello message */
	length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_KEXINIT );
	if( cryptStatusError( length ) )
		return( length );
	if( length < ID_SIZE + SSH2_COOKIE_SIZE + \
				 ( ( LENGTH_SIZE + SSH2_MIN_ALGOID_SIZE ) * 6 ) + \
				 ( LENGTH_SIZE * 4 ) + BOOLEAN_SIZE + UINT_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid hello packet length %d", length );
	*keyexLength = length;
	bufPtr = sessionInfoPtr->receiveBuffer + ID_SIZE + SSH2_COOKIE_SIZE;
	length -= ID_SIZE + SSH2_COOKIE_SIZE;
	if( isServer )
		{
		/* DES is a placeholder for EDH (as opposed to the standard static
		   DH) */
		setAlgoIDInfo( &algoIDInfo, algoStringKeyexTbl, CRYPT_ALGO_DES, 
					   GETALGO_FIRST_MATCH_WARN );
		}
	else
		{
		setAlgoIDInfo( &algoIDInfo, algoStringKeyexTbl, CRYPT_ALGO_NONE, 
					   GETALGO_BEST_MATCH );
		}
	status = getAlgoIDEx( &algoIDInfo, bufPtr, length, sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );
	if( algoIDInfo.prefAlgoMismatch )
		/* We didn't get a match for our first choice, remember that we have
		   to discard any guessed keyex that may follow */
		preferredAlgoMismatch = TRUE;
	if( algoIDInfo.algo == CRYPT_ALGO_DES )
		/* If the keyex algorithm is the DES placeholder, we're using 
		   ephemeral rather than static DH keys and need to negotiate the 
		   keyex key before we can perform the exchange */
		handshakeInfo->requestedServerKeySize = SSH2_DEFAULT_KEYSIZE;
	bufPtr += algoIDInfo.algoStringLength;
	length -= algoIDInfo.algoStringLength;
	if( isServer )
		{
		setAlgoIDInfo( &algoIDInfo, handshakeInfo->algoStringPubkeyTbl, 
					   handshakeInfo->pubkeyAlgo, GETALGO_FIRST_MATCH_WARN );
		}
	else
		{
		setAlgoIDInfo( &algoIDInfo, handshakeInfo->algoStringPubkeyTbl, 
					   CRYPT_ALGO_NONE, GETALGO_BEST_MATCH );
		}
	status = getAlgoIDEx( &algoIDInfo, bufPtr, length, sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );
	if( !isServer )
		handshakeInfo->pubkeyAlgo = algoIDInfo.algo;
	if( algoIDInfo.prefAlgoMismatch )
		/* We didn't get a match for our first choice, remember that we have
		   to discard any guessed keyex that may follow */
		preferredAlgoMismatch = TRUE;
	bufPtr += algoIDInfo.algoStringLength;
	length -= algoIDInfo.algoStringLength;
	stringLength = getAlgoIDpair( ( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
									algoStringEncrTblServer : \
									algoStringEncrTblClient, 
								  &sessionInfoPtr->cryptAlgo, bufPtr, 
								  length, isServer, sessionInfoPtr );
	if( cryptStatusError( stringLength ) )
		return( stringLength );
	bufPtr += stringLength;
	length -= stringLength;
	stringLength = getAlgoIDpair( algoStringMACTbl,
								  &sessionInfoPtr->integrityAlgo, bufPtr, 
								  length, isServer, sessionInfoPtr );
	if( cryptStatusError( stringLength ) )
		return( stringLength );
	bufPtr += stringLength;
	length -= stringLength;
	stringLength = getAlgoIDpair( algoStringCoprTbl, NULL, bufPtr, 
								  length, isServer, sessionInfoPtr );
	if( cryptStatusError( stringLength ) )
		return( stringLength );
	bufPtr += stringLength;
	length -= stringLength;
	stringLength = mgetLong( bufPtr );
	if( stringLength < 0 || stringLength > length + LENGTH_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid hello packet client language string length %d", 
				stringLength );
	bufPtr += stringLength;
	length -= stringLength + LENGTH_SIZE;
	stringLength = mgetLong( bufPtr );
	if( stringLength < 0 || stringLength > length + LENGTH_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid hello packet server language string length %d", 
				stringLength );
	bufPtr += stringLength;
	length -= stringLength + LENGTH_SIZE;
	if( length != BOOLEAN_SIZE + UINT_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid hello packet length remainder size %d, expected "
				"%d", length, BOOLEAN_SIZE + UINT_SIZE );
	if( *bufPtr && preferredAlgoMismatch )
		/* There's a guessed keyex following this packet and we didn't match
		   the first-choice keyex/pubkey algorithm, tell the caller to skip 
		   it */
		return( OK_SPECIAL );
	return( CRYPT_OK );
	}

/* Process a global or channel request.  At the moment it's set up in allow-
   all mode, it may be necessary to switch to deny-all instead if clients 
   pop up that submit things that cause problems */

static int sendRequestResponse( SESSION_INFO *sessionInfoPtr,
								const BOOLEAN isChannelRequest,
								const BOOLEAN isSuccessful )
	{
	BYTE *bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;

	/* Indicate that the request succeeded/was denied:

		byte	type = SSH2_MSG_CHANNEL/GLOBAL_SUCCESS/FAILURE
	  [	uint32	channel_no		- For channel reqs ] */
	if( isChannelRequest )
		{
		*bufPtr++ = isSuccessful ? SSH2_MSG_CHANNEL_SUCCESS : \
								   SSH2_MSG_CHANNEL_FAILURE;
		mputLong( bufPtr, sessionInfoPtr->sshChannel );
		return( sendPacketSSH2( sessionInfoPtr, ID_SIZE + UINT_SIZE,
								FALSE ) );
		}
	*bufPtr++ = isSuccessful ? SSH2_MSG_GLOBAL_SUCCESS : \
							   SSH2_MSG_GLOBAL_FAILURE;
	return( sendPacketSSH2( sessionInfoPtr, ID_SIZE, FALSE ) );
	}

int processRequest( SESSION_INFO *sessionInfoPtr, const BYTE *data,
					const int dataLength )
	{
	static const FAR_BSS char *invalidRequests[] = \
			{ "x11-req", NULL };
	static const FAR_BSS char *validRequests[] = \
			{ "shell", "exec", "subsystem", NULL };
#if 0	/* Anything not matched defaults to being treated as a no-op */
	static const FAR_BSS char *noopRequests[] = \
			{ "pty-req", "env", "window-change", "xon-xoff", NULL };
#endif /* 0 */
	const BOOLEAN isChannelRequest = \
			( sessionInfoPtr->sshPacketType == SSH2_MSG_CHANNEL_REQUEST );
	BOOLEAN wantReply = FALSE;
	const char *requestNamePtr;
	int length = dataLength, stringLength, i;
	int extraLength = isChannelRequest ? UINT_SIZE : 0;

	/* Process the channel/global request:

		byte	type = SSH2_MSG_CHANNEL_REQUEST
	  [	uint32	recipient_channel	- For channel reqs ]
		string	request_type
		boolean	want_reply
		[...] */
	if( length < extraLength + ( LENGTH_SIZE + 1 ) + BOOLEAN_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid global/channel request packet length %d",
				length );
	if( isChannelRequest )
		{
		long channelNo;

		channelNo = mgetLong( data );
		if( channelNo != sessionInfoPtr->sshChannel )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid channel number %d, expected %d",
					channelNo, sessionInfoPtr->sshChannel );
		}
	stringLength = mgetLong( data );
	if( stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE || \
		length < extraLength + ( LENGTH_SIZE + stringLength ) + \
				 BOOLEAN_SIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid global/channel request packet length %d, "
				"string length %d", length, stringLength );
	length -= extraLength + ( LENGTH_SIZE + stringLength ) + BOOLEAN_SIZE;
	if( data[ stringLength ] )
		wantReply = TRUE;
	requestNamePtr = data;
	data += stringLength + BOOLEAN_SIZE;

	/* Check for requests that we don't allow */
	for( i = 0; invalidRequests[ i ] != NULL; i++ )
		if( stringLength == strlen( invalidRequests[ i ] ) && \
			!memcmp( requestNamePtr, invalidRequests[ i ], stringLength ) )
			return( sendRequestResponse( sessionInfoPtr, 
										 isChannelRequest, FALSE ) );

	/* If we're being asked for a subsystem, record the type */
	if( stringLength == 9 && !memcmp( requestNamePtr, "subsystem", 9 ) )
		{
		const int subsystemLength = mgetLong( data );

		/*	[...]
			string	subsystem_name */
		if( length != ( LENGTH_SIZE + subsystemLength ) || \
			subsystemLength <= 0 || subsystemLength > CRYPT_MAX_TEXTSIZE )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid channel request payload length %d, "
					"subsystem length %d", length, subsystemLength );
		memcpy( sessionInfoPtr->sshSubsystem, data, subsystemLength );
		sessionInfoPtr->sshSubsystemLength = subsystemLength;
		}

	/* If we're being asked for port forwarding, get the address and port 
	   information */
	if( stringLength == 13 && !memcmp( requestNamePtr, "tcpip-forward", 13 ) )
		{
		int status;

		/*	[...]
			string	address_to_bind (e.g. "0.0.0.0")
			uint32	port_to_bind */
		status = getAddressAndPort( sessionInfoPtr, data, length );
		if( cryp

⌨️ 快捷键说明

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