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

📄 ssh1.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
								 SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	MESSAGE_DATA msgData;
	BYTE *bufPtr = sessionInfoPtr->sendBuffer;
	static const int keyLength = bitsToBytes( 768 );
	long value;
	int length, status;

	krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_GETATTRIBUTE,
					 &handshakeInfo->serverKeySize, CRYPT_CTXINFO_KEYSIZE );

	/* Generate the 768-bit RSA server key.  It would be better to do this
	   before the listen on the socket, but we can't do it until we know that
	   the client is v1, which we only know after the initial message
	   exchange */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_RSA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, "SSH server key", 14 );
	status = krnlSendMessage( createInfo.cryptHandle,
							  IMESSAGE_SETATTRIBUTE_S, &msgData,
							  CRYPT_CTXINFO_LABEL );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( createInfo.cryptHandle,
								  IMESSAGE_SETATTRIBUTE, ( int * ) &keyLength,
								  CRYPT_CTXINFO_KEYSIZE );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( createInfo.cryptHandle,
								  IMESSAGE_CTX_GENKEY, NULL, FALSE );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		return( status );
		}
	handshakeInfo->iServerCryptContext = createInfo.cryptHandle;

	/* Send the server public key packet:

		byte[8]		cookie
		uint32		keysize_bits		- Usually 768 bits
		mpint		serverkey_exponent
		mpint		serverkey_modulus
		uint32		keysize_bits		- Usually 1024 bits
		mpint		hostkey_exponent
		mpint		hostkey_modulus
		uint32		protocol_flags		- Not used
		uint32		offered_ciphers
		uint32		offered_authent */
	setMessageData( &msgData, handshakeInfo->cookie, SSH1_COOKIE_SIZE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
	if( cryptStatusError( status ) )
		return( status );
	memcpy( bufPtr, handshakeInfo->cookie, SSH1_COOKIE_SIZE );
	bufPtr += SSH1_COOKIE_SIZE;
	setMessageData( &msgData, bufPtr, LENGTH_SIZE + \
					( ( SSH1_MPI_LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 2 ) );
	status = krnlSendMessage( handshakeInfo->iServerCryptContext,
							  IMESSAGE_GETATTRIBUTE_S, &msgData,
							  CRYPT_IATTRIBUTE_KEY_SSH1 );
	if( cryptStatusError( status ) )
		return( status );
	length = processPublickeyData( handshakeInfo, bufPtr, msgData.length,
								   TRUE, NULL );
	bufPtr += length;
	setMessageData( &msgData, bufPtr, LENGTH_SIZE + \
					( ( 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 );
	length = processPublickeyData( handshakeInfo, bufPtr, msgData.length,
								   FALSE, NULL );
	bufPtr += length;
	mputLong( bufPtr, 0 );		/* No protocol flags */
	value = getAlgorithmMask();
	mputLong( bufPtr, value );	/* Cipher algorithms */
	value = 1 << SSH1_AUTH_PASSWORD;
	if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
		value |= 1 << SSH1_AUTH_RSA;
	mputLong( bufPtr, value );	/* Authent algorithms */

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

	/* If the peer is using cryptlib, we use HMAC-SHA instead of CRC32 */
	if( sessionInfoPtr->flags & SESSION_ISCRYPTLIB )
		{
		setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
								  OBJECT_TYPE_CONTEXT );
		if( cryptStatusError( status ) )
			return( status );
		sessionInfoPtr->iAuthInContext = createInfo.cryptHandle;
		}

	return( CRYPT_OK );
	}

/* Exchange keys with the client */

static int exchangeServerKeys( SESSION_INFO *sessionInfoPtr,
							   SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	MECHANISM_WRAP_INFO mechanismInfo;
	BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
	BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
	int length, keyLength, i, status;

	/* Read the client's encrypted session key info:

		byte		cipher_type
		byte[8]		cookie
		mpint		double_enc_sessionkey
		uint32		protocol_flags */
	length = readPacketSSH1( sessionInfoPtr, SSH1_CMSG_SESSION_KEY );
	if( cryptStatusError( length ) )
		return( length );
	sessionInfoPtr->cryptAlgo = sshIDToAlgoID( bufPtr[ 0 ] );
	if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_NONE )
		retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
				"No crypto algorithm compatible with the remote system "
				"could be found" );
	if( memcmp( bufPtr + 1, handshakeInfo->cookie, SSH1_COOKIE_SIZE ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
				"Client cookie doesn't match server cookie" );
	bufPtr += 1 + SSH1_COOKIE_SIZE;
	length -= 1 + SSH1_COOKIE_SIZE;
	keyLength = mgetWord( bufPtr );
	keyLength = bitsToBytes( keyLength );
	if( length != SSH1_MPI_LENGTH_SIZE + keyLength + UINT_SIZE || \
		keyLength < handshakeInfo->serverKeySize - 8 || \
		keyLength > handshakeInfo->serverKeySize )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid encrypted session key packet length %d, key "
				"length %d", length, keyLength );

	/* Import the double-encrypted secure state information, first decrypting
	   with the host key, then with the server key */
	setMechanismWrapInfo( &mechanismInfo, bufPtr, keyLength,
						  buffer, CRYPT_MAX_PKCSIZE, CRYPT_UNUSED,
						  sessionInfoPtr->privateKey, CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
							  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
	if( cryptStatusError( status ) )
		return( status );
	setMechanismWrapInfo( &mechanismInfo, buffer, mechanismInfo.keyDataLength,
						  handshakeInfo->secretValue, SSH1_SECRET_SIZE, CRYPT_UNUSED,
						  handshakeInfo->iServerCryptContext, CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT,
							  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
	if( cryptStatusOK( status ) && \
		mechanismInfo.keyDataLength != SSH1_SECRET_SIZE )
		return( CRYPT_ERROR_BADDATA );
	clearMechanismInfo( &mechanismInfo );
	if( cryptStatusError( status ) )
		return( status );
	handshakeInfo->secretValueLength = SSH1_SECRET_SIZE;

	/* Generate the session ID from the handshake info and XOR it with the
	   recovered secure state information to get the final secure state
	   data */
	generateSessionID( handshakeInfo );
	for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
		handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];

	return( CRYPT_OK );
	}

/* Complete the handshake with the client */

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

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

	/* Send the server ack and read back the user name:

		string		username */
	status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_SUCCESS, 0,
							 CRYPT_UNUSED );
	if( cryptStatusOK( status ) )
		length = status = readPacketSSH1( sessionInfoPtr, SSH1_CMSG_USER );
	if( cryptStatusError( status ) )
		return( status );
	bufPtr = sessionInfoPtr->receiveBuffer;
	stringLength = ( int ) mgetLong( bufPtr );
	if( length != LENGTH_SIZE + stringLength || \
		stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid user name packet length %d, name length %d",
				length, stringLength );
	updateSessionInfo( &sessionInfoPtr->attributeList,
					   CRYPT_SESSINFO_USERNAME, bufPtr,
					   stringLength, CRYPT_MAX_TEXTSIZE, ATTR_FLAG_NONE );

	/* Send the server ack (which is actually a nack since the user needs
	   to submit a password) and read back the password */
	status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_FAILURE, 0,
							 CRYPT_UNUSED );
	if( cryptStatusOK( status ) )
		length = status = readPacketSSH1( sessionInfoPtr,
										  SSH1_CMSG_AUTH_PASSWORD );
	if( cryptStatusError( status ) )
		return( status );
	bufPtr = sessionInfoPtr->receiveBuffer;
	stringLength = ( int ) mgetLong( bufPtr );
	if( length != LENGTH_SIZE + stringLength || \
		stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid password packet length %d, password length %d",
				length, stringLength );
	updateSessionInfo( &sessionInfoPtr->attributeList,
					   CRYPT_SESSINFO_PASSWORD, bufPtr,
					   stringLength, CRYPT_MAX_TEXTSIZE, ATTR_FLAG_NONE );

	/* Send the server ack and process any further junk that the caller may
	   throw at us until we get an exec shell or command 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 which submit things that cause
	   problems */
	status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_SUCCESS, 0,
							 CRYPT_UNUSED );
	if( cryptStatusError( status ) )
		return( status );
	do
		{
		status = readPacketSSH1( sessionInfoPtr, SSH1_MSG_SPECIAL_ANY );
		if( cryptStatusError( status ) )
			break;
		packetType = sessionInfoPtr->receiveBuffer[ 0 ];
		switch( packetType )
			{
			case SSH1_CMSG_REQUEST_COMPRESSION:
			case SSH1_CMSG_X11_REQUEST_FORWARDING:
			case SSH1_CMSG_PORT_FORWARD_REQUEST:
			case SSH1_CMSG_AGENT_REQUEST_FORWARDING:
				/* Special operations aren't supported by cryptlib */
				status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_FAILURE,
										 0, CRYPT_UNUSED );
				break;

			case SSH1_CMSG_EXEC_SHELL:
			case SSH1_CMSG_EXEC_CMD:
				/* These commands move the server into the interactive
				   session mode and aren't explicitly acknowledged */
				break;

			case SSH1_CMSG_REQUEST_PTY:
			default:
				status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_SUCCESS,
										 0, CRYPT_UNUSED );
			}
		}
	while( !cryptStatusError( status ) && \
		   ( packetType != SSH1_CMSG_EXEC_SHELL && \
			 packetType != SSH1_CMSG_EXEC_CMD ) && iterationCount++ < 50 );
	if( iterationCount >= 50 )
		retExt( sessionInfoPtr, CRYPT_ERROR_OVERFLOW,
				"Peer sent excessive number of session open packets" );

	return( cryptStatusError( status ) ? status : CRYPT_OK );
	}

