📄 ssh2_cry.c
字号:
if( cryptStatusOK( status ) )
status = loadCryptovariable( isClient ? \
sessionInfoPtr->iCryptOutContext : \
sessionInfoPtr->iCryptInContext,
CRYPT_CTXINFO_KEY, keySize,
hashFunction, initialHashInfo, "C",
handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
if( cryptStatusOK( status ) )
status = loadCryptovariable( isClient ? \
sessionInfoPtr->iCryptInContext : \
sessionInfoPtr->iCryptOutContext,
CRYPT_CTXINFO_KEY, keySize,
hashFunction, initialHashInfo, "D",
handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
if( cryptStatusOK( status ) )
status = loadCryptovariable( isClient ? \
sessionInfoPtr->iAuthOutContext : \
sessionInfoPtr->iAuthInContext,
CRYPT_CTXINFO_KEY,
( sessionInfoPtr->protocolFlags & \
SSH_PFLAG_HMACKEYSIZE ) ? \
SSH2_FIXED_KEY_SIZE : \
sessionInfoPtr->authBlocksize,
hashFunction, initialHashInfo, "E",
handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
if( cryptStatusOK( status ) )
status = loadCryptovariable( isClient ? \
sessionInfoPtr->iAuthInContext : \
sessionInfoPtr->iAuthOutContext,
CRYPT_CTXINFO_KEY,
( sessionInfoPtr->protocolFlags & \
SSH_PFLAG_HMACKEYSIZE ) ? \
SSH2_FIXED_KEY_SIZE : \
sessionInfoPtr->authBlocksize,
hashFunction, initialHashInfo, "F",
handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
return( status );
}
/****************************************************************************
* *
* Hash/MAC Data *
* *
****************************************************************************/
/* Hash a value encoded as an SSH string and as an MPI */
int hashAsString( const CRYPT_CONTEXT iHashContext,
const BYTE *data, const int dataLength )
{
BYTE buffer[ 128 ], *bufPtr = buffer;
int status;
/* Prepend the string length to the data and hash it. If it'll fit into
the buffer we copy it over to save a kernel call */
mputLong( bufPtr, dataLength );
if( dataLength <= 128 - LENGTH_SIZE )
{
memcpy( buffer + LENGTH_SIZE, data, dataLength );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
LENGTH_SIZE + dataLength );
}
else
{
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
LENGTH_SIZE );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
( void * ) data, dataLength );
}
zeroise( buffer, 128 );
return( status );
}
int hashAsMPI( const CRYPT_CONTEXT iHashContext, const BYTE *data,
const int dataLength )
{
BYTE buffer[ 8 ], *bufPtr = buffer;
const int length = ( data[ 0 ] & 0x80 ) ? dataLength + 1 : dataLength;
int headerLength = LENGTH_SIZE;
/* Prepend the MPI length to the data and hash it. Since this is often
sensitive data, we don't take a local copy but hash it in two parts */
mputLong( bufPtr, length );
if( data[ 0 ] & 0x80 )
{
/* MPIs are signed values */
*bufPtr++ = 0;
headerLength++;
}
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer, headerLength );
return( krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
( void * ) data, dataLength ) );
}
/* MAC the payload of a data packet. Since we may not have the whole packet
available at once, we can do this in one go or incrementally */
int macPayload( const CRYPT_CONTEXT iMacContext, const long seqNo,
const BYTE *data, const int dataLength,
const int packetDataLength, const MAC_TYPE macType,
const int macLength, const BOOLEAN isRead )
{
int status;
/* MAC the data and either compare the result to the stored MAC or
append the MAC value to the data:
HMAC( seqNo || length || payload )
During the handshake process we have the entire packet at hand
(dataLength == packetDataLength) and can process it at once. When
we're processing payload data (dataLength a subset of
packetDataLength) we have to process the header separately in order
to determine how much more we have to read, so we have to MAC the
packet in two parts */
if( macType == MAC_START || macType == MAC_ALL )
{
BYTE buffer[ 16 ], *bufPtr = buffer;
int length = ( macType == MAC_ALL ) ? dataLength : packetDataLength;
assert( ( macType == MAC_ALL && packetDataLength == 0 ) || \
( macType == MAC_START && packetDataLength >= dataLength ) );
/* Since the payload had the length stripped during the speculative
read if we're MAC'ing read data, we have to reconstruct it and
hash it separately before we hash the data. If we're doing the
hash in parts, the amount of data being hashed won't match the
overall length so the caller needs to supply the overall packet
length as well as the current data length */
mputLong( bufPtr, seqNo );
mputLong( bufPtr, length );
krnlSendMessage( iMacContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, buffer,
UINT32_SIZE + LENGTH_SIZE );
}
if( dataLength > 0 )
status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH,
( void * ) data, dataLength );
if( macType == MAC_END || macType == MAC_ALL )
{
RESOURCE_DATA msgData;
status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
return( status );
setMessageData( &msgData, ( BYTE * ) data + dataLength, macLength );
if( isRead )
/* It's a read, compare the MAC value to the stored MAC
value */
status = krnlSendMessage( iMacContext, IMESSAGE_COMPARE,
&msgData, MESSAGE_COMPARE_HASH );
else
/* It's a write, append the MAC value to the data */
status = krnlSendMessage( iMacContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
return( status );
}
/****************************************************************************
* *
* Miscellaneous Functions *
* *
****************************************************************************/
/* Complete the DH key agreement */
int completeKeyex( SESSION_INFO *sessionInfoPtr,
SSH_HANDSHAKE_INFO *handshakeInfo,
const BOOLEAN isServer )
{
KEYAGREE_PARAMS keyAgreeParams;
RESOURCE_DATA msgData;
STREAM stream;
int status;
/* Read the other side's key agreement information. Note that the size
check has already been performed at a higher level when the overall
key agreement value was read, this is a secondary check of the MPI
payload */
memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
if( isServer )
sMemConnect( &stream, handshakeInfo->clientKeyexValue,
handshakeInfo->clientKeyexValueLength );
else
sMemConnect( &stream, handshakeInfo->serverKeyexValue,
handshakeInfo->serverKeyexValueLength );
status = readInteger32( &stream, keyAgreeParams.publicValue,
&keyAgreeParams.publicValueLen,
bitsToBytes( MIN_PKCSIZE_BITS ),
CRYPT_MAX_PKCSIZE );
sMemDisconnect( &stream );
if( cryptStatusOK( status ) && \
!isValidDHsize( keyAgreeParams.publicValueLen,
handshakeInfo->serverKeySize, 0 ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid DH phase 1 MPI" );
/* Perform phase 2 of the DH key agreement */
status = krnlSendMessage( handshakeInfo->iServerCryptContext,
IMESSAGE_CTX_DECRYPT, &keyAgreeParams,
sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusOK( status ) )
{
memcpy( handshakeInfo->secretValue, keyAgreeParams.wrappedKey,
keyAgreeParams.wrappedKeyLen );
handshakeInfo->secretValueLength = keyAgreeParams.wrappedKeyLen;
}
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusError( status ) )
return( status );
/* If we're using ephemeral DH, hash the requested keyex key length(s)
and DH p and g values. Since this has been deferred until long after
the keyex negotiation took place, we have to recreate the original
encoded values here */
if( handshakeInfo->requestedServerKeySize > 0 )
{
BYTE keyexBuffer[ 128 + ( CRYPT_MAX_PKCSIZE * 2 ) ];
const int extraLength = LENGTH_SIZE + sizeofString32( "ssh-dh", 6 );
krnlSendMessage( handshakeInfo->iExchangeHashcontext,
IMESSAGE_CTX_HASH,
handshakeInfo->encodedReqKeySizes,
handshakeInfo->encodedReqKeySizesLength );
setMessageData( &msgData, keyexBuffer,
128 + ( CRYPT_MAX_PKCSIZE * 2 ) );
status = krnlSendMessage( handshakeInfo->iServerCryptContext,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEY_SSH2 );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( handshakeInfo->iExchangeHashcontext,
IMESSAGE_CTX_HASH, keyexBuffer + extraLength,
msgData.length - extraLength );
}
/* Hash the client and server DH values and shared secret */
krnlSendMessage( handshakeInfo->iExchangeHashcontext, IMESSAGE_CTX_HASH,
handshakeInfo->clientKeyexValue,
handshakeInfo->clientKeyexValueLength );
krnlSendMessage( handshakeInfo->iExchangeHashcontext, IMESSAGE_CTX_HASH,
handshakeInfo->serverKeyexValue,
handshakeInfo->serverKeyexValueLength );
status = hashAsMPI( handshakeInfo->iExchangeHashcontext,
handshakeInfo->secretValue,
handshakeInfo->secretValueLength );
if( cryptStatusError( status ) )
return( status );
/* Complete the hashing to obtain the exchange hash and then hash *that*
to get the hash that the server signs and sends to the client. The
overall hashed data for the exchange hash is:
string V_C, client version string (CR and NL excluded)
string V_S, server version string (CR and NL excluded)
string I_C, client hello
string I_S, server hello
string K_S, the host key
[[ uint32 min, min.preferred keyex key size for ephemeral DH ]]
[ uint32 n, preferred keyex key size for ephemeral DH ]
[[ uint32 max, max.preferred keyex key size for ephemeral DH ]]
[ mpint p, DH p for ephemeral DH ]
[ mpint g, DH g for ephemeral DH ]
mpint e, client DH keyex value
mpint f, server DH keyex value
mpint K, the shared secret
The client and server version string ahd hellos and the host key were
hashed inline during the handshake. The optional parameters are for
negotiated DH values (see the conditional-hashing code above). The
double-optional parameters are for the revised version of the DH
negotiation mechanism, the original only had n, the revised version
allowed a { min, n, max } range */
krnlSendMessage( handshakeInfo->iExchangeHashcontext, IMESSAGE_CTX_HASH,
"", 0 );
setMessageData( &msgData, handshakeInfo->sessionID, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( handshakeInfo->iExchangeHashcontext,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusError( status ) )
return( status );
handshakeInfo->sessionIDlength = msgData.length;
krnlSendMessage( handshakeInfo->iExchangeHashcontext,
IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( handshakeInfo->iExchangeHashcontext,
IMESSAGE_CTX_HASH, handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
return( krnlSendMessage( handshakeInfo->iExchangeHashcontext,
IMESSAGE_CTX_HASH, "", 0 ) );
}
#endif /* USE_SSH2 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -