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

📄 ssh2_svr.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Exchange keys with the client */

static int exchangeServerKeys( SESSION_INFO *sessionInfoPtr,
							   SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	KEYAGREE_PARAMS keyAgreeParams;
	RESOURCE_DATA msgData;
	BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
	int length, length2, sigLength, status;

	/* Create the server DH value */
	memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
	status = krnlSendMessage( handshakeInfo->iServerCryptContext,
							  IMESSAGE_CTX_ENCRYPT, &keyAgreeParams,
							  sizeof( KEYAGREE_PARAMS ) );
	if( cryptStatusError( status ) )
		return( status );

	/* Build the DH phase 2 keyex packet:

		byte		type = SSH2_MSG_KEXDH_REPLY / SSH2_MSG_KEXDH_GEX_REPLY
		string		server key/certificate
			string	"ssh-rsa"	"ssh-dss"
			mpint	e			p
			mpint	n			q
			mpint				g
			mpint				y
		mpint		y'
		string		signature of handshake data
			string	"ssh-rsa"	"ssh-dss"
			string	signature	signature
		...

	   The specification also makes provision for using X.509 and PGP keys,
	   but only so far as to say that keys and signatures are in "X.509 DER"
	   and "PGP" formats, neither of which actually explain what it is
	   that's sent or signed (and no-one on the SSH list can agree on what
	   they're supposed to look like), so we can't use either of them */
	bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
	*bufPtr++ = handshakeInfo->requestedServerKeySize ? \
				SSH2_MSG_KEXDH_GEX_REPLY : SSH2_MSG_KEXDH_REPLY;
	setMessageData( &msgData, bufPtr, 128 + ( CRYPT_MAX_PKCSIZE * 4 ) );
	status = krnlSendMessage( sessionInfoPtr->privateKey,
							  IMESSAGE_GETATTRIBUTE_S, &msgData,
							  CRYPT_IATTRIBUTE_KEY_SSH2 );
	if( cryptStatusError( status ) )
		return( status );
	krnlSendMessage( handshakeInfo->iExchangeHashcontext, IMESSAGE_CTX_HASH,
					 bufPtr, msgData.length );
	bufPtr += msgData.length;
	handshakeInfo->serverKeyexValueLength = \
					encodeMPI( handshakeInfo->serverKeyexValue, 
							   keyAgreeParams.publicValue,
							   keyAgreeParams.publicValueLen );
	memcpy( bufPtr, handshakeInfo->serverKeyexValue, 
			handshakeInfo->serverKeyexValueLength );
	bufPtr += handshakeInfo->serverKeyexValueLength;

	/* Complete phase 2 of the DH key agreement process to obtain the shared
	   secret value */
	status = completeKeyex( sessionInfoPtr, handshakeInfo, TRUE );
	if( cryptStatusError( status ) )
		return( status );

	/* Sign the hash */
	status = iCryptCreateSignatureEx( bufPtr, &sigLength,
							min( sessionInfoPtr->sendBufSize - \
								 ( ( bufPtr - sessionInfoPtr->sendBuffer ) + 128 ),
								 DEFAULT_PACKET_SIZE ),
							CRYPT_IFORMAT_SSH, sessionInfoPtr->privateKey,
							handshakeInfo->iExchangeHashcontext,
							CRYPT_UNUSED, CRYPT_UNUSED );
	krnlSendNotifier( handshakeInfo->iExchangeHashcontext,
					  IMESSAGE_DECREFCOUNT );
	handshakeInfo->iExchangeHashcontext = CRYPT_ERROR;
	if( cryptStatusError( status ) )
		return( status );
	bufPtr += sigLength;
	status = length = wrapPacket( sessionInfoPtr, sessionInfoPtr->sendBuffer,
				bufPtr - ( sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE ) );
	if( cryptStatusError( status ) )
		return( status );

	/* Build our change cipherspec message and send the whole mess through
	   to the client:

		...
		byte	type = SSH2_MSG_NEWKEYS */
	bufPtr = sessionInfoPtr->sendBuffer + length;
	bufPtr[ SSH2_HEADER_SIZE ] = SSH2_MSG_NEWKEYS;
	status = length2 = wrapPacket( sessionInfoPtr, bufPtr, ID_SIZE );
	if( !cryptStatusError( status ) )
		status = sendPacketSSH2( sessionInfoPtr, length + length2, TRUE );
	return( status );
	}

/* Complete the handshake with the client */

