📄 ssl_cry.c
字号:
int loadExplicitIV( SESSION_INFO *sessionInfoPtr, STREAM *stream )
{
RESOURCE_DATA msgData;
BYTE iv[ CRYPT_MAX_IVSIZE + 8 ];
int status;
/* Read and load the IV */
status = sread( stream, iv, sessionInfoPtr->cryptBlocksize );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, iv, sessionInfoPtr->cryptBlocksize );
status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
}
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status, "Packet IV read/load failed" );
/* The following alternate code, which decrypts and discards the first
block, can be used when we can't reload an IV during decryption */
#if 0
status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
IMESSAGE_CTX_DECRYPT, iv,
sessionInfoPtr->cryptBlocksize );
#endif /* 0 */
return( CRYPT_OK );
}
/****************************************************************************
* *
* Encrypt/Decrypt Functions *
* *
****************************************************************************/
/* Encrypt/decrypt a data block */
int encryptData( const SESSION_INFO *sessionInfoPtr, BYTE *data,
const int dataLength )
{
int length = dataLength, status;
assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength > 0 && dataLength <= MAX_PACKET_SIZE + 20 );
assert( isWritePtr( data, dataLength ) );
/* If it's a block cipher, we need to add end-of-block padding */
if( sessionInfoPtr->cryptBlocksize > 1 )
{
BYTE *dataPadPtr = data + dataLength;
const int padSize = ( sessionInfoPtr->cryptBlocksize - 1 ) - \
( dataLength & ( sessionInfoPtr->cryptBlocksize - 1 ) );
int i;
/* Add the PKCS #5-style padding (PKCS #5 uses n, TLS uses n-1) */
for( i = 0; i < padSize + 1; i++ )
*dataPadPtr++ = padSize;
length += padSize + 1;
}
status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
IMESSAGE_CTX_ENCRYPT, data, length );
return( cryptStatusError( status ) ? status : length );
}
int decryptData( SESSION_INFO *sessionInfoPtr, BYTE *data,
const int dataLength )
{
int length = dataLength, status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength > 0 && dataLength <= sessionInfoPtr->receiveBufEnd );
assert( isWritePtr( data, dataLength ) );
/* Decrypt the data */
status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
IMESSAGE_CTX_DECRYPT, data, length );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Packet decryption failed" );
/* If it's a block cipher, we need to remove end-of-block padding. Up
until TLS 1.1 the spec was silent about any requirement to check the
padding (and for SSLv3 it didn't specify the padding format at all)
so it's not really safe to reject an SSL message if we don't find the
correct padding because many SSL implementations didn't process the
padded space in any way, leaving it containing whatever was there
before (which can include old plaintext (!!)). Almost all TLS
implementations get it right (even though in TLS 1.0 there was only a
requirement to generate, but not to check, the PKCS #5-style padding).
Because of this we only check the padding bytes if we're talking
TLS */
if( sessionInfoPtr->cryptBlocksize > 1 )
{
const int padSize = data[ dataLength - 1 ];
/* Make sure that the padding info looks OK. TLS allows up to 256
bytes of padding (only GnuTLS actually seems to use this
capability though) so we can't check for a sensible (small)
padding length, however we can check this for SSL, which is good
because for that we can't check the padding itself */
if( padSize < 0 || \
( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL && \
padSize > sessionInfoPtr->cryptBlocksize - 1 ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid encryption padding value 0x%02X", padSize );
length -= padSize + 1;
if( length < 0 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Encryption padding adjustment value %d is greater "
"than packet length %d", padSize, dataLength );
/* Check for PKCS #5-type padding (PKCS #5 uses n, TLS uses n-1) if
necessary */
if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
{
int i;
for( i = 0; i < padSize; i++ )
if( data[ length + i ] != padSize )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid encryption padding byte 0x%02X at "
"position %d, should be 0x%02X",
data[ length + i ], length + i, padSize );
}
}
return( length );
}
/****************************************************************************
* *
* MAC Data Functions *
* *
****************************************************************************/
/* Perform a MAC or dual MAC of a data block. We have to provide special-
case handling of zero-length blocks since some versions of OpenSSL send
these as a kludge in SSL/TLS 1.0 to work around chosen-IV attacks */
int macDataSSL( SESSION_INFO *sessionInfoPtr, const void *data,
const int dataLength, const int type, const BOOLEAN isRead,
const BOOLEAN noReportError )
{
SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
RESOURCE_DATA msgData;
STREAM stream;
BYTE buffer[ 128 ];
const CRYPT_CONTEXT iHashContext = isRead ? \
sessionInfoPtr->iAuthInContext : sessionInfoPtr->iAuthOutContext;
const void *macSecret = isRead ? sslInfo->macReadSecret : \
sslInfo->macWriteSecret;
const long seqNo = isRead ? sslInfo->readSeqNo++ : sslInfo->writeSeqNo++;
const int padSize = \
( sessionInfoPtr->integrityAlgo == CRYPT_ALGO_MD5 ) ? 48 : 40;
int length, status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
assert( dataLength == 0 || isReadPtr( data, dataLength ) );
/* Set up the sequence number and length data */
memset( buffer, PROTOHMAC_PAD1_VALUE, padSize );
sMemOpen( &stream, buffer + padSize, 128 - padSize );
writeUint64( &stream, seqNo );
sputc( &stream, type );
writeUint16( &stream, dataLength );
length = stell( &stream );
sMemDisconnect( &stream );
/* Reset the hash context and generate the inner portion of the MAC:
hash( MAC_secret || pad1 || seq_num || type || length || data ) */
krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) macSecret,
sessionInfoPtr->authBlocksize );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
padSize + length );
if( dataLength > 0 )
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
return( status );
/* Extract the inner hash value */
memset( buffer, PROTOHMAC_PAD2_VALUE, padSize );
setMessageData( &msgData, buffer + padSize, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusError( status ) )
return( status );
/* Generate the outer portion of the handshake message's MAC:
hash( MAC_secret || pad2 || inner_hash ) */
krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) macSecret,
sessionInfoPtr->authBlocksize );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer,
padSize + msgData.length );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
return( status );
/* If it's a read, compare the calculated MAC to the MAC present at the
end of the data */
if( isRead )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, ( BYTE * ) data + dataLength,
sessionInfoPtr->authBlocksize );
status = krnlSendMessage( iHashContext, IMESSAGE_COMPARE,
&msgData, MESSAGE_COMPARE_HASH );
if( cryptStatusError( status ) )
{
/* If the error message has already been set at a higher level,
don't update the error info */
if( noReportError )
return( CRYPT_ERROR_SIGNATURE );
retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
"Bad message MAC for packet type %d, length %d",
type, dataLength );
}
return( CRYPT_OK );
}
/* Set the MAC value at the end of the packet */
setMessageData( &msgData, ( BYTE * ) data + dataLength,
sessionInfoPtr->authBlocksize );
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
return( cryptStatusOK( status ) ? dataLength + msgData.length : status );
}
int macDataTLS( SESSION_INFO *sessionInfoPtr, const void *data,
const int dataLength, const int type, const BOOLEAN isRead,
const BOOLEAN noReportError )
{
SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
RESOURCE_DATA msgData;
STREAM stream;
BYTE buffer[ 64 ];
const CRYPT_CONTEXT iHashContext = isRead ? \
sessionInfoPtr->iAuthInContext : sessionInfoPtr->iAuthOutContext;
const long seqNo = isRead ? sslInfo->readSeqNo++ : sslInfo->writeSeqNo++;
int length, status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
assert( dataLength == 0 || isReadPtr( data, dataLength ) );
/* Set up the sequence number, type, version, and length data */
sMemOpen( &stream, buffer, 64 );
writeUint64( &stream, seqNo );
sputc( &stream, type );
sputc( &stream, SSL_MAJOR_VERSION );
sputc( &stream, sessionInfoPtr->version );
writeUint16( &stream, dataLength );
length = stell( &stream );
sMemDisconnect( &stream );
/* Reset the hash context and generate the MAC:
HMAC( seq_num || type || version || length || data ) */
krnlSendMessage( iHashContext, IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CTXINFO_HASHVALUE );
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer, length );
if( dataLength > 0 )
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
return( status );
/* If it's a read, compare the calculated MAC to the MAC present at the
end of the data */
if( isRead )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, ( BYTE * ) data + dataLength,
sessionInfoPtr->authBlocksize );
status = krnlSendMessage( iHashContext, IMESSAGE_COMPARE,
&msgData, MESSAGE_COMPARE_HASH );
if( cryptStatusError( status ) )
{
/* If the error message has already been set at a higher level,
don't update the error info */
if( noReportError )
return( CRYPT_ERROR_SIGNATURE );
retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
"Bad message MAC for packet type %d, length %d",
type, dataLength );
}
return( CRYPT_OK );
}
/* Set the MAC value at the end of the packet */
setMessageData( &msgData, ( BYTE * ) data + dataLength,
sessionInfoPtr->authBlocksize );
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
return( cryptStatusOK( status ) ? dataLength + msgData.length : status );
}
int dualMacData( const SSL_HANDSHAKE_INFO *handshakeInfo,
const STREAM *stream, const BOOLEAN isRawData )
{
const int dataLength = isRawData ? sMemDataLeft( stream ) : \
stell( stream ) - SSL_HEADER_SIZE;
const void *data = isRawData ? sMemBufPtr( stream ) : \
sMemBufPtr( stream ) - dataLength;
int status;
assert( dataLength > 0 );
status = krnlSendMessage( handshakeInfo->clientMD5context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
if( cryptStatusOK( status ) )
status = krnlSendMessage( handshakeInfo->clientSHA1context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
if( cryptStatusOK( status ) )
status = krnlSendMessage( handshakeInfo->serverMD5context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
if( cryptStatusOK( status ) )
status = krnlSendMessage( handshakeInfo->serverSHA1context,
IMESSAGE_CTX_HASH, ( void * ) data,
dataLength );
return( status );
}
/* Complete the dual MD5/SHA1 hash/MAC used in the finished message */
int completeSSLDualMAC( const CRYPT_CONTEXT md5context,
const CRYPT_CONTEXT sha1context, BYTE *hashValues,
const char *label, const BYTE *masterSecret )
{
RESOURCE_DATA msgData;
int status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -