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

📄 ssh.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						cryptlib SSHv1/v2 Session Management				*
*						Copyright Peter Gutmann 1998-2002					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "stream.h"
  #include "session.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../keymgmt/stream.h"
  #include "../session/session.h"
#else
  #include "crypt.h"
  #include "keymgmt/stream.h"
  #include "session/session.h"
#endif /* Compiler-specific includes */

/* Default SSH port */

#define SSH_PORT				22

/* Various SSH constants */

#define ID_SIZE					1	/* ID byte */
#define LENGTH_SIZE				4	/* Size of packet length field */
#define UINT_SIZE				4	/* Size of integer value */
#define PADLENGTH_SIZE			1	/* Size of padding length field */
#define BOOLEAN_SIZE			1	/* Size of boolean value */
#define CRC_SIZE				4	/* Size of CRC value */
#define MPI_LENGTH_SIZE			2	/* Size of MPI length field */
#define SSH_COOKIE_SIZE			8	/* Size of anti-spoofing cookie */
#define SSH2_COOKIE_SIZE		16	/* Size of SSHv2 cookie */
#define SSH_SESSIONID_SIZE		16	/* Size of session ID */
#define SSH_HEADER_SIZE			5	/* Size of the SSHv1 packet header */
#define SSH2_HEADER_SIZE		5	/* Size of the SSHv2 packet header */
#define SSH2_PAYLOAD_HEADER_SIZE 9	/* Size of SSHv2 inner payload header */
#define SSH_SECRET_SIZE			32	/* Size of SSH shared secret */
#define SSH2_FIXED_KEY_SIZE		16	/* Size of SSHv2 fixed-size keys */
#define SSH_CHALLENGE_SIZE		32	/* Size of RSA auth.challenge */
#define SSH_RESPONSE_SIZE		16	/* Size of RSA auth.response */

/* Default and maximum SSH send/receive buffer sizes */

#define BUFFER_SIZE				( 16384 + 64 )
#define MAX_BUFFER_SIZE			262144L

/* Various data sizes used for read-ahead and buffering.  The minimum SSH 
   packet size is used to determine how much data we can read when reading 
   a packet header, the remainder size is how much extra data we've got
   available from the header once we've extracted the length, and the 
   maximum SSH header size is used to determine how much space we need to 
   reserve at the start of the buffer when encoding SSHv1's variable-length 
   data packets (SSHv2 has a fixed header size so this isn't a problem any
   more) */

#define MIN_PACKET_SIZE			16
#define PACKET_REMAINDER_SIZE	( MIN_PACKET_SIZE - LENGTH_SIZE )
#define MAX_HEADER_SIZE			( LENGTH_SIZE + 8 + ID_SIZE + LENGTH_SIZE )

/* SSH ID information */

#define SSH_ID					"SSH-"		/* Start of SSH ID */
#define SSH_ID_SIZE				4	/* Size of SSH ID */
#define SSH_ID_MAX_SIZE			255	/* Max.size of SSHv2 ID string */
#define SSH_ID_STRING			"SSH-1.5-cryptlib"
#define SSH2_ID_STRING			"SSH-2.0-cryptlib"	/* cryptlib SSH ID strings */

/* SSHv1 packet types */

#define SSH_MSG_DISCONNECT		1	/* Disconnect session */
#define SSH_SMSG_PUBLIC_KEY		2	/* Server public key */
#define SSH_CMSG_SESSION_KEY	3	/* Encrypted session key */
#define SSH_CMSG_USER			4	/* User name */
#define SSH_CMSG_AUTH_RSA		6	/* RSA public key */
#define SSH_SMSG_AUTH_RSA_CHALLENGE 7	/* RSA challenge from server */
#define SSH_CMSG_AUTH_RSA_RESPONSE 8	/* RSA response from client */
#define SSH_CMSG_AUTH_PASSWORD	9	/* Password */
#define SSH_CMSG_REQUEST_PTY	10	/* Request a pty */
#define SSH_CMSG_EXEC_SHELL		12	/* Request a shell */
#define SSH_CMSG_EXEC_CMD		13	/* Request command execution */
#define SSH_SMSG_SUCCESS		14	/* Success status message */
#define SSH_SMSG_FAILURE		15	/* Failure status message */
#define SSH_CMSG_STDIN_DATA		16	/* Data from client stdin */
#define SSH_SMSG_STDOUT_DATA	17	/* Data from server stdout */
#define SSH_SMSG_EXITSTATUS		20	/* Exit status of command run on server */
#define SSH_MSG_IGNORE			32	/* No-op */
#define SSH_CMSG_EXIT_CONFIRMATION 33 /* Client response to server exitstatus */
#define SSH_MSG_DEBUG			36	/* Debugging/informational message */
#define SSH_CMSG_MAX_PACKET_SIZE 38	/* Maximum data packet size */

/* Further SSHv1 packet types which aren't used but which we need to 
   recognise */

#define SSH_CMSG_PORT_FORWARD_REQUEST		28
#define SSH_CMSG_AGENT_REQUEST_FORWARDING	30
#define SSH_CMSG_X11_REQUEST_FORWARDING		34
#define SSH_CMSG_REQUEST_COMPRESSION		37

/* SSHv2 packet types.  There is some overlap with SSHv1, but an annoying
   number of messages have the same name but different values */

#define SSH2_MSG_DISCONNECT		1	/* Disconnect session */
#define SSH2_MSG_IGNORE			2	/* No-op */
#define SSH2_MSG_DEBUG			4	/* No-op */
#define SSH2_MSG_SERVICE_REQUEST 5	/* Request authentiction */
#define SSH2_MSG_SERVICE_ACCEPT	6	/* Acknowledge request */
#define SSH2_MSG_KEXINIT		20	/* Hello */
#define SSH2_MSG_NEWKEYS		21	/* Change cipherspec */
#define SSH2_MSG_KEXDH_INIT		30	/* DH, phase 1 */
#define SSH2_MSG_KEXDH_REPLY	31	/* DH, phase 2 */
#define SSH2_MSG_USERAUTH_REQUEST 50 /* Request authentication */
#define SSH2_MSG_USERAUTH_FAILURE 51 /* Authentication failed */
#define SSH2_MSG_USERAUTH_SUCCESS 52 /* Authentication succeeded */
#define SSH2_MSG_USERAUTH_BANNER 53	/* No-op */
#define	SSH2_MSG_CHANNEL_OPEN	90	/* Open a channel over SSH link */
#define	SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91	/* Channel open succeeded */
#define	SSH2_MSG_CHANNEL_WINDOW_ADJUST 93	/* No-op */
#define SSH2_MSG_CHANNEL_DATA	94	/* Data */
#define SSH2_MSG_CHANNEL_REQUEST 98	/* Open' a channel' over SSH link */
#define SSH2_MSG_CHANNEL_SUCCESS 99	/* Channel' open' succeeded */

/* Special-case expected-packet-type values which are passed to readPacket()
   to handle situations where more than one return value is valid.  CMSG_USER
   can return failure meaning "no password" even if there's no actual 
   failure, CMSG_AUTH_PASSWORD can return SMSG_FAILURE which indicates a 
   wrong password used iff it's a response to the client sending a password,
   and MSG_USERAUTH_REQUEST can similarly return a failure or success 
   response.
   
   In addition to these types there's a "any" type which is used during the
   setup negotiation which will accept any (non-error) packet type and return
   the type as the return code */

#define SSH_MSG_SPECIAL_USEROPT		500	/* Value to handle SSHv1 user name */
#define SSH_MSG_SPECIAL_PWOPT		501	/* Value to handle SSHv1 password */
#define SSH_MSG_SPECIAL_USERAUTH	502	/* Value to handle SSHv2 combined auth.*/
#define SSH_MSG_SPECIAL_RSAOPT		503	/* Value to handle RSA challenge */
#define SSH_MSG_SPECIAL_ANY			504	/* Any packet type */

/* SSHv1 cipher types */

#define SSH_CIPHER_NONE			0	/* No encryption */
#define SSH_CIPHER_IDEA			1	/* IDEA/CFB */
#define SSH_CIPHER_DES			2	/* DES/CBC */
#define SSH_CIPHER_3DES			3	/* 3DES/inner-CBC */
#define SSH_CIPHER_TSS			4	/* Deprecated */
#define SSH_CIPHER_RC4			5	/* RC4 */
#define SSH_CIPHER_BLOWFISH		6	/* Blowfish */
#define SSH_CIPHER_CRIPPLED		7	/* Reserved, from ssh 1.2.x source */

/* SSHv1 authentication types */

#define SSH_AUTH_RHOSTS			1	/* .rhosts or /etc/hosts.equiv */
#define SSH_AUTH_RSA			2	/* RSA challenge-response */
#define SSH_AUTH_PASSWORD		3	/* Password */
#define SSH_AUTH_RHOSTS_RSA		4	/* .rhosts with RSA challenge-response */
#define SSH_AUTH_TIS			5	/* TIS authsrv */
#define SSH_AUTH_KERBEROS		6	/* Kerberos */
#define SSH_PASS_KERBEROS_TGT	7	/* Kerberos TGT-passing */

/* Macros to evaluate the effective length for a packet and the number of 
   padding bytes to add to a packet to make it a multiple of 8 bytes (SSHv1)
   or the cipher block size (SSHv2) long.

   SSHv2 uses a peculiar means of determining the padding length which
   requires a minimum padding size of 4 bytes.  This isn't easy to evaluate
   in one go without using intermediate variables, which in turn is 
   difficult to do in a macro.  Because of this we have to break the 
   operation into two parts, storing the output of the first part in a temp.
   variable.  The first part gets the remainder, the second part evaluates
   the padding size, scaling it upwards by an extra block if the remainder 
   size is within 4 bytes of the block size, which would cause the pad length
   to be less than 4 bytes */

#define getEffectiveLength1( length ) \
		( ID_SIZE + ( length ) + CRC_SIZE )
#define getEffectiveLength2( length ) \
		( PADLENGTH_SIZE + ( length ) )
#define getPadLength1( length ) \
		( 8 - ( getEffectiveLength1( length ) & 7 ) )
#define getPrePadLength2( length, blockSize ) \
		( ( LENGTH_SIZE + getEffectiveLength2( length ) ) & ( ( blockSize ) - 1 ) )
#define getFinalPadLength2( length, blockSize ) \
		( ( ( length ) > ( blockSize ) - 4 ) ? \
			( ( 2 * ( blockSize ) ) - ( length ) ) : ( ( blockSize ) - ( length ) ) )

/* SSH handshake state information.  This is passed around various 
   subfunctions which handle individual parts of the handshake */

typedef struct SH {
	/* SSHv1 session state information/SSHv2 exchange hash */
	BYTE cookie[ SSH_COOKIE_SIZE ];			/* Anti-spoofing cookie */
	BYTE sessionID[ CRYPT_MAX_HASHSIZE ];	/* Session ID/exchange hash */
	int sessionIDlength;
	CRYPT_CONTEXT iExchangeHashcontext;		/* Hash of exchanged info */

	/* Information needed to compute the session ID.  SSHv1 requires the 
	   host and server key modulus, SSHv2 requires the client DH value 
	   (along with various other things, but these are hashed inline).
	   Since the data fields are rather large and also disjoint, we alias
	   one to the other */
	BYTE hostModulus[ CRYPT_MAX_PKCSIZE ], serverModulus[ CRYPT_MAX_PKCSIZE ];
	#define clientKeyexValue	hostModulus
	int hostModulusLength, serverModulusLength, clientKeyexValueLength;

	/* Encryption algorithm and key information */
	CRYPT_ALGO pubkeyAlgo;					/* Host signature algo */
	BYTE secretValue[ CRYPT_MAX_PKCSIZE ];	/* Shared secret value */
	int secretValueLength;

	/* Short-term server key (SSHv1) or DH key agreement context (SSHv2).
	   The long-term host key is stored as the session info 
	   iKeyexCryptContext for the client and privateKey for the server */
	CRYPT_CONTEXT iServerCryptContext;

	/* Function pointers to SSHv1 or SSHv2 functions */
	int ( *beginClientHandshake )( SESSION_INFO *sessionInfoPtr, 
								   struct SH *handshakeInfo );
	int ( *exchangeClientKeys )( SESSION_INFO *sessionInfoPtr, 
								 struct SH *handshakeInfo );
	int ( *completeClientHandshake )( SESSION_INFO *sessionInfoPtr, 
									  struct SH *handshakeInfo );
	} SSH_HANDSHAKE_INFO;

/* Mapping of SSHv2 algorithm names to cryptlib algorithm IDs, in
   preferred algorithm order */

typedef struct {
	const char *name;						/* Algorithm name */
	const CRYPT_ALGO algo;					/* Algorithm ID */
	} ALGO_STRING_INFO;

static const ALGO_STRING_INFO algoStringCoprTbl[] = {
	{ "none", CRYPT_ALGO_NONE },
	{ NULL, 0 }
	};
static const ALGO_STRING_INFO algoStringPubkeyTbl[] = {
	{ "ssh-rsa", CRYPT_ALGO_RSA },
	{ "ssh-dsa", CRYPT_ALGO_DSA },
	{ NULL, 0 }
	};
static const ALGO_STRING_INFO algoStringEncrTbl[] = {
	{ "3des-cbc", CRYPT_ALGO_3DES },
	{ "blowfish-cbc", CRYPT_ALGO_BLOWFISH },
	{ "aes128-cbc", CRYPT_ALGO_AES },
	{ "cast128-cbc", CRYPT_ALGO_CAST },
	{ "idea-cbc", CRYPT_ALGO_IDEA },
	{ NULL, 0 }
	};
static const ALGO_STRING_INFO algoStringKeyexTbl[] = {
	{ "diffie-hellman-group1-sha1", CRYPT_ALGO_DH },
	{ NULL, 0 }
	};
static const ALGO_STRING_INFO algoStringMACTbl[] = {
	{ "hmac-sha1", CRYPT_ALGO_HMAC_SHA },
	{ "hmac-md5", CRYPT_ALGO_HMAC_MD5 },
	{ NULL, 0 }
	};
static const ALGO_STRING_INFO algoStringUserauthentTbl[] = {
	{ "password", CRYPT_ALGO_DES },
	{ "publickey", CRYPT_ALGO_RSA },
	{ NULL, 0 }
	};
static const ALGO_STRING_INFO algoStringMapTbl[] = {
	{ "none", CRYPT_ALGO_NONE },
	{ "ssh-rsa", CRYPT_ALGO_RSA },
	{ "ssh-dsa", CRYPT_ALGO_DSA },
	{ "3des-cbc", CRYPT_ALGO_3DES },
	{ "blowfish-cbc", CRYPT_ALGO_BLOWFISH },
	{ "aes128-cbc", CRYPT_ALGO_AES },
	{ "idea-cbc", CRYPT_ALGO_IDEA },
	{ "cast128-cbc", CRYPT_ALGO_CAST },
	{ "diffie-hellman-group1-sha1", CRYPT_ALGO_DH },
	{ "hmac-sha1", CRYPT_ALGO_HMAC_SHA },
	{ "hmac-md5", CRYPT_ALGO_HMAC_MD5 },
	{ NULL, CRYPT_ALGO_NONE }
	};

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Initialise and destroy the handshake state information */

static int initHandshakeInfo( SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	/* Initialise the handshake state info values */
	memset( handshakeInfo, 0, sizeof( SSH_HANDSHAKE_INFO ) );
	handshakeInfo->iExchangeHashcontext = \
		handshakeInfo->iServerCryptContext = CRYPT_ERROR;

	return( CRYPT_OK );
	}

static void destroyHandshakeInfo( SSH_HANDSHAKE_INFO *handshakeInfo )
	{
	/* Destroy any active contexts */
	if( handshakeInfo->iExchangeHashcontext != CRYPT_ERROR )
		krnlSendNotifier( handshakeInfo->iExchangeHashcontext,
						  RESOURCE_IMESSAGE_DECREFCOUNT );
	if( handshakeInfo->iServerCryptContext != CRYPT_ERROR )
		krnlSendNotifier( handshakeInfo->iServerCryptContext,
						  RESOURCE_IMESSAGE_DECREFCOUNT );

	zeroise( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) );
	}

/* Initialise and destroy the security contexts */

static void destroySecurityContexts( SESSION_INFO *sessionInfoPtr )
	{
	/* Destroy any active contexts */
	if( sessionInfoPtr->iKeyexCryptContext != CRYPT_ERROR )
		{
		krnlSendNotifier( sessionInfoPtr->iKeyexCryptContext,
						  RESOURCE_IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iKeyexCryptContext = CRYPT_ERROR;
		}
	if( sessionInfoPtr->iCryptInContext != CRYPT_ERROR )
		{
		krnlSendNotifier( sessionInfoPtr->iCryptInContext,
						  RESOURCE_IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iCryptInContext = CRYPT_ERROR;
		}
	if( sessionInfoPtr->iCryptOutContext != CRYPT_ERROR )
		{
		krnlSendNotifier( sessionInfoPtr->iCryptOutContext,
						  RESOURCE_IMESSAGE_DECREFCOUNT );
		sessionInfoPtr->iCryptOutContext = CRYPT_ERROR;

⌨️ 快捷键说明

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