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

📄 ssh1.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:

	/* Output the start of the session key packet:

		byte		cipher_type
		byte[8]		cookie
		mpint		double_enc_sessionkey
		uint32		protocol_flags */
	switch( sessionInfoPtr->cryptAlgo )
		{
		case CRYPT_ALGO_BLOWFISH:
			value = SSH1_CIPHER_BLOWFISH;
			break;
		case CRYPT_ALGO_DES:
			value = SSH1_CIPHER_DES;
			break;
		case CRYPT_ALGO_IDEA:
			value = SSH1_CIPHER_IDEA;
			break;
		case CRYPT_ALGO_RC4:
			value = SSH1_CIPHER_RC4;
			break;
		default:
			retIntError();
		}
	*bufPtr++ = value;
	memcpy( bufPtr, handshakeInfo->cookie, SSH1_COOKIE_SIZE );
	bufPtr += SSH1_COOKIE_SIZE;

	/* Generate the session ID and secure state information and XOR the
	   secure state with the session ID */
	generateSessionID( handshakeInfo );
	setMessageData( &msgData, handshakeInfo->secretValue, SSH1_SECRET_SIZE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_RANDOM );
	if( cryptStatusError( status ) )
		return( status );
	handshakeInfo->secretValueLength = SSH1_SECRET_SIZE;
	for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
		handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];

	/* Export the secure state information in double-encrypted form,
	   encrypted first with the server key, then with the host key */
	setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_PKCSIZE,
						  handshakeInfo->secretValue, SSH1_SECRET_SIZE,
						  CRYPT_UNUSED, handshakeInfo->iServerCryptContext,
						  CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT,
							  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
	if( cryptStatusError( status ) )
		return( status );
	length = mechanismInfo.wrappedDataLength;
	setMechanismWrapInfo( &mechanismInfo,
						  bufPtr + SSH1_MPI_LENGTH_SIZE, CRYPT_MAX_PKCSIZE,
						  buffer, length, CRYPT_UNUSED,
						  sessionInfoPtr->iKeyexCryptContext, CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT,
							  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
	if( cryptStatusError( status ) )
		return( status );
	length = bytesToBits( mechanismInfo.wrappedDataLength );
	mputWord( bufPtr, length );
	bufPtr += mechanismInfo.wrappedDataLength;
	clearMechanismInfo( &mechanismInfo );

	/* XOR the state with the session ID to recover the actual state */
	for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
		handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];

	/* Write the various flags */
	mputLong( bufPtr, 0 );		/* Protocol flags */

	/* Move the data up in the buffer to allow for the variable-length
	   padding and send it to the server */
	dataLength = bufPtr - sessionInfoPtr->sendBuffer;
	memmove( sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
			 getPadLength( dataLength ) + ID_SIZE,
			 sessionInfoPtr->sendBuffer, dataLength );
	return( sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_SESSION_KEY,
							dataLength, CRYPT_UNUSED ) );
	}

/* Complete the handshake with the server */

static int completeClientHandshake( SESSION_INFO *sessionInfoPtr,
									SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	const ATTRIBUTE_LIST *userNamePtr = \
				findSessionInfo( sessionInfoPtr->attributeList,
								 CRYPT_SESSINFO_USERNAME );
	const ATTRIBUTE_LIST *passwordPtr = \
				findSessionInfo( sessionInfoPtr->attributeList,
								 CRYPT_SESSINFO_PASSWORD );
	BYTE *bufPtr;
	int padLength, modulusLength, length, status;

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

	/* Read back the server ack and send the user name:
		string		username */
	status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
	if( cryptStatusError( status ) )
		return( status );
	padLength = getPadLength( LENGTH_SIZE + userNamePtr->valueLength );
	bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
	encodeString( bufPtr, userNamePtr->value, userNamePtr->valueLength );
	status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_USER,
							 LENGTH_SIZE + userNamePtr->valueLength,
							 CRYPT_UNUSED );
	if( cryptStatusError( status ) )
		return( status );

	/* Read back the server ack and send the authentication information if
	   required.  This information is optional, if the server returns a
	   failure packet (converted to an OK_SPECIAL return status) it means
	   authentication is required, otherwise it isn't and we're already
	   logged in */
	status = readPacketSSH1( sessionInfoPtr, SSH1_MSG_SPECIAL_USEROPT );
	if( status == OK_SPECIAL )
		{
		/* If there's a password present, we're using password-based
		   authentication:
			string		password */
		if( passwordPtr != NULL )
			{
			int maxLen, packetType, i;

			/* Since SSHv1 sends the packet length in the clear and uses
			   implicit-length padding, it reveals the length of the
			   encrypted password to an observer.  To get around this, we
			   send a series of packets of length 4...maxLen to the server,
			   one of which is the password, the rest are SSH_MSG_IGNOREs.
			   It's still possible for an attacker who can perform very
			   precise timing measurements to determine which one is the
			   password based on server response time, but it's a lot less
			   problematic than with a single packet.  Unfortunately, it's
			   also possible for an attacker to determine the password packet
			   by checking which one generates the password response, unless
			   the server somehow knows how many packets are coming reads
			   them all in a loop and only then sends a response, which
			   means that this defence isn't as effective as it seems */
			status = CRYPT_OK;
			for( maxLen = 16; maxLen <= passwordPtr->valueLength;
				 maxLen <<= 1 );
			for( i = min( 4, passwordPtr->valueLength );
				 i < maxLen && cryptStatusOK( status ); i++ )
				{
				padLength = getPadLength( LENGTH_SIZE + i );
				bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
													  padLength + ID_SIZE;
				if( i == passwordPtr->valueLength )
					{
					encodeString( bufPtr, passwordPtr->value,
								  passwordPtr->valueLength );
					packetType = SSH1_CMSG_AUTH_PASSWORD;
					}
				else
					{
					MESSAGE_DATA msgData;

					setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
									i );
					krnlSendMessage( SYSTEM_OBJECT_HANDLE,
									 IMESSAGE_GETATTRIBUTE_S, &msgData,
									 CRYPT_IATTRIBUTE_RANDOM_NONCE );
					encodeString( bufPtr, sessionInfoPtr->receiveBuffer, i );
					packetType = SSH1_MSG_IGNORE;
					}
				status = sendPacketSsh1( sessionInfoPtr, packetType,
										 LENGTH_SIZE + i, CRYPT_UNUSED );
				if( cryptStatusOK( status ) && \
					packetType == SSH1_CMSG_AUTH_PASSWORD )
					status = readPacketSSH1( sessionInfoPtr,
											 SSH1_MSG_SPECIAL_PWOPT );
				}
			}
		else
			{
			MECHANISM_WRAP_INFO mechanismInfo;
			MESSAGE_DATA msgData;
			BYTE challenge[ SSH1_CHALLENGE_SIZE + 8 ];
			BYTE response[ SSH1_RESPONSE_SIZE ];
			BYTE modulusBuffer[ ( ( SSH1_MPI_LENGTH_SIZE + \
									CRYPT_MAX_PKCSIZE ) * 2 ) + 8 ];
			BYTE *modulusPtr;

			/* We're using RSA authentication, initially we send just the user's
			   public-key info:

		        mpint	identity_public_modulus

			   First we get the modulus used to identify the client's key.
			   For no adequately explored reason this is only the modulus and
			   not the usual exponent+modulus combination, which means that
			   there's no way for a cryptlib server to identify the public
			   key from it, although at a pinch we could try with e=17, 257,
			   or F4 */
			setMessageData( &msgData, modulusBuffer,
							( SSH1_MPI_LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 2 );
			status = krnlSendMessage( sessionInfoPtr->privateKey,
									  IMESSAGE_GETATTRIBUTE_S, &msgData,
									  CRYPT_IATTRIBUTE_KEY_SSH1 );
			if( cryptStatusError( status ) )
				return( status );

			/* Skip the key size and exponent to get to the modulus.  We
			   don't have to perform safety checks here since the data is
			   coming from within cryptlib */
			modulusPtr = modulusBuffer + sizeof( LENGTH_SIZE );
			length = mgetWord( modulusPtr );			/* Exponent */
			length = bitsToBytes( length );
			modulusPtr += length;
			modulusLength = mgetWord( modulusPtr );		/* Modulus */
			modulusLength = bitsToBytes( modulusLength );
			length = SSH1_MPI_LENGTH_SIZE + modulusLength;
			modulusPtr -= SSH1_MPI_LENGTH_SIZE;

			/* Send the modulus to the server */
			padLength = getPadLength( length );
			bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
												  padLength + ID_SIZE;
			memcpy( bufPtr, modulusPtr, length );
			status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_AUTH_RSA,
									 length, CRYPT_UNUSED );
			if( cryptStatusOK( status ) )
				status = readPacketSSH1( sessionInfoPtr,
										 SSH1_MSG_SPECIAL_RSAOPT );
			if( cryptStatusError( status ) )
				return( status );

			/* The server recognises our key (no mean feat, considering that
			   e could be anything) and has sent an RSA challenge, decrypt
			   it:

				mpint	encrypted_challenge */
			bufPtr = sessionInfoPtr->receiveBuffer;
			length = mgetWord( bufPtr );
			length = bitsToBytes( length );
			if( length < modulusLength - 8 || length > modulusLength )
				retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
						"Invalid encrypted challenge length %d for modulus "
						"length %d", length, modulusLength );
			setMechanismWrapInfo( &mechanismInfo, bufPtr, length,
								  challenge, SSH1_CHALLENGE_SIZE, CRYPT_UNUSED,
								  sessionInfoPtr->privateKey, CRYPT_UNUSED );
			status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
									  IMESSAGE_DEV_IMPORT, &mechanismInfo,
									  MECHANISM_ENC_PKCS1_RAW );
			clearMechanismInfo( &mechanismInfo );
			if( cryptStatusError( status ) )
				return( status );

			/* Send the response to the challenge:

				byte[16]	MD5 of decrypted challenge

			   Since this completes the authentication, we expect to see
			   either a success or failure packet once we're done */
			generateChallengeResponse( response, handshakeInfo, challenge );
			padLength = getPadLength( SSH1_RESPONSE_SIZE );
			bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE +
												  padLength + ID_SIZE;
			memcpy( bufPtr, response, SSH1_RESPONSE_SIZE );
			status = sendPacketSsh1( sessionInfoPtr,
									 SSH1_CMSG_AUTH_RSA_RESPONSE,
									 SSH1_RESPONSE_SIZE, CRYPT_UNUSED );
			if( cryptStatusOK( status ) )
				status = readPacketSSH1( sessionInfoPtr,
										 SSH1_MSG_SPECIAL_PWOPT );
			}
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Tell the server to adjust its maximum packet size if required:

		uint32		packet_size */
	if( sessionInfoPtr->sendBufSize < EXTRA_PACKET_SIZE + MAX_PACKET_SIZE )
		{
		const int maxLength = sessionInfoPtr->sendBufSize - \
							  EXTRA_PACKET_SIZE;

		padLength = getPadLength( LENGTH_SIZE );
		bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
		mputLong( bufPtr, maxLength );
		status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_MAX_PACKET_SIZE,
								 LENGTH_SIZE, CRYPT_UNUSED );
		if( cryptStatusOK( status ) )
			status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Request a pty from the server:

		string		TERM environment variable = "vt100"
		uint32		rows = 24
		uint32		cols = 80
		uint32		pixel_width = 0
		uint32		pixel_height = 0
		byte		tty_mode_info = 0 */
	padLength = getPadLength( ( LENGTH_SIZE + 5 ) + ( UINT_SIZE * 4 ) + 1 );
	bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
	bufPtr += encodeString( bufPtr, "vt100", 0 );	/* Generic terminal type */
	mputLong( bufPtr, 24 );
	mputLong( bufPtr, 80 );			/* 24 x 80 */
	mputLong( bufPtr, 0 );
	mputLong( bufPtr, 0 );			/* No graphics capabilities */
	*bufPtr = 0;					/* No special TTY modes */
	status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_REQUEST_PTY,
							 ( LENGTH_SIZE + 5 ) + ( UINT_SIZE * 4 ) + 1,
							 CRYPT_UNUSED );
	if( cryptStatusOK( status ) )
		status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
	if( cryptStatusError( status ) )
		return( status );

	/* Tell the server to create a shell for us.  This moves the server into
	   the interactive session mode, if we're talking to a standard Unix
	   server implementing a remote shell we could read the stdout data
	   response from starting the shell but this may not be the case so we
	   leave the response for the user to process explicitly */
	return( sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_EXEC_SHELL, 0,
							CRYPT_UNUSED ) );
	}

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

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

static int beginServerHandshake( SESSION_INFO *sessionInfoPtr,

⌨️ 快捷键说明

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