📄 ssh2_svr.c
字号:
/* Exchange keys with the client */
static int exchangeServerKeys( SESSION_INFO *sessionInfoPtr,
SSH_HANDSHAKE_INFO *handshakeInfo )
{
KEYAGREE_PARAMS keyAgreeParams;
RESOURCE_DATA msgData;
BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
int length, length2, sigLength, status;
/* Create the server DH value */
memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
status = krnlSendMessage( handshakeInfo->iServerCryptContext,
IMESSAGE_CTX_ENCRYPT, &keyAgreeParams,
sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusError( status ) )
return( status );
/* Build 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
...
The specification also makes provision for using X.509 and PGP keys,
but only so far as to say that keys and signatures are in "X.509 DER"
and "PGP" formats, neither of which actually explain what it is
that's sent or signed (and no-one on the SSH list can agree on what
they're supposed to look like), so we can't use either of them */
bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
*bufPtr++ = handshakeInfo->requestedServerKeySize ? \
SSH2_MSG_KEXDH_GEX_REPLY : SSH2_MSG_KEXDH_REPLY;
setMessageData( &msgData, bufPtr, 128 + ( CRYPT_MAX_PKCSIZE * 4 ) );
status = krnlSendMessage( sessionInfoPtr->privateKey,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEY_SSH2 );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( handshakeInfo->iExchangeHashcontext, IMESSAGE_CTX_HASH,
bufPtr, msgData.length );
bufPtr += msgData.length;
handshakeInfo->serverKeyexValueLength = \
encodeMPI( handshakeInfo->serverKeyexValue,
keyAgreeParams.publicValue,
keyAgreeParams.publicValueLen );
memcpy( bufPtr, handshakeInfo->serverKeyexValue,
handshakeInfo->serverKeyexValueLength );
bufPtr += handshakeInfo->serverKeyexValueLength;
/* Complete phase 2 of the DH key agreement process to obtain the shared
secret value */
status = completeKeyex( sessionInfoPtr, handshakeInfo, TRUE );
if( cryptStatusError( status ) )
return( status );
/* Sign the hash */
status = iCryptCreateSignatureEx( bufPtr, &sigLength,
min( sessionInfoPtr->sendBufSize - \
( ( bufPtr - sessionInfoPtr->sendBuffer ) + 128 ),
DEFAULT_PACKET_SIZE ),
CRYPT_IFORMAT_SSH, sessionInfoPtr->privateKey,
handshakeInfo->iExchangeHashcontext,
CRYPT_UNUSED, CRYPT_UNUSED );
krnlSendNotifier( handshakeInfo->iExchangeHashcontext,
IMESSAGE_DECREFCOUNT );
handshakeInfo->iExchangeHashcontext = CRYPT_ERROR;
if( cryptStatusError( status ) )
return( status );
bufPtr += sigLength;
status = length = wrapPacket( sessionInfoPtr, sessionInfoPtr->sendBuffer,
bufPtr - ( sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE ) );
if( cryptStatusError( status ) )
return( status );
/* Build our change cipherspec message and send the whole mess through
to the client:
...
byte type = SSH2_MSG_NEWKEYS */
bufPtr = sessionInfoPtr->sendBuffer + length;
bufPtr[ SSH2_HEADER_SIZE ] = SSH2_MSG_NEWKEYS;
status = length2 = wrapPacket( sessionInfoPtr, bufPtr, ID_SIZE );
if( !cryptStatusError( status ) )
status = sendPacketSSH2( sessionInfoPtr, length + length2, TRUE );
return( status );
}
/* Complete the handshake with the client */
static int completeServerHandshake( SESSION_INFO *sessionInfoPtr,
SSH_HANDSHAKE_INFO *handshakeInfo )
{
BYTE *bufPtr;
int length, stringLength, status;
/* Set up the security information required for the session */
status = initSecurityInfo( sessionInfoPtr, handshakeInfo );
if( cryptStatusError( status ) )
return( status );
/* Wait for the client's change cipherspec message */
status = readPacketSSH2( sessionInfoPtr, SSH2_MSG_NEWKEYS );
if( cryptStatusError( status ) )
return( status );
/* We've sent the change cipherspec message, from now on all data is
encrypted and MAC'ed */
sessionInfoPtr->flags |= SESSION_ISSECURE;
/* Wait for the client's authentication packets. For some reason SSHv2
requires the use of two authentication messages, an "I'm about to
authenticate" packet and an "I'm authenticating" packet. First we
handle the "I'm about to authenticate":
byte type = SSH2_MSG_SERVICE_REQUEST
string service_name = "ssh-userauth"
byte type = SSH2_MSG_SERVICE_ACCEPT
string service_name = "ssh-userauth" */
length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_SERVICE_REQUEST );
if( cryptStatusError( length ) )
return( length );
bufPtr = sessionInfoPtr->receiveBuffer + ID_SIZE;
stringLength = ( int ) mgetLong( bufPtr );
if( length != ID_SIZE + LENGTH_SIZE + stringLength || \
stringLength != 12 || memcmp( bufPtr, "ssh-userauth", 12 ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid service request packet length %d, string length "
"%d", length, stringLength );
bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
*bufPtr++ = SSH2_MSG_SERVICE_ACCEPT;
length = encodeString( bufPtr, "ssh-userauth", 0 );
status = sendPacketSSH2( sessionInfoPtr, ID_SIZE + length, FALSE );
if( cryptStatusError( status ) )
return( status );
/* Wait for the second part of the authentication:
byte type = SSH2_MSG_USERAUTH_REQUEST
string user_name
string service_name = "ssh-connection"
string method_name = "none" | "password"
[ boolean FALSE ]
[ string password ]
The client can send a method-type of "none" to indicate that it'd
like the server to return a list of allowed authentication types, if
we get a packet of this kind we return our allowed types list. Unlike
SSHv1, SSHv2 properly identifies public keys, however because of its
complexity (several more states added to the state machine because of
SSHv2's propensity for carrying out any negotiation it performs in
little bits and pieces) we don't support this form of authentication
until someone specifically requests it */
while( cryptStatusOK( status ) )
{
length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_USERAUTH_REQUEST );
if( cryptStatusError( length ) )
return( length );
bufPtr = sessionInfoPtr->receiveBuffer + ID_SIZE;
stringLength = ( int ) mgetLong( bufPtr );
if( length < ID_SIZE + ( LENGTH_SIZE + stringLength ) + \
( LENGTH_SIZE + 14 ) + ( LENGTH_SIZE + 4 ) || \
stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid user auth packet length %d, string length %d",
length, stringLength );
memcpy( sessionInfoPtr->userName, bufPtr, stringLength );
sessionInfoPtr->userNameLength = stringLength;
bufPtr += stringLength;
length -= ID_SIZE + ( LENGTH_SIZE + stringLength );
stringLength = ( int ) mgetLong( bufPtr );
if( stringLength != 14 || memcmp( bufPtr, "ssh-connection", 14 ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid user auth service string length %d",
stringLength );
bufPtr += stringLength;
length -= ( LENGTH_SIZE + stringLength );
stringLength = ( int ) mgetLong( bufPtr );
if( length < LENGTH_SIZE + stringLength )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid user auth method length %d, string length %d",
length, stringLength );
/* If the client wants a list of supported authentication mechanisms,
tell them what we allow and await further input:
byte type = SSH2_MSG_USERAUTH_FAILURE
string allowed_authent
boolean partial_success = FALSE */
if( stringLength == 4 && !memcmp( bufPtr, "none", 4 ) )
{
bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
*bufPtr++ = SSH2_MSG_USERAUTH_FAILURE;
length = encodeString( bufPtr, algoStringUserauthentList, 0 );
bufPtr[ length ] = 0;
status = sendPacketSSH2( sessionInfoPtr, ID_SIZE + length + \
BOOLEAN_SIZE, FALSE );
continue;
}
/* The only other permitted type is password authentication */
if( stringLength != 8 || memcmp( bufPtr, "password", 8 ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid user auth method name, string length %d",
stringLength );
break;
}
if( cryptStatusError( status ) )
return( status );
/* We got authentication info, save it for the caller to check */
bufPtr += stringLength + BOOLEAN_SIZE;
length -= LENGTH_SIZE + stringLength + BOOLEAN_SIZE;
stringLength = ( int ) mgetLong( bufPtr );
if( length != LENGTH_SIZE + stringLength || \
stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid user auth payload length %d, string length %d",
length, stringLength );
memcpy( sessionInfoPtr->password, bufPtr, stringLength );
sessionInfoPtr->passwordLength = stringLength;
/* Acknowledge the authentication:
byte type = SSH2_MSG_USERAUTH_SUCCESS */
bufPtr = sessionInfoPtr->sendBuffer + SSH2_HEADER_SIZE;
*bufPtr = SSH2_MSG_USERAUTH_SUCCESS;
status = sendPacketSSH2( sessionInfoPtr, ID_SIZE, FALSE );
if( cryptStatusError( status ) )
return( status );
/* Handle the channel open */
length = readPacketSSH2( sessionInfoPtr, SSH2_MSG_CHANNEL_OPEN );
if( cryptStatusError( length ) )
return( length );
status = processChannelOpen( sessionInfoPtr,
sessionInfoPtr->receiveBuffer + ID_SIZE,
length - ID_SIZE );
if( cryptStatusError( status ) )
return( status );
/* Process any further junk that the caller may throw at us until we get
a request that we can handle */
while( !cryptStatusError( status = length = \
readPacketSSH2( sessionInfoPtr, SSH2_MSG_SPECIAL_REQUEST ) ) )
{
status = processRequest( sessionInfoPtr,
sessionInfoPtr->receiveBuffer + ID_SIZE,
length - ID_SIZE );
if( cryptStatusError( status ) )
return( ( status == OK_SPECIAL ) ? CRYPT_OK : status );
}
return( status );
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
void initSSH2serverProcessing( SESSION_INFO *sessionInfoPtr,
SSH_HANDSHAKE_INFO *handshakeInfo )
{
handshakeInfo->beginHandshake = beginServerHandshake;
handshakeInfo->exchangeKeys = exchangeServerKeys;
handshakeInfo->completeHandshake = completeServerHandshake;
}
#endif /* SSH2 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -