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

📄 ssh.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 2 页
字号:
			sessionInfoPtr->protocolFlags |= SSH_PFLAG_TEXTDIAGS;
		}
	if( !memcmp( versionStringPtr, "3.0 SecureCRT", 13 ) || \
		!memcmp( versionStringPtr, "1.7 SecureFX", 12 ) )
		sessionInfoPtr->protocolFlags |= SSH_PFLAG_NOHASHLENGTH;
	if( !memcmp( versionStringPtr, "1.0", 3 ) )
		sessionInfoPtr->protocolFlags |= SSH_PFLAG_CUTEFTP;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								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 );
#ifdef USE_SSH1
	if( sessionInfoPtr->version == 1 )
		{
		initSSH1processing( sessionInfoPtr, handshakeInfo,
							( sessionInfoPtr->flags & SESSION_ISSERVER) ? \
								TRUE : FALSE );
		sessionInfoPtr->sendBufStartOfs = \
			sessionInfoPtr->receiveBufStartOfs = \
				sessionInfoPtr->protocolInfo->sendBufStartOfs;
		return( CRYPT_OK );
		}
#endif /* USE_SSH1 */
	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 ) )
		{
		/* If we run into an error at this point we need to disable error-
		   reporting during the shutdown phase since we've already got
		   error information present from the already-encountered error */
		destroyHandshakeInfo( &handshakeInfo );
		sessionInfoPtr->flags |= SESSION_NOREPORTERROR;
		sessionInfoPtr->shutdownFunction( sessionInfoPtr );
		return( status );
		}

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

	/* Complete the handshake */
	status = handshakeInfo.completeHandshake( sessionInfoPtr,
											  &handshakeInfo );
	destroyHandshakeInfo( &handshakeInfo );
	if( cryptStatusError( status ) )
		{
		/* If we need confirmation from the user before continuing, let
		   them know */
		if( status == CRYPT_ENVELOPE_RESOURCE )
			return( 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->flags |= SESSION_NOREPORTERROR;
		sessionInfoPtr->shutdownFunction( sessionInfoPtr );
		destroySecurityContextsSSH( sessionInfoPtr );
		return( status );
		}

	return( CRYPT_OK );
	}

/* 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;

	/* If we're completing a handshake that was interrupted while we got
	   confirmation of the client auth, skip the initial handshake stages
	   and go straight to the handshake completion stage */
	if( sessionInfoPtr->flags & SESSION_PARTIALOPEN )
		{
		SSH_HANDSHAKE_INFO handshakeInfo;

		initHandshakeInfo( &handshakeInfo );
		initSSH2processing( sessionInfoPtr, &handshakeInfo, TRUE );
		status = handshakeInfo.completeHandshake( sessionInfoPtr,
												  &handshakeInfo );
		destroyHandshakeInfo( &handshakeInfo );
		return( 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 )
	{
	int status;

	assert( type == CRYPT_SESSINFO_SSH_CHANNEL ||\
			type == CRYPT_SESSINFO_SSH_CHANNEL_TYPE || \
			type == CRYPT_SESSINFO_SSH_CHANNEL_ARG1 || \
			type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
			type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE );

	if( type == CRYPT_SESSINFO_SSH_CHANNEL || \
		type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE )
		status = getChannelAttribute( sessionInfoPtr, type,
									  NULL, data );
	else
		{
		RESOURCE_DATA *msgData = data;

		status = getChannelAttribute( sessionInfoPtr, type,
									  msgData->data, &msgData->length );
		}
	return( ( status == CRYPT_ERROR ) ? CRYPT_ARGERROR_NUM1 : status );
	}

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

	assert( type == CRYPT_SESSINFO_SSH_CHANNEL ||\
			type == CRYPT_SESSINFO_SSH_CHANNEL_TYPE || \
			type == CRYPT_SESSINFO_SSH_CHANNEL_ARG1 || \
			type == CRYPT_SESSINFO_SSH_CHANNEL_ARG2 || \
			type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE );

	/* If we're selecting a channel and there's unwritten data from a
	   previous write still in the buffer, we can't change the write
	   channel */
	if( type == CRYPT_SESSINFO_SSH_CHANNEL && sessionInfoPtr->partialWrite )
		return( CRYPT_ERROR_INCOMPLETE );

	/* If we're creating a new channel by setting the value to CRYPT_UNUSED,
	   create the new channel */
	if( type == CRYPT_SESSINFO_SSH_CHANNEL && \
		*( int * ) data == CRYPT_UNUSED )
		{
		/* If the session hasn't been activated yet, we can only create a
		   single channel during session activation, any subsequent ones
		   have to be handled later */
		if( !( sessionInfoPtr->flags & SESSION_ISOPEN ) && \
			getCurrentChannelNo( sessionInfoPtr, \
								 CHANNEL_READ ) != UNUSED_CHANNEL_NO )
			return( CRYPT_ERROR_INITED );

		return( createChannel( sessionInfoPtr ) );
		}

	/* If we 're setting the channel-active attribute, this implicitly
	   activates or deactivates the channel rather than setting any 
	   attribute value */
	if( type == CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE )
		{
		if( *( int * ) data )
			return( sendChannelOpen( sessionInfoPtr ) );
		return( closeChannel( sessionInfoPtr, FALSE ) );
		}

	if( type == CRYPT_SESSINFO_SSH_CHANNEL )
		status = setChannelAttribute( sessionInfoPtr, type,
									  NULL, *( int * ) data );
	else
		{
		const RESOURCE_DATA *msgData = data;

		status = setChannelAttribute( sessionInfoPtr, type,
									  msgData->data, msgData->length );
		}
	return( ( status == CRYPT_ERROR ) ? CRYPT_ARGERROR_NUM1 : status );
	}

static int checkAttributeFunction( SESSION_INFO *sessionInfoPtr,
								   const CRYPT_HANDLE cryptHandle,
								   const CRYPT_ATTRIBUTE_TYPE type )
	{
	HASHFUNCTION hashFunction;
	STREAM stream;
	BYTE buffer[ 128 + ( CRYPT_MAX_PKCSIZE * 4 ) ];
	BYTE fingerPrint[ CRYPT_MAX_HASHSIZE ];
	int length, hashSize, status;

	if( type != CRYPT_SESSINFO_PRIVATEKEY )
		return( CRYPT_OK );

	/* Only the server key has a fingerprint */
	if( !( sessionInfoPtr->flags & SESSION_ISSERVER ) )
		return( CRYPT_OK );

	getHashParameters( CRYPT_ALGO_MD5, &hashFunction, &hashSize );

	/* The fingerprint is computed from the "key blob", which is different
	   from the server key.  The server key is the full key, while the "key
	   blob" is only the raw key components (e, n for RSA, p, q, g, y for
	   DSA), so we have to skip the key header before we hash the key data.
	   Note that, as with the old PGP 2.x key hash mechanism, this allows
	   key spoofing (although it isn't quite as bad as the PGP 2.x key
	   fingerprint mechanism) since it doesn't hash an indication of the key
	   type or format */
	sMemOpen( &stream, buffer, 128 + ( CRYPT_MAX_PKCSIZE * 4 ) );
	status = exportAttributeToStream( &stream, cryptHandle,
									  CRYPT_IATTRIBUTE_KEY_SSH2,
									  CRYPT_USE_DEFAULT );
	if( cryptStatusError( status ) )
		return( status );
	length = stell( &stream );
	sseek( &stream, 0 );
	readUint32( &stream );					/* Length */
	status = readUniversal32( &stream );	/* Algorithm ID */
	if( cryptStatusOK( status ) )
		hashFunction( NULL, fingerPrint, sMemBufPtr( &stream ),
					  length - stell( &stream ), HASH_ALL );
	sMemClose( &stream );
	if( cryptStatusError( status ) )
		return( status );

	/* Add the fingerprint */
	return( addSessionAttribute( &sessionInfoPtr->attributeList,
								 CRYPT_SESSINFO_SERVER_FINGERPRINT,
								 fingerPrint, hashSize ) );
	}

/****************************************************************************
*																			*
*							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;
	sessionInfoPtr->checkAttributeFunction = checkAttributeFunction;
	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 + -