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

📄 ssh.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*							cryptlib SSH Test Routines						*
*						Copyright Peter Gutmann 1998-2005					*
*																			*
****************************************************************************/

#ifdef _MSC_VER
  #include "../cryptlib.h"
  #include "test.h"
#else
  #include "cryptlib.h"
  #include "test/test.h"
#endif /* Braindamaged MSC include handling */

#if defined( __MVS__ ) || defined( __VMCMS__ )
  /* Suspend conversion of literals to ASCII. */
  #pragma convlit( suspend )
#endif /* IBM big iron */
#if defined( __ILEC400__ )
  #pragma convert( 0 )
#endif /* IBM medium iron */

/* Uncomment the following to ask the user for a password rather than using
   a hardcoded password when testing against live accounts */

/* #define USER_SUPPLIED_PASSWORD */
#ifdef USER_SUPPLIED_PASSWORD
  #undef SSH2_SERVER_NAME
  #undef SSH_USER_NAME
  #define SSH2_SERVER_NAME	"testserver"
  #define SSH_USER_NAME		"testname"
#endif /* USER_SUPPLIED_PASSWORD */

/* We can run the SSH self-test with a large variety of options, rather than
   use dozens of boolean option flags to control them all we define various
   test classes that exercise each option type */

typedef enum {
	SSH_TEST_NORMAL,			/* Standard SSHv2 test */
	SSH_TEST_SSH1,				/* SSHv1 test */
	SSH_TEST_CLIENTCERT,		/* Use client public-key for auth */
	SSH_TEST_SUBSYSTEM,			/* Test SFTP subsystem */
	SSH_TEST_PORTFORWARDING,	/* Test port forwarding */
	SSH_TEST_MULTICHANNEL,		/* Test multi-channel handling */
	SSH_TEST_FINGERPRINT,		/* Test (invalid) key fingerprint */
	SSH_TEST_CONFIRMAUTH		/* Test manual server confirmation of auth.*/
	} SSH_TEST_TYPE;

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

/* Test the ability to parse URLs */

static const struct {
	const C_STR url;			/* Server URL */
	const C_STR name;			/* Parsed server name */
	const int port;				/* Parsed server port */
	const C_STR userInfo;		/* Parsed user info */
	} urlParseInfo[] = {
	/* IP address forms */
	{ TEXT( "1.2.3.4" ), TEXT( "1.2.3.4" ), 0, NULL },
	{ TEXT( "1.2.3.4:80" ), TEXT( "1.2.3.4" ), 80, NULL },
	{ TEXT( "user@1.2.3.4" ), TEXT( "1.2.3.4" ), 0, TEXT( "user" ) },
	{ TEXT( "[1:2:3:4]" ), TEXT( "1:2:3:4" ), 0, NULL },
	{ TEXT( "[1:2:3:4]:80" ), TEXT( "1:2:3:4" ), 80, NULL },
	{ TEXT( "user@[1:2:3:4]" ), TEXT( "1:2:3:4" ), 0, TEXT( "user" ) },

	/* General URI forms */
	{ TEXT( "www.server.com" ), TEXT( "www.server.com" ), 0, NULL },
	{ TEXT( "www.server.com:80" ), TEXT( "www.server.com" ), 80, NULL },
	{ TEXT( "http://www.server.com:80" ), TEXT( "www.server.com" ), 80, NULL },
	{ TEXT( "http://user@www.server.com:80" ), TEXT( "www.server.com" ), 80, TEXT( "user" ) },

	/* Spurious whitespace */
	{ TEXT( "  www.server.com  :   80 " ), TEXT( "www.server.com" ), 80, NULL },
	{ TEXT( "http:// user  @ www.server.com  :   80 " ), TEXT( "www.server.com" ), 80, TEXT( "user" ) },
	{ NULL, NULL, 0, NULL }
	};

int testSessionUrlParse( void )
	{
	CRYPT_SESSION cryptSession;
	int i, status;

	puts( "Testing session URL parsing..." );

	/* Create a session of the most generic type */
	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, CRYPT_SESSION_SSL );
	if( status == CRYPT_ERROR_PARAM3 )	/* SSL session access not available */
		return( CRYPT_ERROR_NOTAVAIL );
	if( cryptStatusError( status ) )
		{
		printf( "cryptCreateSession() failed with error code %d, line %d.\n",
				status, __LINE__ );
		return( FALSE );
		}

	/* Set various URLs as the server name and retrieve the parsed form */
	for( i = 0; urlParseInfo[ i ].url != NULL; i++ )
		{
		C_CHR nameBuffer[ 256 ], userInfoBuffer[ 256 ];
		int lengthLength, userInfoLength, port;

		/* Clear any leftover attributes from previous tests */
		cryptDeleteAttribute( cryptSession, CRYPT_SESSINFO_SERVER_NAME );
		cryptDeleteAttribute( cryptSession, CRYPT_SESSINFO_SERVER_PORT );
		cryptDeleteAttribute( cryptSession, CRYPT_SESSINFO_USERNAME );

		/* Set the URL */
		status = cryptSetAttributeString( cryptSession,
										  CRYPT_SESSINFO_SERVER_NAME,
										  urlParseInfo[ i ].url,
										  paramStrlen( urlParseInfo[ i ].url ) );
		if( cryptStatusError( status ) )
			{
			printf( "Couldn't set URL '%s', line %d.\n",
					urlParseInfo[ i ].url, __LINE__ );
			return( FALSE );
			}

		/* Make sure that the parsed form is OK */
		status = cryptGetAttributeString( cryptSession,
										  CRYPT_SESSINFO_SERVER_NAME,
										  nameBuffer, &lengthLength );
		if( cryptStatusOK( status ) && urlParseInfo[ i ].port )
			status = cryptGetAttribute( cryptSession,
										CRYPT_SESSINFO_SERVER_PORT, &port );
		if( cryptStatusOK( status ) && urlParseInfo[ i ].userInfo != NULL )
			status = cryptGetAttributeString( cryptSession,
											  CRYPT_SESSINFO_USERNAME,
											  userInfoBuffer,
											  &userInfoLength );
		if( cryptStatusError( status ) )
			{
			printf( "Couldn't get parsed URL info for '%s', line %d.\n",
					urlParseInfo[ i ].url, __LINE__ );
			return( FALSE );
			}
		if( memcmp( nameBuffer, urlParseInfo[ i ].name, lengthLength ) || \
			( urlParseInfo[ i ].port && port != urlParseInfo[ i ].port ) || \
			( urlParseInfo[ i ].userInfo != NULL && \
			  memcmp( userInfoBuffer, urlParseInfo[ i ].userInfo,
			  userInfoLength ) ) )
			{
			printf( "Parsed URL info for '%s' is incorrect, line %d.\n",
					urlParseInfo[ i ].url, __LINE__ );
			return( FALSE );
			}
		}

	/* Clean up */
	status = cryptDestroySession( cryptSession );
	if( cryptStatusError( status ) )
		{
		printf( "cryptDestroySession() failed with error code %d, line %d.\n",
				status, __LINE__ );
		return( FALSE );
		}
	puts( "Session URL parsing succeeded.\n" );
	return( TRUE );
	}

/* Test the ability to have multiple server threads waiting on a session.
   Since this requries (OS-specific) threading, we just use two sample
   systems, Win32 (Windows threads) and Linux (pthreads).  Since Linux's
   somewhat strange not-quite-a-thread/not-quite-a-process implementation 
   can be a bit buggy, we also use another sample pthreads implementation 
   (FreeBSD/NetBSD) as a sanity check */

#define NO_SERVER_THREADS	4

#if defined( WINDOWS_THREADS ) || defined( __linux ) || \
	defined( __FreeBSD__ ) || defined( __NetBSD__ )

#if defined( __FreeBSD__ ) || defined( __NetBSD__ )
  #include <pthread.h>
#endif /* FreeBSD || NetBSD */

#ifdef WINDOWS_THREADS
  #define THREAD_HANDLE		HANDLE
  #define THREAD_EXIT()		_endthreadex( 0 ); return( 0 )
  #define THREAD_SELF()		GetCurrentThreadId()
#else
  #define THREAD_HANDLE		pthread_t
  #define THREAD_EXIT()		pthread_exit( ( void * ) 0 ); return
  #define THREAD_SELF()		pthread_self()
#endif /* Windows vs. pthreads */

#ifdef WINDOWS_THREADS
  unsigned __stdcall sshMultiServerThread( void *dummy )
#else
  void *sshMultiServerThread( void *dummy )
#endif /* Windows vs. pthreads */
	{
	CRYPT_SESSION cryptSession;
	CRYPT_CONTEXT privateKey;
	int status;

	printf( "Server thread %lX activated.\n", THREAD_SELF() );

	/* Create the session and try to activate it.  We don't do anything
	   beyond that point since this is a test of multi-thread handling
	   capability, not session handling */
	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
								 CRYPT_SESSION_SSH_SERVER );
	if( cryptStatusError( status ) )
		{
		printf( "cryptCreateSession() failed with error code %d, line %d.\n",
				status, __LINE__ );
		THREAD_EXIT();
		}
	if( !setLocalConnect( cryptSession, 22 ) )
		{
		THREAD_EXIT();
		}
	status = getPrivateKey( &privateKey, SSH_PRIVKEY_FILE,
							SSH_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
	if( cryptStatusOK( status ) )
		{
		status = cryptSetAttribute( cryptSession,
									CRYPT_SESSINFO_PRIVATEKEY, privateKey );
		cryptDestroyContext( privateKey );
		}
	if( cryptStatusError( status ) )
		{
		printf( "cryptSetAttribute/AttributeString() failed with error code "
				"%d, line %d.\n", status, __LINE__ );
		THREAD_EXIT();
		}
	printf( "Server for thread %lX activated.\n", THREAD_SELF() );
	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
	printConnectInfo( cryptSession );
	if( cryptStatusError( status ) )
		printExtError( cryptSession,
					   "Attempt to activate SSH server session", status,
					   __LINE__ );
	cryptDestroySession( cryptSession );
	printf( "Server for thread %lX has exited.\n", THREAD_SELF() );

	THREAD_EXIT();
	}

#ifdef WINDOWS_THREADS
  unsigned __stdcall sshMultiClientThread( void *dummy )
#else
  void *sshMultiClientThread( void *dummy )
#endif /* Windows vs. pthreads */
	{
	CRYPT_SESSION cryptSession;
	int status;

	printf( "Client thread %lX activated.\n", THREAD_SELF() );

	/* Create the session and try to activate it.  We don't do anything
	   beyond that point since this is a test of multi-thread handling
	   capability, not session handling */
	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
								 CRYPT_SESSION_SSH );
	if( cryptStatusError( status ) )
		{
		printf( "cryptCreateSession() failed with error code %d, line %d.\n",
				status, __LINE__ );
		THREAD_EXIT();
		}
	if( !setLocalConnect( cryptSession, 22 ) )
		{
		THREAD_EXIT();
		}
	status = cryptSetAttribute( cryptSession,
								CRYPT_OPTION_NET_CONNECTTIMEOUT, 10 );
	if( cryptStatusOK( status ) )
		status = cryptSetAttributeString( cryptSession,
										  CRYPT_SESSINFO_USERNAME,
										  SSH_USER_NAME,
										  paramStrlen( SSH_USER_NAME ) );
	if( cryptStatusOK( status ) )
		status = cryptSetAttributeString( cryptSession,
										  CRYPT_SESSINFO_PASSWORD,
										  SSH_PASSWORD,
										  paramStrlen( SSH_PASSWORD ) );
	if( cryptStatusError( status ) )
		{
		printf( "cryptSetAttribute/AttributeString() failed with error code "
				"%d, line %d.\n", status, __LINE__ );
		THREAD_EXIT();
		}
	printf( "Client for thread %lX activated.\n", THREAD_SELF() );
	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
	printConnectInfo( cryptSession );
	if( cryptStatusError( status ) )
		printExtError( cryptSession,
					   "Attempt to activate SSH client session", status,
					   __LINE__ );
	cryptDestroySession( cryptSession );
	printf( "Client for thread %lX has exited.\n", THREAD_SELF() );

	THREAD_EXIT();
	}

int testSessionSSHMultiServer( void )
	{
	THREAD_HANDLE hClientThreads[ NO_SERVER_THREADS ];
	THREAD_HANDLE hServerThreads[ NO_SERVER_THREADS ];
	int i;

	/* Start the sessions and wait for them initialise.  We have to wait for
	   some time since the multiple private key reads can take awhile */
	for( i = 0; i < NO_SERVER_THREADS; i++ )
		{
#ifdef WINDOWS_THREADS
		unsigned int threadID;

		hServerThreads[ i ] = ( HANDLE ) \
						_beginthreadex( NULL, 0, sshMultiServerThread,
										NULL, 0, &threadID );
#else
		pthread_t threadHandle;

		hServerThreads[ i ] = 0;
		if( pthread_create( &threadHandle, NULL, sshMultiServerThread,
							NULL ) == 0 )
			hServerThreads[ i ] = threadHandle;
#endif /* Windows vs. pthreads */
		}
	delayThread( 3 );

	/* Connect to the local server */
	for( i = 0; i < NO_SERVER_THREADS; i++ )
		{
#ifdef WINDOWS_THREADS
		unsigned int threadID;

		hClientThreads[ i ] = ( HANDLE ) \
						_beginthreadex( NULL, 0, sshMultiClientThread,
										NULL, 0, &threadID );
#else
		pthread_t threadHandle;

		hServerThreads[ i ] = 0;
		if( pthread_create( &threadHandle, NULL, sshMultiClientThread,
							NULL ) == 0 )
			hClientThreads[ i ] = threadHandle;
#endif /* Windows vs. pthreads */
		}
#ifdef WINDOWS_THREADS
	if( WaitForMultipleObjects( NO_SERVER_THREADS, hServerThreads, TRUE,
								60000 ) == WAIT_TIMEOUT )
#else
	/* Posix doesn't have an ability to wait for multiple threads for mostly
	   religious reasons ("That's not how we do things around here") so we
	   just wait for two token threads */
	pthread_join( hServerThreads[ 0 ], NULL );
	pthread_join( hClientThreads[ 0 ], NULL );
#endif /* Windows vs. pthreads */
		{
		puts( "Warning: Server threads are still active due to session "
			  "negotiation failure,\n         this will cause an error "
			  "condition when cryptEnd() is called due\n         to "
			  "resources remaining allocated.  Press a key to continue." );
		getchar();
		}
#ifdef WINDOWS_THREADS
	for( i = 0; i < NO_SERVER_THREADS; i++ )
		if( hServerThreads[ i ] != 0 )
			CloseHandle( hServerThreads[ i ] );
	for( i = 0; i < NO_SERVER_THREADS; i++ )
		if( hClientThreads[ i ] != 0 )
			CloseHandle( hClientThreads[ i ] );
#endif /* Windows vs. pthreads */

	return( TRUE );
	}
#endif /* OS-specific threading functions */

/* Create an SSH channel */

static int createChannel( const CRYPT_SESSION cryptSession,
						  const C_STR type, const C_STR arg1 )
	{
	int status;

	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_SSH_CHANNEL,
								CRYPT_UNUSED );
	if( cryptStatusOK( status ) )
		status = cryptSetAttributeString( cryptSession,
										  CRYPT_SESSINFO_SSH_CHANNEL_TYPE,
										  type, paramStrlen( type ) );
	if( cryptStatusOK( status ) )
		status = cryptSetAttributeString( cryptSession,
										  CRYPT_SESSINFO_SSH_CHANNEL_ARG1,
										  arg1, paramStrlen( arg1 ) );
	return( status );
	}

/* Print information on an SSH channel */

static int printChannelInfo( const CRYPT_SESSION cryptSession,
							 const SSH_TEST_TYPE testType,
							 const BOOLEAN isServer )
	{
	C_CHR stringBuffer[ CRYPT_MAX_TEXTSIZE + 1 ];

⌨️ 快捷键说明

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