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

📄 ssh.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 2 页
字号:

		OpenSSH:
			Omits hashing the exchange hash length when creating the hash
			to be signed for client auth for version 2.0 (all subversions).

		ssh.com:
			This implementation puts the version number first, so if we find 
			something without a vendor name at the start we treat it as an 
			ssh.com version.  However, Van Dyke's SSH server VShell also 
			uses the ssh.com-style identification (fronti nulla fides), so 
			when we check for the ssh.com implementation we make sure that 
			it isn't really VShell.  In addition CuteFTP advertises whatever 
			it's using as "1.x" (without and vendor name), which is going to 
			cause problems in the future if they ever move to 2.x of 
			whatever it is.

			Omits the DH-derived shared secret when hashing the keying
			material for versions identified as "2.0.0" (all 
			sub-versions) and "2.0.10" .

			Uses an SSH2_FIXED_KEY_SIZE-sized key for HMAC instead of the de
			facto 160 bits for versions identified as "2.0.", "2.1 ", "2.1.",
			and "2.2." (i.e. all sub-versions of 2.0, 2.1, and 2.2), and
			specifically version "2.3.0".  This was fixed in 2.3.1.

			Omits the signature algorithm name for versions identified as 
			"2.0" and "2.1" (all sub-versions).

			Requires a window adjust for every 32K sent even if the window is
			advertised as being (effectively) infinite in size for versions 
			identified as "2.0" and "2.1" (all sub-versions).

			Omits hashing the exchange hash length when creating the hash
			to be signed for client auth for versions 2.1 and 2.2 (all 
			subversions).

			Dumps text diagnostics (that is, raw text strings rather than
			SSH error packets) onto the connection if something unexpected 
			occurs, for uncertain versions probably in the 2.x range.

		Van Dyke:
			Omits hashing the exchange hash length when creating the hash to 
			be signed for client auth for version 3.0 (SecureCRT = SSH) and 
			1.7 (SecureFX = SFTP).

	   Further quirks and peculiarities exist, but fortunately these are rare
	   enough (mostly for SSHv1) that we don't have to go out of our way to
	   handle them */
	if( !memcmp( versionStringPtr, "OpenSSH_", 8 ) )
		{
		const char *subVersionStringPtr = versionStringPtr + 8;

		if( !memcmp( subVersionStringPtr, "2.0", 3 ) )
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_NOHASHLENGTH;
		}
	if( *versionStringPtr == '2' && \
		strstr( versionStringPtr, "VShell" ) == NULL )
		{
		/* ssh.com 2.x versions have quite a number of bugs so we check for 
		   them as a group */
		if( !memcmp( versionStringPtr, "2.0.0", 5 ) || \
			!memcmp( versionStringPtr, "2.0.10", 6 ) )
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_NOHASHSECRET;
		if( !memcmp( versionStringPtr, "2.0", 3 ) || \
			!memcmp( versionStringPtr, "2.1", 3 ) )
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_SIGFORMAT;
		if( !memcmp( versionStringPtr, "2.0", 3 ) || \
			!memcmp( versionStringPtr, "2.1", 3 ) )
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_WINDOWBUG;
		if( !memcmp( versionStringPtr, "2.1", 3 ) || \
			!memcmp( versionStringPtr, "2.2", 3 ) )
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_NOHASHLENGTH;
		if( !memcmp( versionStringPtr, "2.0", 3 ) || \
			!memcmp( versionStringPtr, "2.1", 3 ) || \
			!memcmp( versionStringPtr, "2.2", 3 ) || \
			!memcmp( versionStringPtr, "2.3.0", 5 ) )
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_HMACKEYSIZE;
		if( !memcmp( versionStringPtr, "2.", 2 ) )
			/* Not sure of the exact versions where this occurs */
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_TEXTDIAGS;
		}
	if( !memcmp( versionStringPtr, "3.0 SecureCRT", 13 ) || \
		!memcmp( versionStringPtr, "1.7 SecureFX", 12 ) )
		sessionInfoPtr->protocolFlags |= SSH_PFLAG_NOHASHLENGTH;

	return( CRYPT_OK );
	}

/* Encode a value as an SSH string */

int encodeString( BYTE *buffer, const BYTE *string, const int stringLength )
	{
	BYTE *bufPtr = buffer;
	const int length = ( stringLength > 0 ) ? stringLength : strlen( string );

	if( buffer != NULL )
		{
		mputLong( bufPtr, length );
		memcpy( bufPtr, string, length );
		}
	return( LENGTH_SIZE + length );
	}

/****************************************************************************
*																			*
*								Init/Shutdown Functions						*
*																			*
****************************************************************************/

/* Connect to an SSH server */

static int initVersion( SESSION_INFO *sessionInfoPtr,
						SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	int status;

	/* Set up handshake function pointers based on the protocol version */
	status = readVersionString( sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );
	if( sessionInfoPtr->version == 1 )
		{
		initSSH1processing( sessionInfoPtr, handshakeInfo,
							( sessionInfoPtr->flags & SESSION_ISSERVER) ? \
								TRUE : FALSE );
		return( CRYPT_OK );
		}
	initSSH2processing( sessionInfoPtr, handshakeInfo,
						( sessionInfoPtr->flags & SESSION_ISSERVER) ? \
							TRUE : FALSE );

	/* SSHv2 hashes parts of the handshake messages for integrity-protection
	   purposes, so if we're talking to an SSHv2 peer we create a context
	   for the hash */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_SHA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
							  &createInfo, OBJECT_TYPE_CONTEXT );
	if( cryptStatusOK( status ) )
		handshakeInfo->iExchangeHashcontext = createInfo.cryptHandle;
	return( status );
	}

static int completeStartup( SESSION_INFO *sessionInfoPtr )
	{
	SSH_HANDSHAKE_INFO handshakeInfo;
	int status;

	/* Initialise the handshake info and begin the handshake.  Since we don't
	   know what type of peer we're talking to and since the protocols aren't
	   compatible in anything but name, we have to peek at the peer's initial
	   communication and redirect function pointers based on that */
	status = initHandshakeInfo( &handshakeInfo );
	if( cryptStatusOK( status ) )
		status = initVersion( sessionInfoPtr, &handshakeInfo );
	if( cryptStatusOK( status ) )
		status = handshakeInfo.beginHandshake( sessionInfoPtr,
											   &handshakeInfo );
	if( cryptStatusError( status ) )
		{
		destroyHandshakeInfo( &handshakeInfo );
		sessionInfoPtr->shutdownFunction( sessionInfoPtr );
		return( status );
		}

	/* Exchange a key with the server */
	status = handshakeInfo.exchangeKeys( sessionInfoPtr, &handshakeInfo );
	if( cryptStatusError( status ) )
		{
		destroySecurityContexts( sessionInfoPtr );
		destroyHandshakeInfo( &handshakeInfo );
		sessionInfoPtr->shutdownFunction( sessionInfoPtr );
		return( status );
		}

	/* Complete the handshake */
	status = handshakeInfo.completeHandshake( sessionInfoPtr,
											  &handshakeInfo );
	destroyHandshakeInfo( &handshakeInfo );
	if( cryptStatusError( status ) )
		{
		/* At this point we could be in the secure state, so we have to
		   keep the security info around until after we've called the 
		   shutdown function, which could require sending secured data */
		sessionInfoPtr->shutdownFunction( sessionInfoPtr );
		destroySecurityContexts( sessionInfoPtr );
		return( status );
		}
	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_HANDSHAKETIMEOUT, NULL, 0 );

	return( status );
	}

/* Start an SSH server */

static int serverStartup( SESSION_INFO *sessionInfoPtr )
	{
	const char *idString = ( sessionInfoPtr->version == 1 ) ? \
						   SSH1_ID_STRING "\n" : SSH2_ID_STRING "\r\n";
	int status;

	/* Send the ID string to the client before we continue with the
	   handshake.  We don't have to wait for any input from the client since
	   we know that if we got here there's a client listening.  Note that
	   standard cryptlib practice for sessions is to wait for input from the
	   client, make sure that it looks reasonable, and only then send back a
	   reply of any kind.  If anything that doesn't look right arrives, we
	   close the connection immediately without any response.  Unfortunately
	   this isn't possible with SSH, which requires that the server send data
	   before the client does */
	status = swrite( &sessionInfoPtr->stream, idString, strlen( idString ) );
	if( cryptStatusError( status ) )
		return( status );

	/* Complete the handshake in the shared code */
	return( completeStartup( sessionInfoPtr ) );
	}

/****************************************************************************
*																			*
*						Control Information Management Functions			*
*																			*
****************************************************************************/

static int getAttributeFunction( SESSION_INFO *sessionInfoPtr,
								 void *data, const CRYPT_ATTRIBUTE_TYPE type )
	{
	RESOURCE_DATA *msgData = data;

	assert( type == CRYPT_SESSINFO_SSH_SUBSYSTEM || \
			type == CRYPT_SESSINFO_SSH_PORTFORWARD );

	switch( type )
		{
		case CRYPT_SESSINFO_SSH_SUBSYSTEM:
			if( sessionInfoPtr->sshSubsystemLength <= 0 )
				return( CRYPT_ERROR_NOTINITED );
			return( attributeCopy( msgData, sessionInfoPtr->sshSubsystem,
								   sessionInfoPtr->sshSubsystemLength ) );

		case CRYPT_SESSINFO_SSH_PORTFORWARD:
			if( sessionInfoPtr->sshPortForwardLength <= 0 )
				return( CRYPT_ERROR_NOTINITED );
			return( attributeCopy( msgData, sessionInfoPtr->sshPortForward,
								   sessionInfoPtr->sshPortForwardLength ) );
		}

	assert( NOTREACHED );
	return( CRYPT_ARGERROR_NUM1 );
	}

static int setAttributeFunction( SESSION_INFO *sessionInfoPtr,
								 const void *data,
								 const CRYPT_ATTRIBUTE_TYPE type )
	{
	const RESOURCE_DATA *msgData = data;

	assert( type == CRYPT_SESSINFO_SSH_SUBSYSTEM || \
			type == CRYPT_SESSINFO_SSH_PORTFORWARD );

	switch( type )
		{
		case CRYPT_SESSINFO_SSH_SUBSYSTEM:
			if( sessionInfoPtr->sshSubsystemLength > 0 )
				return( CRYPT_ERROR_INITED );
			memcpy( sessionInfoPtr->sshSubsystem, msgData->data, 
					msgData->length );
			sessionInfoPtr->sshSubsystemLength = msgData->length;
			break;

		case CRYPT_SESSINFO_SSH_PORTFORWARD:
			{
			URL_INFO urlInfo;
			int status;

			/* Make sure that we've been given a valid URL for forwarding */
			if( sessionInfoPtr->sshPortForwardLength > 0 )
				return( CRYPT_ERROR_INITED );
			status = sNetParseURL( &urlInfo, msgData->data, 
								   msgData->length );
			if( cryptStatusError( status ) )
				return( status );
			memcpy( sessionInfoPtr->sshPortForward, msgData->data, 
					msgData->length );
			sessionInfoPtr->sshPortForwardLength = msgData->length;
			break;
			}

		default:
			assert( NOTREACHED );
			return( CRYPT_ARGERROR_NUM1 );
		}

	return( CRYPT_OK );
	}

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

int setAccessMethodSSH( SESSION_INFO *sessionInfoPtr )
	{
	/* Set the access method pointers.  Since the protocol version is
	   negotiable, we default to SSHv2, which is the one most commonly
	   used */
	sessionInfoPtr->getAttributeFunction = getAttributeFunction;
	sessionInfoPtr->setAttributeFunction = setAttributeFunction;
	if( sessionInfoPtr->flags & SESSION_ISSERVER )
		{
		sessionInfoPtr->transactFunction = serverStartup;
		initSSH2processing( sessionInfoPtr, NULL, TRUE );
		}
	else
		{
		sessionInfoPtr->transactFunction = completeStartup;
		initSSH2processing( sessionInfoPtr, NULL, FALSE );
		}

	return( CRYPT_OK );
	}
#endif /* USE_SSH1 || USE_SSH2 */

⌨️ 快捷键说明

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