📄 ssl_rw.c
字号:
/****************************************************************************
* *
* cryptlib SSL v3/TLS Session Read/Write Routines *
* Copyright Peter Gutmann 1998-2004 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "misc_rw.h"
#include "session.h"
#include "ssl.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../misc/misc_rw.h"
#include "session.h"
#include "ssl.h"
#else
#include "crypt.h"
#include "misc/misc_rw.h"
#include "session/session.h"
#include "session/ssl.h"
#endif /* Compiler-specific includes */
#ifdef USE_SSL
/****************************************************************************
* *
* Legacy SSLv2 Functions *
* *
****************************************************************************/
/* Handle a legacy SSLv2 client hello:
uint16 length code = { 0x80, len }
byte type = SSL_HAND_CLIENT_HELLO
byte[2] vers = { 0x03, 0x0n } */
static int handleSSLv2Header( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
const BYTE *bufPtr )
{
STREAM stream;
int length, value, status;
assert( bufPtr[ 0 ] == SSL_MSG_V2HANDSHAKE );
/* Make sure that the length is in order. Beyond the header we need at
least the three 16-bit field lengths, one 24-bit cipher suite, and at
least 16 bytes of nonce */
bufPtr++; /* Skip SSLv2 length ID, already checked by caller */
length = *bufPtr++;
if( length < ID_SIZE + VERSIONINFO_SIZE + \
( UINT16_SIZE * 3 ) + 3 + 16 || \
length > sessionInfoPtr->receiveBufSize )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid legacy SSLv2 hello packet length %d", length );
/* Due to the different ordering of header fields in SSLv2, the type and
version is regarded as part of the payload that needs to be
hashed, rather than the header as for SSLv3 */
sMemConnect( &stream, bufPtr, ID_SIZE + VERSIONINFO_SIZE );
dualMacData( handshakeInfo, &stream, TRUE );
value = sgetc( &stream );
if( value != SSL_HAND_CLIENT_HELLO )
{
sMemDisconnect( &stream );
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Unexpected legacy SSLv2 packet type %d, should be %d",
value, SSL_HAND_CLIENT_HELLO );
}
status = processVersionInfo( sessionInfoPtr, &stream,
&handshakeInfo->clientOfferedVersion );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
length -= stell( &stream );
sMemDisconnect( &stream );
/* Read the packet payload */
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,
"Timeout during legacy SSLv2 hello packet read, only got "
"%d of %d bytes", status, length );
sessionInfoPtr->receiveBufPos = 0;
sessionInfoPtr->receiveBufEnd = length;
sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
dualMacData( handshakeInfo, &stream, TRUE );
sMemDisconnect( &stream );
/* SSLv2 puts the version info in the header, so we set the SSLv2 flag
in the handshake info to ensure that it doesn't get confused with a
normal SSL packet type */
handshakeInfo->isSSLv2 = TRUE;
return( length );
}
/****************************************************************************
* *
* Read Packet Utility Functions *
* *
****************************************************************************/
/* Process version information */
int processVersionInfo( SESSION_INFO *sessionInfoPtr, STREAM *stream,
int *clientVersion )
{
int version;
/* Clear return value */
if( clientVersion != NULL )
*clientVersion = CRYPT_ERROR;
/* Check the major version number */
version = sgetc( stream );
if( version != SSL_MAJOR_VERSION )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid major version number %d, should be 3", version );
/* Check the minor version number. If we've already got the version
established, make sure that it matches the existing one, otherwise
determine which version we'll be using */
version = sgetc( stream );
if( clientVersion == NULL )
{
if( version != sessionInfoPtr->version )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid version number 3.%d, should be 3.%d",
version, sessionInfoPtr->version );
return( CRYPT_OK );
}
switch( version )
{
case SSL_MINOR_VERSION_SSL:
/* If the other side can't do TLS, fall back to SSL */
if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
sessionInfoPtr->version = SSL_MINOR_VERSION_SSL;
break;
case SSL_MINOR_VERSION_TLS:
/* If the other side can't do TLS 1.1, fall back to TLS 1.0 */
if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS11 )
sessionInfoPtr->version = SSL_MINOR_VERSION_TLS;
break;
case SSL_MINOR_VERSION_TLS11:
/* If the other side can't do post-TLS 1.1, fall back to
TLS 1.1 */
if( sessionInfoPtr->version > SSL_MINOR_VERSION_TLS11 )
sessionInfoPtr->version = SSL_MINOR_VERSION_TLS11;
break;
default:
/* If we're the server and the client has offered a vaguely
sensible version, fall back to the highest version that we
support */
if( ( sessionInfoPtr->flags && SESSION_ISSERVER ) && \
version <= 5 )
{
sessionInfoPtr->version = SSL_MINOR_VERSION_TLS11;
break;
}
/* It's nothing that we can handle */
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid protocol version 3.%d", version );
}
*clientVersion = version;
return( CRYPT_OK );
}
/* Check that the header of an SSL packet is in order:
byte type
byte[2] vers = { 0x03, 0x0n }
uint16 length
[ byte[] iv - TLS 1.1 ]
If this is the initial hello packet we request a dummy version info read
since the peer's version isn't known yet at this point. The actual
version info is taken from the hello packet data, not from the SSL
wrapper */
static int checkPacketHeader( SESSION_INFO *sessionInfoPtr, STREAM *stream,
const int packetType, const int minLength )
{
SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
const int expectedPacketType = \
( packetType == SSL_MSG_FIRST_HANDSHAKE ) ? \
SSL_MSG_HANDSHAKE : packetType;
int value, status;
/* Check the packet type */
value = sgetc( stream );
if( value != expectedPacketType )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Unexpected packet type %d, expected %d",
value, expectedPacketType );
status = processVersionInfo( sessionInfoPtr, stream,
( packetType == SSL_MSG_FIRST_HANDSHAKE ) ? &value : NULL );
if( cryptStatusError( status ) )
return( status );
/* Check the packet length */
value = readUint16( stream );
if( sessionInfoPtr->flags & SESSION_ISSECURE_READ )
{
if( value < sslInfo->ivSize + minLength + \
sessionInfoPtr->authBlocksize || \
value > sslInfo->ivSize + MAX_PACKET_SIZE + \
sessionInfoPtr->authBlocksize + 256 || \
value > sessionInfoPtr->receiveBufSize )
status = CRYPT_ERROR_BADDATA;
}
else
if( value < minLength || value > MAX_PACKET_SIZE || \
value > sessionInfoPtr->receiveBufSize )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid packet length %d for packet type %d",
value, packetType );
/* Load the TLS 1.1 explicit IV if necessary */
if( ( sessionInfoPtr->flags & SESSION_ISSECURE_READ ) && \
sslInfo->ivSize > 0 )
{
const int offset = stell( stream );
status = loadExplicitIV( sessionInfoPtr, stream );
value -= stell( stream ) - offset;
}
return( value );
}
/* Check that the header of an SSL packet and SSL handshake packet is in
order */
int checkPacketHeaderSSL( SESSION_INFO *sessionInfoPtr, STREAM *stream )
{
return( checkPacketHeader( sessionInfoPtr, stream,
SSL_MSG_APPLICATION_DATA, 0 ) );
}
int checkHSPacketHeader( SESSION_INFO *sessionInfoPtr, STREAM *stream,
const int packetType, const int minSize )
{
int type, length;
/* byte ID = type
uint24 length */
type = sgetc( stream );
if( type != packetType )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid handshake packet type %d, expected %d",
type, packetType );
length = readUint24( stream );
if( length < minSize || length > MAX_PACKET_SIZE || \
length > sMemDataLeft( stream ) )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid length %d for handshake packet type %d",
length, type );
return( length );
}
/****************************************************************************
* *
* Read/Unwrap a Packet *
* *
****************************************************************************/
/* Unwrap an SSL data packet:
------ MAC'd
================== Encrypted
[ hdr | IV | data | MAC | pad ]
+------------------+
| |
buffer length
This decrypts and removes the padding, checks and removes the MAC, and
returns the payload length. Processing of the header and IV have already
been performed during the packet header read */
int unwrapPacketSSL( SESSION_INFO *sessionInfoPtr, STREAM *stream,
const int packetType )
{
const int totaLength = sMemDataLeft( stream );
BYTE *bufPtr = sMemBufPtr( stream );
BOOLEAN badDecrypt = FALSE;
int length, status;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( sessionInfoPtr->flags & SESSION_ISSECURE_READ );
assert( stell( stream ) == 0 );
assert( totaLength >= sessionInfoPtr->authBlocksize && \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -