📄 ssh.c
字号:
/****************************************************************************
* *
* cryptlib SSH Test Routines *
* Copyright Peter Gutmann 1998-2005 *
* *
****************************************************************************/
#include "cryptlib.h"
#include "test/test.h"
#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
using 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_EXEC, /* Test rexec rather than rsh functionality */
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_DUALTHREAD,
SSH_TEST_DUALTHREAD2 /* Two-phase connect via different threads */
} SSH_TEST_TYPE;
#if defined( TEST_SESSION ) || defined( TEST_SESSION_LOOPBACK )
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Test the ability to parse URLs */
typedef 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 */
} URL_PARSE_INFO;
static const FAR_BSS URL_PARSE_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" ) },
{ TEXT( "http://www.server.com/location.php" ), TEXT( "www.server.com/location.php" ), 0, NULL },
{ TEXT( "http://www.server.com:80/location.php" ), TEXT( "www.server.com/location.php" ), 80, NULL },
{ TEXT( "http://www.server.com/location1/location2/location.php" ), TEXT( "www.server.com/location1/location2/location.php" ), 0, NULL },
/* Spurious whitespace */
{ TEXT( " www.server.com : 80 " ), TEXT( "www.server.com" ), 80, NULL },
{ TEXT( " user @ www.server.com : 80 " ), TEXT( "www.server.com" ), 80, NULL },
{ TEXT( "http:// user @ www.server.com : 80 " ), TEXT( "www.server.com" ), 80, TEXT( "user" ) },
{ TEXT( "www.server.com : 80 /location.php" ), TEXT( "www.server.com/location.php" ), 80, NULL },
{ NULL, NULL, 0, NULL }
};
static const FAR_BSS URL_PARSE_INFO invalidUrlParseInfo[] = {
/* Bad port */
{ TEXT( "www.server.com:2" ), NULL, 0, NULL },
{ TEXT( "www.server.com:80abcd" ), NULL, 0, NULL },
{ TEXT( "www.server.com:abcd" ), NULL, 0, NULL },
/* Bad general URI */
{ TEXT( "http://" ), NULL, 0, NULL },
{ TEXT( "http://xy" ), NULL, 0, NULL },
{ TEXT( "@www.server.com" ), NULL, 0, NULL },
{ TEXT( " @www.server.com" ), NULL, 0, NULL },
{ 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 nameLength, userInfoLength, port;
/* Clear any leftover attributes from previous tests */
memset( nameBuffer, 0, 16 );
memset( userInfoBuffer, 0, 16 );
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, &nameLength );
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( paramStrlen( urlParseInfo[ i ].name ) != ( size_t ) nameLength || \
memcmp( nameBuffer, urlParseInfo[ i ].name, nameLength ) || \
( 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 );
}
}
/* Now try it with invalid URLs */
for( i = 0; invalidUrlParseInfo[ i ].url != NULL; i++ )
{
/* 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,
invalidUrlParseInfo[ i ].url,
paramStrlen( invalidUrlParseInfo[ i ].url ) );
if( cryptStatusOK( status ) )
{
printf( "Invalid URL '%s' was accepted as valid, line %d.\n",
invalidUrlParseInfo[ 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 session attribute handling */
int testSessionAttributes( void )
{
CRYPT_SESSION cryptSession;
int status;
puts( "Testing session attribute handling..." );
/* Create a server session of the most generic type */
status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
CRYPT_SESSION_SSL_SERVER );
if( status == CRYPT_ERROR_PARAM3 ) /* SSL server session access not avail.*/
return( CRYPT_ERROR_NOTAVAIL );
if( cryptStatusError( status ) )
{
printf( "cryptCreateSession() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
/* Add an initial attribute */
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_SERVER_NAME, TEXT( "servername" ),
paramStrlen( TEXT( "servername" ) ) );
if( cryptStatusError( status ) )
{
printf( "cryptSetAttributeString() failed with error code %d, "
"line %d.\n", status, __LINE__ );
return( FALSE );
}
/* Add several username/password pairs */
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "test1" ),
paramStrlen( TEXT( "test1" ) ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD, TEXT( "test1" ),
paramStrlen( TEXT( "test1" ) ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "test2" ),
paramStrlen( TEXT( "test2" ) ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD, TEXT( "test2" ),
paramStrlen( TEXT( "test2" ) ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "test3" ),
paramStrlen( TEXT( "test3" ) ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD, TEXT( "test3" ),
paramStrlen( TEXT( "test3" ) ) );
if( cryptStatusError( status ) )
{
printf( "cryptSetAttributeString() for username/password pairs "
"failed with error code %d, line %d.\n", status, __LINE__ );
return( FALSE );
}
/* Add a duplicate entry and make sure that it's detected */
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "test2" ),
paramStrlen( TEXT( "test2" ) ) );
if( status != CRYPT_ERROR_DUPLICATE )
{
printf( "Addition of duplicate user/password entry wasn't detected, "
"line %d.\n", __LINE__ );
return( FALSE );
}
/* Add a password without a preceding username and make sure that it's
detected */
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD, TEXT( "invalid_pw" ),
paramStrlen( TEXT( "invalid_pw" ) ) );
if( status != CRYPT_ERROR_NOTINITED )
{
printf( "Addition of password without username wasn't detected, "
"line %d.\n", __LINE__ );
return( FALSE );
}
/* Add a username without a password and make sure that it's detected */
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "valid_name" ),
paramStrlen( TEXT( "valid_name" ) ) );
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME, TEXT( "invalid_name" ),
paramStrlen( TEXT( "invalid_name" ) ) );
if( status != CRYPT_ERROR_PARAM2 )
{
printf( "Addition of username without password wasn't detected, "
"line %d.\n", __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 attribute handling succeeded.\n" );
return( TRUE );
}
/****************************************************************************
* *
* SSH Utility Functions *
* *
****************************************************************************/
#if defined( WINDOWS_THREADS ) || defined( UNIX_THREADS )
/* 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 */
#ifdef WINDOWS_THREADS
unsigned __stdcall sshServerMultiThread( void *dummy )
#else
void *sshServerMultiThread( void *dummy )
#endif /* Windows vs. pthreads */
{
CRYPT_SESSION cryptSession;
CRYPT_CONTEXT privateKey;
int status;
printf( "Server thread %lX activated.\n", THREAD_SELF() );
fflush( stdout );
/* 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,
USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
if( cryptStatusOK( status ) )
{
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_PRIVATEKEY, privateKey );
cryptDestroyContext( privateKey );
}
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_AUTHRESPONSE,
TRUE );
if( cryptStatusError( status ) )
{
printf( "Private key read/set 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() );
fflush( stdout );
THREAD_EXIT();
}
#ifdef WINDOWS_THREADS
unsigned __stdcall sshClientMultiThread( void *dummy )
#else
void *sshClientMultiThread( void *dummy )
#endif /* Windows vs. pthreads */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -