📄 ssl.c
字号:
sessionInfoPtr->authBlocksize = cipherSuiteInfo[ currentSuiteIndex ].macBlockSize;
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_QUERYCAPABILITY, &queryInfo,
sessionInfoPtr->cryptAlgo );
if( cryptStatusError( status ) )
return( status );
sessionInfoPtr->cryptBlocksize = queryInfo.blockSize;
return( CRYPT_OK );
}
/* Process RFC 3546 TLS extensions:
uint16 extListLen | RFC 3546
uint16 extType
uint16 extLen
byte[] extData */
static int processExtensions( SESSION_INFO *sessionInfoPtr, STREAM *stream,
const int length )
{
int endPos = stell( stream ) + length, extListLen, iterationCount = 0;
/* Read the extension header and make sure that it's valid */
if( length < UINT16_SIZE + UINT16_SIZE + UINT16_SIZE + 1 )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"TLS hello contains %d bytes extraneous data", length ) );
}
extListLen = readUint16( stream );
if( cryptStatusError( extListLen ) || \
extListLen != length - UINT16_SIZE )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS extension data length %d, should be %d",
extListLen, length - UINT16_SIZE ) );
}
/* Process the extensions */
while( stell( stream ) < endPos && \
iterationCount++ < FAILSAFE_ITERATIONS_MED )
{
int type, extLen, value;
/* Get the next extension */
type = readUint16( stream );
extLen = readUint16( stream );
if( cryptStatusError( extLen ) || extLen < 1 )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS extension list item header" ) );
}
/* Process the extension data. The internal structure of some of
these things shows that they were created by ASN.1 people... */
switch( type )
{
case TLS_EXT_SERVER_NAME:
{
int listLen;
/* Response: Send zero-length reply to peer:
uint16 listLen
byte nameType
uint16 nameLen
byte[] name */
listLen = readUint16( stream );
if( cryptStatusError( listLen ) || \
listLen != extLen - UINT16_SIZE || \
listLen < 1 + UINT16_SIZE || \
cryptStatusError( sSkip( stream, listLen ) ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS host name extension" ) );
}
/* Parsing of further SEQUENCE OF SEQUENCE data omitted */
break;
}
case TLS_EXT_MAX_FRAGMENT_LENTH:
{
/* static const int fragmentTbl[] = \
{ 0, 512, 1024, 2048, 4096, 8192, 16384, 16384 }; */
/* Response: If frag-size == 3...5, send same to peer.
Note that we also allow a frag-size value of 5, which
isn't specified in the standard but should probably be
present since it would otherwise result in a missing
value between 4096 and the default of 16384:
byte fragmentLength */
value = sgetc( stream );
if( cryptStatusError( value ) || \
extLen != 1 || value < 1 || value > 5 )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS fragment length extension" ) );
}
/* sessionInfoPtr->maxPacketSize = fragmentTbl[ value ]; */
break;
}
case TLS_EXT_CLIENT_CERTIFICATE_URL:
/* Response: Ignore. This dangerous extension allows a
client to direct a server to grope around in arbitrary
external (and untrusted) URLs trying to locate certs,
provinding a convenient mechanism for bounce attacks
and all manner of similar firewall/trusted-host
subversion problems:
byte chainType
uint16 urlAndHashList
uint16 urlLen
byte[] url
byte hashPresent
byte[20] hash - If hashPresent flag set */
if( extLen < 1 + UINT16_SIZE + \
UINT16_SIZE + MIN_URL_SIZE + 1 || \
cryptStatusError( sSkip( stream, extLen ) ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS client certificate URL "
"extension" ) );
}
break;
case TLS_EXT_TRUSTED_CA_KEYS:
/* Response: Ignore. This allows a client to specify which
CA certs it trusts, and by extension which server certs
it trusts, supposedly to reduce handshake messages in
constrained clients. Since the server usually has only
a single cert signed by a single CA, specifying the CAs
the client trusts doesn't serve much purpose:
uint16 caList
byte idType
... */
if( extLen < UINT16_SIZE + 1 || \
cryptStatusError( sSkip( stream, extLen ) ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS trusted CA extension" ) );
}
break;
case TLS_EXT_TRUNCATED_HMAC:
/* Truncate the HMAC to a nonstandard 80 bits (rather than
the de facto IPsec cargo-cult standard of 96 bits) */
if( extLen != 0 )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS truncated HMAC extension" ) );
}
break;
case TLS_EXT_STATUS_REQUEST:
/* Response: Ignore - another bounce-attack enabler, this
time on both the server and an OCSP responder:
byte statusType
... */
if( extLen < 1 || \
cryptStatusError( sSkip( stream, extLen ) ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS status request extension" ) );
}
break;
case TLS_EXT_USER_MAPPING:
/* Response: Used with a complex RFC 4680 mechanism, ignore
until someone actually asks for it:
byte mappingLength
byte[] mapping */
if( extLen < 1 + 1 || \
cryptStatusError( sSkip( stream, extLen ) ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS user-mapping extension" ) );
}
break;
default:
/* Default: Ignore the extension */
if( cryptStatusError( sSkip( stream, extLen ) ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TLS extension data for extension "
"type %d", type ) );
}
}
}
if( iterationCount >= FAILSAFE_ITERATIONS_MED )
{
retExt( CRYPT_ERROR_OVERFLOW,
( CRYPT_ERROR_OVERFLOW, SESSION_ERRINFO,
"Excessive number (%d) of TLS extensions encountered",
iterationCount ) );
}
return( CRYPT_OK );
}
/* Process a session ID */
static int processSessionID( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
STREAM *stream )
{
BYTE sessionID[ SESSIONID_SIZE + 8 ];
const int sessionIDlength = sgetc( stream );
int status;
/* Get the session ID info and if it's not one of ours, skip it */
if( cryptStatusError( sessionIDlength ) || \
sessionIDlength > MAX_SESSIONID_SIZE )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid session ID length %d, should be 0...%d",
sessionIDlength, MAX_SESSIONID_SIZE ) );
}
if( sessionIDlength != SESSIONID_SIZE )
{
if( sessionIDlength > 0 )
{
status = sSkip( stream, sessionIDlength );
if( cryptStatusError( status ) )
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid session ID" ) );
}
return( CRYPT_OK );
}
/* There's a session ID present, check to make sure that it matches our
expectations. If we're the server the the size is right for it to
(potentially) be one of ours, if we're the client we check to see
whether it matches what we sent */
status = sread( stream, sessionID, SESSIONID_SIZE );
if( cryptStatusError( status ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid session ID" ) );
}
#if 0 /* Old PSK mechanism */
if( !isServer( sessionInfoPtr ) )
{
const ATTRIBUTE_LIST *userNamePtr;
BYTE formattedSessionID[ SESSIONID_SIZE + 8 ];
/* If the returned session ID matches the one that we sent,
it's a resumed session */
if( ( userNamePtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME ) ) == NULL )
{
/* There's no user name present, it can't be a resumed
session */
return( CRYPT_OK );
}
memset( formattedSessionID, 0, SESSIONID_SIZE );
memcpy( formattedSessionID, userNamePtr->value,
min( userNamePtr->valueLength, SESSIONID_SIZE ) );
if( memcmp( formattedSessionID, sessionID, SESSIONID_SIZE ) )
{
/* The user name doesn't match the returned ID, it's not a
resumed session */
return( CRYPT_OK );
}
}
#endif /* 0 */
/* It's a potentially resumed session, remember the details and let the
caller know */
memcpy( handshakeInfo->sessionID, sessionID, SESSIONID_SIZE );
handshakeInfo->sessionIDlength = SESSIONID_SIZE;
return( OK_SPECIAL );
}
/* Process the client/server hello:
byte ID = SSL_HAND_CLIENT_HELLO / SSL_HAND_SERVER_HELLO
uint24 len
byte[2] version = { 0x03, 0x0n }
uint32 time | Client/server nonce
byte[28] nonce |
byte sessIDlen | May receive nonzero len +
byte[] sessID | <len> bytes data
Client Server
uint16 suiteLen -
uint16[] suites uint16 suite
byte coprLen = 1 -
byte copr = 0 byte copr = 0 */
int processHelloSSL( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
STREAM *stream, const BOOLEAN isServer )
{
BOOLEAN potentiallyResumedSession = FALSE;
int endPos, length, suiteLength = 1, status;
/* Check the header and version info */
if( isServer )
{
status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
SSL_HAND_CLIENT_HELLO,
VERSIONINFO_SIZE + SSL_NONCE_SIZE + \
1 + ( UINT16_SIZE * 2 ) + 1 + 1 );
}
else
{
status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
SSL_HAND_SERVER_HELLO,
VERSIONINFO_SIZE + SSL_NONCE_SIZE + \
1 + UINT16_SIZE + 1 );
}
if( cryptStatusError( status ) )
return( status );
endPos = stell( stream ) + length;
status = processVersionInfo( sessionInfoPtr, stream,
isServer ? \
&handshakeInfo->clientOfferedVersion : \
NULL );
if( cryptStatusError( status ) )
return( status );
/* Process the nonce and session ID */
status = sread( stream, isServer ? \
handshakeInfo->clientNonce :
handshakeInfo->serverNonce, SSL_NONCE_SIZE );
if( cryptStatusOK( status ) )
status = processSessionID( sessionInfoPtr, handshakeInfo, stream );
if( status == OK_SPECIAL )
potentiallyResumedSession = TRUE;
else
{
if( cryptStatusError( status ) )
return( status );
}
/* Process the cipher suite information */
if( isServer )
{
/* If we're reading the client hello, the packet contains a
selection of suites preceded by a suite count */
suiteLength = readUint16( stream );
if( cryptStatusError( suiteLength ) || \
suiteLength < UINT16_SIZE || ( suiteLength % UINT16_SIZE ) != 0 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -