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

📄 ssh2_svr.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
							CRYPT_SESSINFO_USERNAME, stringBuffer, 
							stringLength, CRYPT_MAX_TEXTSIZE,
							ATTR_FLAG_NONE );

	/* Get the service name and authentication method name, either
	   "password" or "none" */
	status = readString32( &stream, stringBuffer, &stringLength,
						   CRYPT_MAX_TEXTSIZE );
	if( cryptStatusError( status ) || \
		stringLength != 14 || memcmp( stringBuffer, "ssh-connection", 14 ) )
		{
		sMemDisconnect( &stream );
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid user auth service name" );
		}
	status = readString32( &stream, stringBuffer, &stringLength,
						   CRYPT_MAX_TEXTSIZE );
	if( cryptStatusError( status ) || \
		stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
		{
		sMemDisconnect( &stream );
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid user auth method name" );
		}
	if( !( ( stringLength == 4 && \
			 !memcmp( stringBuffer, "none", 4 ) ) || \
		   ( stringLength == 8 && \
			 !memcmp( stringBuffer, "password", 8 ) ) ) )
		{
		sMemDisconnect( &stream );
		stringBuffer[ stringLength ] = '\0';
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Unknown user auth method name '%s'", 
				sanitiseString( stringBuffer ) );
		}
	sgetc( &stream );	/* Skip boolean flag */

	/* If the client wants a list of supported authentication mechanisms
	   (indicated by sending the method name "none" of length 4), 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 )
		{
		sMemDisconnect( &stream );
		openPacketStreamSSH( &stream, sessionInfoPtr, CRYPT_USE_DEFAULT,
							 SSH2_MSG_USERAUTH_FAILURE );
		writeAlgoList( &stream, algoStringUserauthentList );
		sputc( &stream, 0 );
		status = sendPacketSSH2( sessionInfoPtr, &stream, FALSE );
		sMemDisconnect( &stream );

		return( CRYPT_OK );
		}

	/* The client has asked for password auth, save the authentication info 
	   for the caller to check */
	status = readString32( &stream, stringBuffer, &stringLength,
						   CRYPT_MAX_TEXTSIZE );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) || \
		stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid user auth payload" );
	updateSessionAttribute( &sessionInfoPtr->attributeList,
							CRYPT_SESSINFO_PASSWORD, stringBuffer, 
							stringLength, CRYPT_MAX_TEXTSIZE,
							ATTR_FLAG_NONE );

	return( OK_SPECIAL );
	}

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

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

static int beginServerHandshake( SESSION_INFO *sessionInfoPtr,
								 SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	static const FAR_BSS ALGO_STRING_INFO algoStringPubkeyRSATbl[] = {
		{ "ssh-rsa", CRYPT_ALGO_RSA },
		{ NULL, CRYPT_ALGO_NONE }
		};
	static const FAR_BSS ALGO_STRING_INFO algoStringPubkeyDSATbl[] = {
		{ "ssh-dss", CRYPT_ALGO_DSA },
		{ NULL, CRYPT_ALGO_NONE }
		};
	STREAM stream;
	void *serverHelloPtr;
	int length, serverHelloLength, clientHelloLength, status;

	/* Get the public-key algorithm that we'll be advertising to the client 
	   and set the algorithm table used for processing the client hello to 
	   only match the one that we're offering */
	status = krnlSendMessage( sessionInfoPtr->privateKey,
							  IMESSAGE_GETATTRIBUTE,
							  &handshakeInfo->pubkeyAlgo,
							  CRYPT_CTXINFO_ALGO );
	if( cryptStatusError( status ) )
		return( status );
	switch( handshakeInfo->pubkeyAlgo )
		{
		case CRYPT_ALGO_RSA:
			handshakeInfo->algoStringPubkeyTbl = algoStringPubkeyRSATbl;
			break;

		case CRYPT_ALGO_DSA:
			handshakeInfo->algoStringPubkeyTbl = algoStringPubkeyDSATbl;
			break;

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

	/* SSHv2 hashes parts of the handshake messages for integrity-protection
	   purposes, so before we start we hash the ID strings (first the client 
	   string that we read previously, then our server string) encoded as SSH 
	   string values */
	hashAsString( handshakeInfo->iExchangeHashcontext,
				  sessionInfoPtr->receiveBuffer,
				  strlen( sessionInfoPtr->receiveBuffer ) );
	hashAsString( handshakeInfo->iExchangeHashcontext, SSH2_ID_STRING,
				  strlen( SSH2_ID_STRING ) );

	/* Send the server hello packet:

		byte		type = SSH2_MSG_KEXINIT
		byte[16]	cookie
		string		keyex algorithms
		string		pubkey algorithms
		string		client_crypto algorithms
		string		server_crypto algorithms
		string		client_mac algorithms
		string		server_mac algorithms
		string		client_compression algorithms = "none"
		string		server_compression algorithms = "none"
		string		client_language = ""
		string		server_language = ""
		boolean		first_keyex_packet_follows = FALSE
		uint32		reserved = 0

	   The SSH spec leaves the order in which things happen ambiguous, in 
	   order to save a while round trip it has provisions for both sides 
	   shouting at each other and then a complex interlock process where
	   bits of the initial exchange can be discarded and retried if necessary.
	   This is ugly and error-prone.  The client code solves this by waiting
	   for the server hello, choosing known-good algorithms, and then sending
	   the client hello immediately followed by the client key exchange data.
	   Since it waits for the server to speak first, it can choose parameters
	   that are accepted the first time.

	   Unfortunately, this doesn't work if we're the server, since we'd end
	   up waiting for the client to speak first while it waits for us to
	   speak first, so we have to send the server hello in order to prevent
	   deadlock.  This works fine with most clients, which take the same 
	   approach and wait for the server to speak first.  The message flow is 
	   then:

		server hello;
		client hello;
		client keyex;
		server keyex;
	   
	   There are one or two exceptions to this, the worst of which is the 
	   F-Secure client, which has the client speak first choosing as its 
	   preference the incompletely specified "x509v3-sign-dss" format (see 
	   the comment in exchangeServerKeys() below) that we can't use since no-
	   one's quite sure what the format is (this was fixed in mid-2004 when
	   the x509v3-* schemes were removed from the spec, since no-one could
	   figure out what they were.  F-Secure still specifies them, but after 
	   the standard ssh-* schemes).  In this case the message flow is:

		server hello;
		client hello;
		client keyex1;
		client keyex2;
		server keyex;

	   This is handled by having the code that reads the client hello return 
	   OK_SPECIAL to indicate that the next packet should be skipped.  An 
	   alternative (and simpler) strategy would be to always throw away the 
	   F-Secure client's first keyex, since it's using an algorithm choice 
	   that's impossible to use */
	openPacketStreamSSH( &stream, sessionInfoPtr, CRYPT_USE_DEFAULT, 
						 SSH2_MSG_KEXINIT );
	streamBookmarkSetFullPacket( &stream, serverHelloPtr, 
								 serverHelloLength );
	exportAttributeToStream( &stream, SYSTEM_OBJECT_HANDLE,
							 CRYPT_IATTRIBUTE_RANDOM_NONCE, 
							 SSH2_COOKIE_SIZE );
	writeAlgoList( &stream, algoKeyexList );
	writeAlgoString( &stream, handshakeInfo->pubkeyAlgo );
	writeAlgoList( &stream, algoEncrList );
	writeAlgoList( &stream, algoEncrList );
	writeAlgoList( &stream, algoMACList );
	writeAlgoList( &stream, algoMACList );
	writeAlgoString( &stream, CRYPT_PSEUDOALGO_COPR );
	writeAlgoString( &stream, CRYPT_PSEUDOALGO_COPR );
	writeUint32( &stream, 0 );			/* No language tag */
	writeUint32( &stream, 0 );
	sputc( &stream, 0 );				/* Don't try and guess the keyex */
	writeUint32( &stream, 0 );			/* Reserved */
	streamBookmarkComplete( &stream, serverHelloLength );
	status = sendPacketSSH2( sessionInfoPtr, &stream, FALSE );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

	/* While we wait for the client to digest our hello and send back its
	   response, create the context with the DH key */
	status = initDHcontextSSH( &handshakeInfo->iServerCryptContext,
							   &handshakeInfo->serverKeySize, NULL, 0,
							   CRYPT_USE_DEFAULT );
	if( cryptStatusError( status ) )
		return( status );

	/* Process the client hello packet and hash the client and server 
	   hello */
	status = processHelloSSH( sessionInfoPtr, handshakeInfo, 
							  &clientHelloLength, TRUE );
	if( cryptStatusOK( status ) )
		status = hashAsString( handshakeInfo->iExchangeHashcontext,
							   sessionInfoPtr->receiveBuffer, 
							   clientHelloLength );
	else
		if( status == OK_SPECIAL )
			{
			/* There's an incorrectly-guessed keyex following the client 
			   hello, skip it */
			hashAsString( handshakeInfo->iExchangeHashcontext,
						  sessionInfoPtr->receiveBuffer, clientHelloLength );
			status = readPacketSSH2( sessionInfoPtr, 
						( handshakeInfo->requestedServerKeySize > 0 ) ? \
							SSH2_MSG_KEXDH_GEX_INIT : SSH2_MSG_KEXDH_INIT, 
						ID_SIZE + sizeofString32( "", bitsToBytes( MIN_PKCSIZE_BITS ) ) );
			}
	if( !cryptStatusError( status ) )	/* rPSSH2() returns a byte count */
		status = hashAsString( handshakeInfo->iExchangeHashcontext,
							   serverHelloPtr, serverHelloLength );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're using a nonstandard DH key value, negotiate a new key with 
	   the client */
	if( handshakeInfo->requestedServerKeySize > 0 )
		{
		status = processDHE( sessionInfoPtr, handshakeInfo );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Process the client keyex:

		byte	type = SSH2_MSG_KEXDH_INIT / SSH2_MSG_KEXDH_GEX_INIT
		mpint	y */
	length = readPacketSSH2( sessionInfoPtr, 
					( handshakeInfo->requestedServerKeySize > 0 ) ? \
					  SSH2_MSG_KEXDH_GEX_INIT : SSH2_MSG_KEXDH_INIT, 
					ID_SIZE + sizeofString32( "", bitsToBytes( MIN_PKCSIZE_BITS ) ) );
	if( cryptStatusError( length ) )
		return( length );
	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
	sgetc( &stream );		/* Skip packet type */
	status = readRawObject32( &stream, handshakeInfo->clientKeyexValue,
							  &handshakeInfo->clientKeyexValueLength,
							  sizeof( handshakeInfo->clientKeyexValue ) );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) || \
		!isValidDHsize( handshakeInfo->clientKeyexValueLength, 
						handshakeInfo->serverKeySize, LENGTH_SIZE ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid DH phase 1 keyex value" );
	return( CRYPT_OK );
	}

/* Exchange keys with the client */

static int exchangeServerKeys( SESSION_INFO *sessionInfoPtr,
							   SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	KEYAGREE_PARAMS keyAgreeParams;

⌨️ 快捷键说明

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