static int completeServerHandshake( SESSION_INFO *sessionInfoPtr,
									SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	BYTE *bufPtr;
	int length, stringLength, status;

	/* Set up the security information required for the session */
	status = initSecurityInfo( sessionInfoPtr, handshakeInfo );
	if( cryptStatusError( status ) )
		return( status );

	/* Wait for the client's change cipherspec message */
	status = readPacketSSH2( sessionInfoPtr, SSH2_MSG_NEWKEYS );
	if( cryptStatusError( status ) )
		return( status );

	/* We've sent the change cipherspec message, from now on all data is
	   encrypted and MAC'ed */
	sessionInfoPtr->flags |= SESSION_ISSECURE;

	/* Wait for the client's authentication packets.  For some reason SSHv2
	   requires the use of two authentication messages, an "I'm about to
	   authenticate" packet and an "I'm authenticating" packet.  First we 
	   handle the "I'm about to authenticate":

		byte	type = SSH2_MSG_SERVICE_REQUEST
		string	service_name = "ssh-userauth"

		byte	type = SSH2_MSG_SERVICE_ACCEPT
		string	service_name = "ssh-userauth" */
	length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_SERVICE_REQUEST );
	if( cryptStatusError( length ) )
		return( length );
	bufPtr = sessionInfoPtr->receiveBuffer + ID_SIZE;
	stringLength = ( int ) mgetLong( bufPtr );
	if( length != ID_SIZE + LENGTH_SIZE + stringLength || \
		stringLength != 12 || memcmp( bufPtr, "ssh-userauth", 12 ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid service request packet length %d, string length "
				"%d", length, stringLength );
	bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
	*bufPtr++ = SSH2_MSG_SERVICE_ACCEPT;
	length = encodeString( bufPtr, "ssh-userauth", 0 );
	status = sendPacketSSH2( sessionInfoPtr, ID_SIZE + length, FALSE );
	if( cryptStatusError( status ) )
		return( status );

	/* Wait for the second part of the authentication:

		byte	type = SSH2_MSG_USERAUTH_REQUEST
		string	user_name
		string	service_name = "ssh-connection"
		string	method_name = "none" | "password"
		[ boolean	FALSE ]
		[ string	password ]

	   The client can send a method-type of "none" to indicate that it'd
	   like the server to return a list of allowed authentication types, if
	   we get a packet of this kind we return our allowed types list.  Unlike
	   SSHv1, SSHv2 properly identifies public keys, however because of its
	   complexity (several more states added to the state machine because of
	   SSHv2's propensity for carrying out any negotiation it performs in
	   little bits and pieces) we don't support this form of authentication 
	   until someone specifically requests it */
	while( cryptStatusOK( status ) )
		{
		length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_USERAUTH_REQUEST );
		if( cryptStatusError( length ) )
			return( length );
		bufPtr = sessionInfoPtr->receiveBuffer + ID_SIZE;
		stringLength = ( int ) mgetLong( bufPtr );
		if( length < ID_SIZE + ( LENGTH_SIZE + stringLength ) + \
					 ( LENGTH_SIZE + 14 ) + ( LENGTH_SIZE + 4 ) || \
			stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid user auth packet length %d, string length %d",
					length, stringLength );
		memcpy( sessionInfoPtr->userName, bufPtr, stringLength );
		sessionInfoPtr->userNameLength = stringLength;
		bufPtr += stringLength;
		length -= ID_SIZE + ( LENGTH_SIZE + stringLength );
		stringLength = ( int ) mgetLong( bufPtr );
		if( stringLength != 14 || memcmp( bufPtr, "ssh-connection", 14 ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid user auth service string length %d",
					stringLength );
		bufPtr += stringLength;
		length -= ( LENGTH_SIZE + stringLength );
		stringLength = ( int ) mgetLong( bufPtr );
		if( length < LENGTH_SIZE + stringLength )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid user auth method length %d, string length %d",
					length, stringLength );

		/* If the client wants a list of supported authentication mechanisms,
		   tell them what we allow and await further input:

			byte	type = SSH2_MSG_USERAUTH_FAILURE
			string	allowed_authent
			boolean	partial_success = FALSE */
		if( stringLength == 4 && !memcmp( bufPtr, "none", 4 ) )
			{
			bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
			*bufPtr++ = SSH2_MSG_USERAUTH_FAILURE;
			length = encodeString( bufPtr, algoStringUserauthentList, 0 );
			bufPtr[ length ] = 0;
			status = sendPacketSSH2( sessionInfoPtr, ID_SIZE + length + \
													 BOOLEAN_SIZE, FALSE );
			continue;
			}

		/* The only other permitted type is password authentication */
		if( stringLength != 8 || memcmp( bufPtr, "password", 8 ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid user auth method name, string length %d", 
					stringLength );
		break;
		}
	if( cryptStatusError( status ) )
		return( status );

	/* We got authentication info, save it for the caller to check */
	bufPtr += stringLength + BOOLEAN_SIZE;
	length -= LENGTH_SIZE + stringLength + BOOLEAN_SIZE;
	stringLength = ( int ) mgetLong( bufPtr );
	if( length != LENGTH_SIZE + stringLength || \
		stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid user auth payload length %d, string length %d",
				length, stringLength );
	memcpy( sessionInfoPtr->password, bufPtr, stringLength );
	sessionInfoPtr->passwordLength = stringLength;

	/* Acknowledge the authentication:
	
		byte	type = SSH2_MSG_USERAUTH_SUCCESS */
	bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
	*bufPtr = SSH2_MSG_USERAUTH_SUCCESS;
	status = sendPacketSSH2( sessionInfoPtr, ID_SIZE, FALSE );
	if( cryptStatusError( status ) )
		return( status );

	/* Handle the channel open */
	length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_CHANNEL_OPEN );
	if( cryptStatusError( length ) )
		return( length );
	status = processChannelOpen( sessionInfoPtr, 
								 sessionInfoPtr->receiveBuffer + ID_SIZE, 
								 length - ID_SIZE );
	if( cryptStatusError( status ) )
		return( status );

	/* Process any further junk that the caller may throw at us until we get 
	   a request that we can handle */
	while( !cryptStatusError( status = length = \
				readPacketSSH2( sessionInfoPtr, SSH2_MSG_SPECIAL_REQUEST ) ) )
		{
		status = processRequest( sessionInfoPtr, 
								 sessionInfoPtr->receiveBuffer + ID_SIZE, 
								 length - ID_SIZE );
		if( cryptStatusError( status ) )
			return( ( status == OK_SPECIAL ) ? CRYPT_OK : status );
		}
	return( status );
	}

/****************************************************************************
*																			*
*							Session Access Routines							*
*																			*
****************************************************************************/

void initSSH2serverProcessing( SESSION_INFO *sessionInfoPtr,
							   SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	handshakeInfo->beginHandshake = beginServerHandshake;
	handshakeInfo->exchangeKeys = exchangeServerKeys;
	handshakeInfo->completeHandshake = completeServerHandshake;
	}
#endif /* SSH2 */

⌨️ 快捷键说明

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