/****************************************************************************
*																			*
*								Get/Put Data Functions						*
*																			*
****************************************************************************/

/* Read data over the SSHv1 link */

static int readHeaderFunction( SESSION_INFO *sessionInfoPtr,
							   READSTATE_INFO *readInfo )
	{
	BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
				   sessionInfoPtr->receiveBufPos;
	long length;
	int status;

	/* Clear return value */
	*readInfo = READINFO_NONE;

	/* Try and read the header data from the remote system */
	assert( sessionInfoPtr->receiveBufPos == sessionInfoPtr->receiveBufEnd );
	status = readFixedHeader( sessionInfoPtr, LENGTH_SIZE );
	if( status <= 0 )
		return( status );

	/* Process the header data.  Since data errors are always fatal, we make
	   all errors fatal until we've finished handling the header */
	*readInfo = READINFO_FATAL;
	assert( status == LENGTH_SIZE );
	length = mgetLong( bufPtr );
	if( length < SSH1_HEADER_SIZE || \
		length > sessionInfoPtr->receiveBufSize - 8 )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid packet length %d", length );

	/* Determine how much data we'll be expecting.  We set the remaining
	   data length to the actual length plus the padding length since we
	   need to read this much to get to the end of the packet */
	sessionInfoPtr->pendingPacketLength = length;
	sessionInfoPtr->pendingPacketRemaining = length + \
				( 8 - ( sessionInfoPtr->pendingPacketLength & 7 ) );

	/* Indicate that we got the header.  Since the header is out-of-band data
	   in SSHv1, we mark it as a no-op read */
	*readInfo = READINFO_NOOP;
	return( OK_SPECIAL );
	}

static int processBodyFunction( SESSION_INFO *sessionInfoPtr,
								READSTAT

⌨️ 快捷键说明

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