📄 ssl_rw.c
字号:
totaLength <= MAX_PACKET_SIZE + sessionInfoPtr->authBlocksize + \
256 );
assert( isWritePtr( bufPtr, totaLength ) );
/* Make sure that the length is a multiple of the block cipher size */
if( sessionInfoPtr->cryptBlocksize > 1 && \
( totaLength % sessionInfoPtr->cryptBlocksize ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid encrypted packet length %d relative to cipher "
"block size %d for packet type %d", totaLength,
sessionInfoPtr->cryptBlocksize, packetType );
/* Decrypt the packet in the buffer. We allow zero-length blocks (once
the padding is stripped) because some versions of OpenSSL send these
as a kludge to work around pre-TLS 1.1 chosen-IV attacks */
length = decryptData( sessionInfoPtr, bufPtr, totaLength );
if( cryptStatusError( length ) )
{
/* If there's a padding error, don't exit immediately but record
that there was a problem for after we've done the MAC'ing.
Delaying the error reporting until then helps prevent timing
attacks of the kind described by Brice Canvel, Alain Hiltgen,
Serge Vaudenay, and Martin Vuagnoux in "Password Interception
in a SSL/TLS Channel", Crypto'03, LNCS No.2729, p.583. These
are close to impossible in most cases because we delay sending
the close notify over a much longer period than the MAC vs.non-
MAC time difference and because it requires repeatedly connecting
with a fixed-format secret such as a password at the same location
in the packet (which MS Outlook does however manage to do), but
we take this step anyway just to be safe */
if( length == CRYPT_ERROR_BADDATA )
{
badDecrypt = TRUE;
length = totaLength;
}
else
return( length );
}
length -= sessionInfoPtr->authBlocksize;
if( length < 0 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid packet payload length %d for packet type %d",
length, packetType );
/* MAC the decrypted data */
if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
status = macDataSSL( sessionInfoPtr, bufPtr, length, packetType,
TRUE, badDecrypt );
else
status = macDataTLS( sessionInfoPtr, bufPtr, length, packetType,
TRUE, badDecrypt );
if( badDecrypt )
/* Report the delayed decrypt error, held to this point to make
timing attacks more difficult */
return( CRYPT_ERROR_BADDATA );
if( cryptStatusError( status ) )
return( status );
return( length );
}
/* Read an SSL packet. This function is only used during the handshake
phase (the data transfer phase has its own read/write code) so we can
perform some special-case handling based on this */
int readPacketSSL( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo, const int packetType )
{
STREAM stream;
BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
sessionInfoPtr->receiveBufEnd;
int length, status;
/* Read and process the header. We don't have to check for status == 0
(meaning no data was read) at this point since all reads during the
handshake phase are blocking reads */
status = length = readFixedHeader( sessionInfoPtr,
sessionInfoPtr->receiveBufStartOfs );
if( status <= 0 )
return( status );
assert( status == sessionInfoPtr->receiveBufStartOfs );
/* Check for an SSL alert message */
if( bufPtr[ 0 ] == SSL_MSG_ALERT )
return( processAlert( sessionInfoPtr, bufPtr, length ) );
/* Decode and process the SSL packet header */
if( packetType == SSL_MSG_FIRST_HANDSHAKE && \
bufPtr[ 0 ] == SSL_MSG_V2HANDSHAKE )
/* It's an SSLv2 handshake, handle it specially */
return( handleSSLv2Header( sessionInfoPtr, handshakeInfo, bufPtr ) );
sMemConnect( &stream, bufPtr, length );
status = length = \
checkPacketHeader( sessionInfoPtr, &stream, packetType,
( packetType == SSL_MSG_CHANGE_CIPHER_SPEC ) ? \
1 : MIN_PACKET_SIZE );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* Read the payload packet(s) */
status = sread( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer,
length );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
if( status < length )
/* If we timed out during the handshake phase, treat it as a hard
timeout error */
retExt( sessionInfoPtr, CRYPT_ERROR_TIMEOUT,
"Timed out reading packet data for packet type %d, only "
"got %d of %d bytes", packetType, status, length );
sessionInfoPtr->receiveBufPos = 0;
sessionInfoPtr->receiveBufEnd = length;
if( handshakeInfo != NULL )
{
sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
dualMacData( handshakeInfo, &stream, TRUE );
sMemDisconnect( &stream );
}
return( length );
}
/* Read the next handshake stream packet */
int refreshHSStream( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
STREAM *stream = &handshakeInfo->stream;
int length;
/* If there's still data present in the stream, there's nothing left
to do */
if( sMemDataLeft( stream ) > 0 )
return( CRYPT_OK );
/* Refill the stream */
sMemDisconnect( stream );
length = readPacketSSL( sessionInfoPtr, handshakeInfo,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( length ) )
return( length );
assert( length > 0 );
sMemConnect( stream, sessionInfoPtr->receiveBuffer, length );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Write Packet Utility Functions *
* *
****************************************************************************/
/* Open and complete an SSL packet */
static void openPacketStream( STREAM *stream, const SESSION_INFO *sessionInfoPtr,
const int bufferSize, const BOOLEAN isNewStream,
const int packetType )
{
SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isNewStream || stell( stream ) >= SSL_HEADER_SIZE );
assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
/* Create the stream if necessary */
if( isNewStream )
{
const int streamSize = ( bufferSize == CRYPT_USE_DEFAULT ) ? \
sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE : \
bufferSize + sessionInfoPtr->sendBufStartOfs;
assert( isWritePtr( sessionInfoPtr->sendBuffer, streamSize ) );
assert( streamSize >= sessionInfoPtr->sendBufStartOfs );
sMemOpen( stream, sessionInfoPtr->sendBuffer, streamSize );
}
/* Write the packet header:
byte ID = packetType
byte[2] version = { 0x03, 0x0n }
uint16 len = 0 (placeholder)
[ byte[] iv - TLS 1.1 only ] */
sputc( stream, packetType );
sputc( stream, SSL_MAJOR_VERSION );
sputc( stream, sessionInfoPtr->version );
writeUint16( stream, 0 ); /* Placeholder */
if( ( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE ) && \
sslInfo->ivSize > 0 )
{
RESOURCE_DATA msgData;
BYTE iv[ CRYPT_MAX_IVSIZE ];
setMessageData( &msgData, iv, sslInfo->ivSize );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
swrite( stream, iv, sslInfo->ivSize );
}
}
void openPacketStreamSSL( STREAM *stream, const SESSION_INFO *sessionInfoPtr,
const int bufferSize, const int packetType )
{
openPacketStream( stream, sessionInfoPtr, bufferSize, TRUE,
packetType );
}
int continuePacketStreamSSL( STREAM *stream,
const SESSION_INFO *sessionInfoPtr,
const int packetType )
{
const int offset = stell( stream );
openPacketStream( stream, sessionInfoPtr, CRYPT_USE_DEFAULT, FALSE,
packetType );
return( offset );
}
int completePacketStreamSSL( STREAM *stream, const int offset )
{
const int packetEndOffset = stell( stream );
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Update the length field at the start of the packet */
sseek( stream, offset + ID_SIZE + VERSIONINFO_SIZE );
status = writeUint16( stream, ( packetEndOffset - offset ) - \
SSL_HEADER_SIZE );
sseek( stream, packetEndOffset );
return( status );
}
/* Start and complete a handshake packet within an SSL packet. Since this
continues an existing packet stream that's been opened using
openPacketStreamSSL(), it's denoted as continueXXX() rather than
openXXX() */
int continueHSPacketStream( STREAM *stream, const int packetType )
{
const int offset = stell( stream );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Write the handshake packet header:
byte ID = packetType
uint24 len = 0 (placeholder) */
sputc( stream, packetType );
writeUint24( stream, 0 );
return( offset );
}
int completeHSPacketStream( STREAM *stream, const int offset )
{
const int packetEndOffset = stell( stream );
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( offset >= SSL_HEADER_SIZE );
/* Update the length field at the start of the packet */
sseek( stream, offset + ID_SIZE );
status = writeUint24( stream, packetEndOffset - \
( offset + ID_SIZE + LENGTH_SIZE ) );
sseek( stream, packetEndOffset );
return( status );
}
/****************************************************************************
* *
* Write/wrap a Packet *
* *
****************************************************************************/
/* Wrap an SSL data packet:
------ MAC'd
================== Encrypted
[ hdr | IV | data | MAC | pad ]
| +------+
| |
buffer length
This MACs the data, adds the IV if necessary, pads and encrypts, and
updates the header */
int wrapPacketSSL( SESSION_INFO *sessionInfoPtr, STREAM *stream,
const int offset )
{
SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
const int payloadLength = ( stell( stream ) - \
sessionInfoPtr->sendBufStartOfs ) - offset;
BYTE *bufPtr = sMemBufPtr( stream ) - payloadLength;
BYTE *headerPtr = bufPtr - ( SSL_HEADER_SIZE + sslInfo->ivSize );
int length;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE );
assert( payloadLength >= 0 && payloadLength <= MAX_PACKET_SIZE );
assert( isWritePtr( bufPtr, payloadLength ) );
assert( *headerPtr >= SSL_MSG_FIRST && *headerPtr <= SSL_MSG_LAST );
/* Safety check to make sure that the stream is OK */
if( !sStatusOK( stream ) )
{
assert( NOTREACHED );
return( sGetStatus( stream ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -