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

📄 ssh2_cli.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
				  clientKeyexLength );
	status = hashAsString( handshakeInfo->iExchangeHashcontext,
						   sessionInfoPtr->receiveBuffer, serverKeyexLength );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're using a non-builtin DH key value, request the keyex key from 
	   the server */
	if( handshakeInfo->requestedServerKeySize > 0 )
		{
		BYTE *dataStartPtr;
		const int extraLength = LENGTH_SIZE + ( LENGTH_SIZE + 6 );

		/*	...
			byte	type = SSH2_MSG_KEXDH_GEX_REQUEST
			uint32	keySize = 1024
	
		   There is an alternative format that allows the client to specify 
		   a range of key sizes:
		   
			byte	type = SSH2_MSG_KEXDH_GEX_REQUEST_NEW
			uint32	minSize = 1024 - 16
			uint32	preferredSize = 1024
			uint32	maxSize = 1024 + 16

		   but few implementations currently seem to support this, with some 
		   servers just dropping the connection without any error response if 
		   they encounter the newer packet type */
		bufPtr = dataStartPtr = sessionInfoPtr->sendBuffer + length + \
								SSH2_HEADER_SIZE;
#if 1
		*bufPtr++ = SSH2_MSG_KEXDH_GEX_REQUEST;
		mputLong( bufPtr, bytesToBits( SSH2_DEFAULT_KEYSIZE ) );
		status = length2 = wrapPacket( sessionInfoPtr,
								sessionInfoPtr->sendBuffer + length,
								ID_SIZE + UINT_SIZE );
#else
		*bufPtr++ = SSH2_MSG_KEXDH_GEX_REQUEST_NEW;
		mputLong( bufPtr, 1024 );
		mputLong( bufPtr, bytesToBits( SSH2_DEFAULT_KEYSIZE ) );
		mputLong( bufPtr, bytesToBits( CRYPT_MAX_PKCSIZE ) );
		status = length2 = wrapPacket( sessionInfoPtr,
								sessionInfoPtr->sendBuffer + length,
								ID_SIZE + ( 3 * UINT_SIZE ) );
#endif /* 1 */
		if( !cryptStatusError( status ) )
			status = sendPacketSSH2( sessionInfoPtr, length + length2, 
									 TRUE );
		if( cryptStatusError( status ) )
			return( status );

		/* Remember the encoded key size info for later when we generate
		   the exchange hash */
#if 1
		memcpy( handshakeInfo->encodedReqKeySizes, dataStartPtr + 1,
				UINT_SIZE );
		handshakeInfo->encodedReqKeySizesLength = UINT_SIZE;
#else
		memcpy( handshakeInfo->encodedReqKeySizes, dataStartPtr + 1,
				3 * UINT_SIZE );
		handshakeInfo->encodedReqKeySizesLength = 3 * UINT_SIZE;
#endif /* 1 */

		/* Process the ephemeral DH key:

			byte	type = SSH2_MSG_KEXDH_GEX_GROUP
			mpint	p
			mpint	g */
		length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_KEXDH_GEX_GROUP );
		if( cryptStatusError( length ) )
			return( length );
		bufPtr = dataStartPtr = sessionInfoPtr->receiveBuffer + ID_SIZE;
		length -= ID_SIZE;
		if( length < ( LENGTH_SIZE + bitsToBytes( MIN_PKCSIZE_BITS ) ) + \
					 ( LENGTH_SIZE + 1 ) || \
			length > ( ( LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 2 ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid DH ephemeral key packet length %d",
					length );

		/* Since this phase of the key negotiation exchanges raw key 
		   components rather than the standard SSH public-key format, we 
		   have to rewrite the raw key components into a standard SSH key so 
		   that we can import it:

			string	"ssh-dh"
			mpint	p
			mpint	g */
		memmove( bufPtr + extraLength, bufPtr, length );
		mputLong( bufPtr, ( extraLength - LENGTH_SIZE ) + length );
		encodeString( bufPtr, "ssh-dh", 0 );

		/* Destroy the existing static DH key, load the new one, and
		   re-perform phase 1 of the DH key agreement process */
		krnlSendNotifier( handshakeInfo->iServerCryptContext, 
						  IMESSAGE_DECREFCOUNT );
		status = initDHcontext( &handshakeInfo->iServerCryptContext,
								&handshakeInfo->serverKeySize, 
								dataStartPtr, extraLength + length,
								CRYPT_UNUSED );
		if( cryptStatusOK( status ) )
			{
			memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
			status = krnlSendMessage( handshakeInfo->iServerCryptContext,
									  IMESSAGE_CTX_ENCRYPT, &keyAgreeParams,
									  sizeof( KEYAGREE_PARAMS ) );
			}
		if( cryptStatusError( status ) )
			return( status );

		/* We've already sent the client hello as part of the keyex 
		   negotiation so there's no need to bundle it with the client
		   keyex, reset the start position in the send buffer */
		length = 0;
		}

	/*	...
		byte	type = SSH2_MSG_KEXDH_INIT / SSH2_MSG_KEXDH_GEX_INIT
		mpint	y */
	bufPtr = sessionInfoPtr->sendBuffer + length + SSH2_HEADER_SIZE;
	*bufPtr++ = ( handshakeInfo->requestedServerKeySize > 0 ) ? \
				SSH2_MSG_KEXDH_GEX_INIT : SSH2_MSG_KEXDH_INIT;
	mpiLength = encodeMPI( bufPtr, keyAgreeParams.publicValue,
						   keyAgreeParams.publicValueLen );
	status = length2 = wrapPacket( sessionInfoPtr,
							sessionInfoPtr->sendBuffer + length,
							ID_SIZE + mpiLength );
	if( cryptStatusError( status ) )
		return( status );

	/* Save the MPI-encoded client DH keyex value for later, when we need to
	   hash it */
	memcpy( handshakeInfo->clientKeyexValue,
			sessionInfoPtr->sendBuffer + length + SSH2_HEADER_SIZE + ID_SIZE,
			mpiLength );
	handshakeInfo->clientKeyexValueLength = mpiLength;

	/* Send the whole mess to the server.  Since SSH, unlike SSL, requires
	   that each packet in a multi-packet group be wrapped as a separate
	   packet, we have to first assemble the packets via wrapPacket() and
	   then send them in a group via sendPacket() with the send-only
	   flag set */
	status = sendPacketSSH2( sessionInfoPtr, length + length2, TRUE );
	if( cryptStatusError( status ) )
		return( status );

	/* Set up PKC info while we wait for the server to process our 
	   response */
	setMessageCreateObjectInfo( &createInfo, handshakeInfo->pubkeyAlgo );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
							  OBJECT_TYPE_CONTEXT );
	if( cryptStatusOK( status ) )
		sessionInfoPtr->iKeyexAuthContext = createInfo.cryptHandle;
	return( status );
	}

/* Exchange keys with the server */

static int exchangeClientKeys( SESSION_INFO *sessionInfoPtr,
							   SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	CRYPT_ALGO_TYPE pubkeyAlgo;
	RESOURCE_DATA msgData;
	BYTE *bufPtr, *dataStartPtr;
	int length, dataLength, stringLength, status;

	/* Process the DH phase 2 keyex packet:

		byte		type = SSH2_MSG_KEXDH_REPLY / SSH2_MSG_KEXDH_GEX_REPLY
		string		server key/certificate
			string	"ssh-rsa"	"ssh-dss"
			mpint	e			p
			mpint	n			q
			mpint				g
			mpint				y
		mpint		y'
		string		signature of handshake data
			string	"ssh-rsa"	"ssh-dss"
			string	signature	signature

	   First, we read and hash the server key/certificate.  Since this is
	   already encoded as an SSH string, we can hash it directly */
	length = readPacketSSH2( sessionInfoPtr, 
					( handshakeInfo->requestedServerKeySize > 0 ) ? \
					SSH2_MSG_KEXDH_GEX_REPLY : SSH2_MSG_KEXDH_REPLY );
	if( cryptStatusError( length ) )
		return( length );
	bufPtr = dataStartPtr = sessionInfoPtr->receiveBuffer + ID_SIZE;
	dataLength = ( int ) mgetLong( bufPtr );	/* Server key size */
	length -= ID_SIZE + LENGTH_SIZE + dataLength;
	if( length < ( LENGTH_SIZE + bitsToBytes( MIN_PKCSIZE_BITS ) ) + \
				 LENGTH_SIZE + ( LENGTH_SIZE + 7 ) + ( LENGTH_SIZE + 40 ) || \
		dataLength < ( LENGTH_SIZE + 7 ) + ( LENGTH_SIZE + 1 ) + \
					 ( LENGTH_SIZE + bitsToBytes( MIN_PKCSIZE_BITS ) ) || \
		dataLength > ( LENGTH_SIZE + 7 ) + \
					 ( ( LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 4 ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid DH phase 2 packet length %d, data length %d",
				length, dataLength );
	stringLength = getAlgoID( handshakeInfo->algoStringPubkeyTbl,
							  &pubkeyAlgo, CRYPT_ALGO_NONE, bufPtr,
							  dataLength, sessionInfoPtr );
	if( cryptStatusError( stringLength ) )
		return( stringLength );
	if( pubkeyAlgo != handshakeInfo->pubkeyAlgo )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid DH phase 2 public key algorithm %d, expected %d",
				pubkeyAlgo, handshakeInfo->pubkeyAlgo );
	setMessageData( &msgData, dataStartPtr, LENGTH_SIZE + dataLength );
	status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext,
							  IMESSAGE_SETATTRIBUTE_S, &msgData,
							  CRYPT_IATTRIBUTE_KEY_SSH2 );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, cryptArgError( status ) ? \
				CRYPT_ERROR_BADDATA : status, 
				"Invalid server key/certificate" );
	status = krnlSendMessage( handshakeInfo->iExchangeHashcontext,
							  IMESSAGE_CTX_HASH, dataStartPtr,
							  LENGTH_SIZE + dataLength );
	if( cryptStatusOK( status ) )
		status = processKeyFingerprint( sessionInfoPtr,
										dataStartPtr + LENGTH_SIZE,
										dataLength );
	if( cryptStatusError( status ) )
		return( status );
	bufPtr += dataLength;

	/* Then we read the server DH keyex value and complete the DH key
	   agreement */
	dataStartPtr = bufPtr;
	dataLength = ( int ) mgetLong( bufPtr );	/* DH keyex value size */
	length -= LENGTH_SIZE + dataLength;
	if( length < LENGTH_SIZE + ( LENGTH_SIZE + 7 ) + ( LENGTH_SIZE + 40 ) || \
		dataLength < bitsToBytes( MIN_PKCSIZE_BITS ) || \
		dataLength > 4 + CRYPT_MAX_PKCSIZE )	/* +4 for zero-pad */
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid DH phase 2 keyex value length %d, packet length "
				"%d", dataLength, length );
	bufPtr += dataLength;
	memcpy( handshakeInfo->serverKeyexValue, dataStartPtr,
			LENGTH_SIZE + dataLength );
	handshakeInfo->serverKeyexValueLength = LENGTH_SIZE + dataLength;
	status = completeKeyex( sessionInfoPtr, handshakeInfo, FALSE );
	if( cryptStatusError( status ) )
		return( status );

	/* Some implementations incorrectly format the signature packet, 
	   omitting the algorithm name and signature blob length for DSA sigs 
	   (that is, they just encode two 20-byte values instead of a properly-
	   formatted signature):

			  Right							  Wrong
		string		signature data		string		signature data
			string	"ssh-dss"						signature
			string	signature

	   If we're talking to one of these versions, we check to see whether 
	   the packet is correctly formatted and if it isn't rewrite it into the 
	   correct format so that we can verify the signature.  This check 
	   requires that the signature format be one of the SSHv2 standard 
	   types, but since we can't (by definition) handle proprietary formats 
	   this isn't a problem */
	if( ( sessionInfoPtr->protocolFlags & SSH_PFLAG_SIGFORMAT ) && \
		( pubkeyAlgo == CRYPT_ALGO_DSA ) && \
		( memcmp( bufPtr + LENGTH_SIZE + LENGTH_SIZE, "ssh-", 4 ) && \
		  memcmp( bufPtr + LENGTH_SIZE + LENGTH_SIZE, "x509v3-", 7 ) && \
		  memcmp( bufPtr + LENGTH_SIZE + LENGTH_SIZE, "spki-", 5 ) && \
		  memcmp( bufPtr + LENGTH_SIZE + LENGTH_SIZE, "pgp-", 4 ) ) )
		{
		BYTE *sigInfoPtr = bufPtr;
		const int extraLength = putAlgoID( NULL, CRYPT_ALGO_DSA ) + \
								LENGTH_SIZE;

		/* Make sure that the rewritten packet still fits into the buffer */
		if( ( bufPtr - sessionInfoPtr->receiveBuffer ) + length + extraLength >= \
			sessionInfoPtr->receiveBufSize )
			retExt( sessionInfoPtr, CRYPT_ERROR_OVERFLOW,
					"Invalid DH phase 2 keyex value length %d, need extra %d "
					"bytes", length, extraLength );

		/* Rewrite the packet to fix up the overall length at the start and 
		   insert the algorithm name and signature length */
		memmove( sigInfoPtr + extraLength, sigInfoPtr, length );
		mputLong( sigInfoPtr, extraLength + length );
		putAlgoID( &sigInfoPtr, pubkeyAlgo );
		mputLong( sigInfoPtr, length );
		}

	/* Finally, verify the server's signature on the exchange hash */
	status = iCryptCheckSignatureEx( bufPtr, length, CRYPT_IFORMAT_SSH,
							sessionInfoPtr->iKeyexAuthContext,
							handshakeInfo->iExchangeHashcontext, NULL );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, status, "Bad handshake data signature" );

	/* We don't need the hash context any more, get rid of it */
	krnlSendNotifier( handshakeInfo->iExchangeHashcontext,
					  IMESSAGE_DECREFCOUNT );
	handshakeInfo->iExchangeHashcontext = CRYPT_ERROR;

	return( CRYPT_OK );
	}

/* Complete the handshake with the server */

static int completeClientHandshake( SESSION_INFO *sessionInfoPtr,
									SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	BYTE *bufPtr;
	int length, totalLength, status;

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

	/* Wait for the server's change cipherspec message */
	status = readPacketSSH2( sessionInfoPtr, SSH2_MSG_NEWKEYS );
	if( cryptStatusError( status ) )
		return( status );

	/* Build our change cipherspec message and request authentication with
	   the server:

		byte	type = SSH2_MSG_NEWKEYS
		... */
	bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;

⌨️ 快捷键说明

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