📄 ssh.c
字号:
C_CHR argBuffer[ CRYPT_MAX_TEXTSIZE + 1 ];
int channel, stringLength, argLength = 0, status;
status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_SSH_CHANNEL,
&channel );
if( cryptStatusOK( status ) )
status = cryptGetAttributeString( cryptSession,
CRYPT_SESSINFO_SSH_CHANNEL_TYPE,
stringBuffer, &stringLength );
if( cryptStatusError( status ) )
{
printf( "%sCouldn't query channel ID/type, status %d, line %d.\n",
isServer ? "SVR: " : "", status, __LINE__ );
return( status );
}
#ifdef UNICODE_STRINGS
stringBuffer[ stringLength / sizeof( wchar_t ) ] = TEXT( '\0' );
#else
stringBuffer[ stringLength ] = '\0';
#endif /* UNICODE_STRINGS */
if( !paramStrcmp( stringBuffer, TEXT( "subsystem" ) ) || \
!paramStrcmp( stringBuffer, TEXT( "direct-tcpip" ) ) )
{
status = cryptGetAttributeString( cryptSession,
CRYPT_SESSINFO_SSH_CHANNEL_ARG1,
argBuffer, &argLength );
if( cryptStatusError( status ) )
{
printf( "%sCouldn't query channel arg, status %d, line %d.\n",
isServer ? "SVR: " : "", status, __LINE__ );
return( status );
}
#ifdef UNICODE_STRINGS
argBuffer[ argLength / sizeof( wchar_t ) ] = TEXT( '\0' );
printf( "SVR: Client opened channel #%d, type '%S', arg '%S'.\n",
channel, stringBuffer, argBuffer );
#else
argBuffer[ argLength ] = '\0';
printf( "SVR: Client opened channel #%d, type '%s', arg '%s'.\n",
channel, stringBuffer, argBuffer );
#endif /* UNICODE_STRINGS */
return( CRYPT_OK );
}
if( testType == SSH_TEST_SUBSYSTEM )
{
printf( "SVR: Client requested subsystem but server didn't "
"report it, line %d.\n", __LINE__ );
return( CRYPT_ERROR_FAILED );
}
#ifdef UNICODE_STRINGS
printf( "SVR: Client opened channel #%d, type '%S'.\n",
channel, stringBuffer );
#else
printf( "SVR: Client opened channel #%d, type '%s'.\n",
channel, stringBuffer );
#endif /* UNICODE_STRINGS */
return( CRYPT_OK );
}
/* Print information on data sent over an SSH channel */
static int printDataInfo( CRYPT_SESSION cryptSession,
char *buffer, int *bytesCopied,
const BOOLEAN isServer )
{
int channel, status;
status = cryptPopData( cryptSession, buffer, BUFFER_SIZE, bytesCopied );
if( cryptStatusError( status ) )
{
printf( "%sCouldn't read data from %s, status %d, line %d.\n",
isServer ? "SVR: " : "", isServer ? "client" : "server",
status, __LINE__ );
return( status );
}
buffer[ *bytesCopied ] = '\0';
cryptGetAttribute( cryptSession, CRYPT_SESSINFO_SSH_CHANNEL, &channel );
printf( "%s---- %s sent %d bytes on channel %d ----\n",
isServer ? "SVR: " : "", isServer ? "Client" : "Server",
*bytesCopied, channel );
if( isServer )
printf( "SVR: " );
puts( buffer );
printf( "%s---- End of output ----\n", isServer ? "SVR: " : "" );
return( CRYPT_OK );
}
/****************************************************************************
* *
* SSH Routines Test *
* *
****************************************************************************/
/* There are various servers running that we can use for testing, the
following remapping allows us to switch between them. Notes:
Server 1: Local loopback.
Server 2: Sends extraneous lines of text before the SSH ID string
(technically allowed by the RFC, but probably not in the way
that it's being used here).
Server 3: Reference ssh.com implementation.
Server 4: Reference OpenSSH implementation.
Server 5: Generic embedded device implementation.
To test local -> remote/remote -> local forwarding:
ssh localhost -v -l test -pw test -L 110:pop3.test.com:110
ssh localhost -v -l test -pw test -R 110:pop3.test.com:110
For test purposes we connect to the OpenSSH server for the SSHv2 test
because this is the most frequently-used one around, so maintaining
compatibility with it whenever it changes is important. Using it for test
connects is slightly antisocial but in practice few people seem to run the
self-test and we never get past the initial handshake phase so it shouldn't
be a big deal. Testing SSHv1 is a bit tricky since there are few of these
servers still around, in the absence of a convenient test server we just
try a local connect, which either times out or goes through an SSHv2
handshake if there's a server there */
static const C_STR ssh1Info[] = {
NULL,
TEXT( "localhost" ),
NULL
};
static const C_STR ssh2Info[] = {
NULL,
TEXT( "localhost" ),
TEXT( "sorrel.humboldt.edu:222" ),
TEXT( "www.ssh.com" ),
TEXT( "www.openssh.com" ),
NULL
};
#define SSH1_SERVER_NO 1
#define SSH2_SERVER_NO 4
/* Establish an SSH session. The generic SSHv1 client test will always step
up to SSHv2 if the server is v2 (which almost all are), so v1 can't
easily be generically tested without hardcoding v1-only into
session/ssh.c. However, the loopback test, which forces the use of a
v1-only server, does test the client as a v1 client */
static int connectSSH( const CRYPT_SESSION_TYPE sessionType,
const SSH_TEST_TYPE testType,
const BOOLEAN localSession )
{
CRYPT_SESSION cryptSession;
#ifdef SSH2_SERVER_NAME
const C_STR serverName = SSH2_SERVER_NAME;
#else
const C_STR serverName = localSession ? TEXT( "localhost" ) : \
( testType == SSH_TEST_SSH1 ) ? \
ssh1Info[ SSH1_SERVER_NO ] : \
ssh2Info[ SSH2_SERVER_NO ];
#endif /* SSH2_SERVER_NAME */
const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_SSH_SERVER ) ? \
TRUE : FALSE;
C_CHR stringBuffer[ CRYPT_MAX_TEXTSIZE + 1 ];
char buffer[ BUFFER_SIZE ];
int channel, length, bytesCopied, status;
printf( "%sTesting %sSSH%s%s session...\n",
isServer ? "SVR: " : "",
localSession ? "local " : "",
( testType == SSH_TEST_SSH1 ) ? "v1" : "v2",
( testType == SSH_TEST_SUBSYSTEM ) ? " SFTP" : \
( testType == SSH_TEST_PORTFORWARDING ) ? " port-forwarding" : \
( testType == SSH_TEST_MULTICHANNEL ) ? " multi-channel" : "" );
if( !isServer && !localSession )
#ifdef UNICODE_STRINGS
printf( " Remote host: %S.\n", serverName );
#else
printf( " Remote host: %s.\n", serverName );
#endif /* UNICODE_STRINGS */
/* Create the session */
status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType );
if( status == CRYPT_ERROR_PARAM3 ) /* SSH 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 up the server and user information and activate the session */
if( isServer )
{
CRYPT_CONTEXT privateKey;
if( !setLocalConnect( cryptSession, 22 ) )
return( FALSE );
status = getPrivateKey( &privateKey, SSH_PRIVKEY_FILE,
SSH_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
if( cryptStatusOK( status ) )
{
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_PRIVATEKEY, privateKey );
cryptDestroyContext( privateKey );
}
}
else
{
if( localSession )
{
if( !setLocalConnect( cryptSession, 22 ) )
return( FALSE );
}
else
{
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_SERVER_NAME,
serverName, paramStrlen( serverName ) );
}
if( cryptStatusOK( status ) )
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME,
SSH_USER_NAME,
paramStrlen( SSH_USER_NAME ) );
if( cryptStatusOK( status ) )
{
if( testType == SSH_TEST_CLIENTCERT )
{
CRYPT_CONTEXT privateKey;
status = getPrivateKey( &privateKey, USER_PRIVKEY_FILE,
USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
if( cryptStatusOK( status ) )
{
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_PRIVATEKEY, privateKey );
cryptDestroyContext( privateKey );
}
}
else
{
#ifdef USER_SUPPLIED_PASSWORD
char password[ 256 ];
printf( "Enter SSHv2 server password: " );
fgets( password, 255, stdin );
password[ strlen( password ) - 1 ] = '\0';
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD,
password, strlen( password ) );
#else
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD,
SSH_PASSWORD,
paramStrlen( SSH_PASSWORD ) );
#endif /* User-supplied password */
}
}
if( cryptStatusOK( status ) && \
( testType == SSH_TEST_SUBSYSTEM ) )
status = createChannel( cryptSession, TEXT( "subsystem" ),
TEXT( "sftp" ) );
if( cryptStatusOK( status ) && \
( testType == SSH_TEST_PORTFORWARDING || \
testType == SSH_TEST_MULTICHANNEL ) )
createChannel( cryptSession, TEXT( "direct-tcpip" ),
TEXT( "localhost:1234" ) );
if( cryptStatusOK( status ) && \
( testType == SSH_TEST_FINGERPRINT ) )
{
BYTE fingerPrint[ CRYPT_MAX_HASHSIZE ];
/* Set a dummy (all-zero) fingerprint to force the connect to
fail */
memset( fingerPrint, 0, CRYPT_MAX_HASHSIZE );
status = cryptSetAttributeString( cryptSession,
CRYPT_SESSINFO_SERVER_FINGERPRINT,
fingerPrint, 16 );
}
}
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_VERSION,
( testType == SSH_TEST_SSH1 ) ? 1 : 2 );
if( cryptStatusOK( status ) && isServer && \
testType != SSH_TEST_CONFIRMAUTH )
/* If we're not testing manual confirmation of client auth, have
cryptlib automatically confirm the auth */
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_AUTHRESPONSE,
TRUE );
if( cryptStatusError( status ) )
{
/* If we're trying to enable SSHv1 and it fails, this isn't an error
since this protocol is disabled by default */
if( testType == SSH_TEST_SSH1 )
{
puts( "SSHv1 appears to be disbled in this build." );
cryptDestroySession( cryptSession );
puts( isServer ? "SVR: SSH server session succeeded.\n" : \
"SSH client session succeeded.\n" );
return( CRYPT_ERROR_NOTAVAIL );
}
printf( "cryptSetAttribute/AttributeString() failed with error code "
"%d, line %d.\n", status, __LINE__ );
return( FALSE );
}
/* Activate the session. Since we need to be able to process out-of-
band signalling such as channel control messages, we set a non-zero
timeout for reads */
cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_READTIMEOUT, 5 );
status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
if( isServer )
{
if( status == CRYPT_ENVELOPE_RESOURCE )
{
/* The client has tried to authenticate themselves, print the
info */
status = cryptGetAttributeString( cryptSession,
CRYPT_SESSINFO_USERNAME,
stringBuffer, &length );
if( cryptStatusOK( status ) )
{
#ifdef UNICODE_STRINGS
stringBuffer[ length / sizeof( wchar_t ) ] = TEXT( '\0' );
printf( "SVR: User name = '%S', ", stringBuffer );
#else
stringBuffer[ length ] = '\0';
printf( "SVR: User name = '%s', ", stringBuffer );
#endif /* UNICODE_STRINGS */
}
if( cryptStatusOK( status ) )
status = cryptGetAttributeString( cryptSession,
CRYPT_SESSINFO_PASSWORD,
stringBuffer, &length );
if( cryptStatusOK( status ) )
{
#ifdef UNICODE_STRINGS
stringBuffer[ length / sizeof( wchar_t ) ] = TEXT( '\0' );
printf( "password = '%S'.\n", stringBuffer );
#else
stringBuffer[ length ] = '\0';
printf( "password = '%s'.\n", stringBuffer );
#endif /* UNICODE_STRINGS */
}
if( cryptStatusError( status ) )
{
printf( "SVR: Couldn't read client authentication details, "
"status = %d, line %d.\n", status, __LINE__ );
return( FALSE );
}
/* Allow the auth.and complete the handshake */
puts( "SVR: Confirming authentication to client..." );
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_AUTHRESPONSE, TRUE );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptSession,
CRYPT_SESSINFO_ACTIVE, TRUE );
}
/* Now that the handshake is complete, display the connection info */
if( !printConnectInfo( cryptSession ) )
return( FALSE );
}
if( cryptStatusError( status ) )
{
if( testType == SSH_TEST_FINGERPRINT )
{
/* We've forced the connect to fail by using a dummy fingerprint,
everything is OK */
if( isServer )
printf( "SVR: " );
puts( "SSH client rejected key with invalid fingerprint." );
cryptDestroySession( cryptSession );
puts( isServer ? "SVR: SSH server session succeeded.\n" : \
"SSH client session succeeded.\n" );
return( TRUE );
}
printExtError( cryptSession, isServer ? \
"SVR: Attempt to activate SSH server session" : \
"Attempt to activate SSH client session", status,
__LINE__ );
cryptDestroySession( cryptSession );
if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_NOTFOUND )
{
/* These servers are constantly appearing and disappearing so if
we get a straight connect error we don't treat it as a serious
failure */
puts( " (Server could be down, faking it and continuing...)\n" );
return( CRYPT_ERROR_FAILED );
}
if( status == CRYPT_ERROR_WRONGKEY )
{
/* This is another possible soft error condition, the default
username and password shouldn't be able to get into many
machines */
puts( " (Incorrect username/password, continuing...)\n" );
return( TRUE );
}
if( status == CRYPT_ERROR_NOSECURE )
{
/* Another soft error condition, the server can't handle the
security level we want (usually occurs when trying to perform
an SSHv2 connect to an SSHv1 server) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -