📄 ssl_svr.c
字号:
exitMutex( MUTEX_SESSIONCACHE );
return( uniqueID );
}
}
}
/* If the total number of entries has shrunk due to old entries expiring,
reduce the overall cache size */
if( lastUsedEntry + 1 < sessionCacheLastEntry )
sessionCacheLastEntry = lastUsedEntry + 1;
/* No match found, if we're adding a new entry, add it at the
appropriate location */
if( cacheAction == CACHE_ACTION_ADD )
{
if( !dataHashed )
hashData( hashValue, sessionID, sessionIDlength );
cachePos = ( nextFreeEntry != CRYPT_ERROR ) ? nextFreeEntry : \
( sessionCacheLastEntry >= SESSIONCACHE_SIZE ) ? \
oldestEntry : sessionCacheLastEntry++;
sessionCacheIndex[ cachePos ].checkValue = checkValue;
memcpy( sessionCacheIndex[ cachePos ].hashValue, hashValue, 20 );
sessionCacheIndex[ cachePos ].expiryTime = \
currentTime + SESSIONCACHE_TIMEOUT;
sessionCacheIndex[ cachePos ].uniqueID = uniqueID = \
sesionCacheUniqueID++;
sessionCacheIndex[ cachePos ].fixedEntry = isFixedEntry;
memcpy( sessionCacheData[ cachePos ], masterKey, SSL_SECRET_SIZE );
}
exitMutex( MUTEX_SESSIONCACHE );
return( uniqueID );
}
/* Add and delete entries to/from the session cache. These are just wrappers
for the local cache-access function, for use by external code */
int findSessionCacheEntryID( const void *sessionID,
const int sessionIDlength )
{
return( handleSessionCache( sessionID, sessionIDlength, NULL,
FALSE, CACHE_ACTION_PRESENCECHECK ) );
}
static int findSessionCacheEntry( const void *sessionID,
const int sessionIDlength,
void *masterSecret )
{
return( handleSessionCache( sessionID, sessionIDlength, masterSecret,
FALSE, CACHE_ACTION_LOOKUP ) );
}
int addSessionCacheEntry( const void *sessionID, const int sessionIDlength,
const void *masterSecret,
const BOOLEAN isFixedEntry )
{
assert( masterSecret != NULL );
/* If we're not doing resumes (or the ID is suspiciously short), don't
try and update the session cache */
if( sessionIDlength < 8 )
return( 0 );
/* Add the entry to the cache */
return( handleSessionCache( sessionID, sessionIDlength,
( void * ) masterSecret, isFixedEntry,
CACHE_ACTION_ADD ) );
}
void deleteSessionCacheEntry( const int uniqueID )
{
int i;
enterMutex( MUTEX_SESSIONCACHE );
/* Search the cache for the entry with the given ID */
for( i = 0; i < sessionCacheLastEntry; i++ )
{
SESSIONCACHE_INDEX *sessionCacheInfo = &sessionCacheIndex[ i ];
/* If we've found the entry we're after, clear it and exit */
if( sessionCacheInfo->uniqueID == uniqueID )
{
sessionCacheIndex[ i ] = SESSIONCACHE_INDEX_TEMPLATE;
zeroise( sessionCacheData[ i ], sizeof( SESSIONCACHE_DATA ) );
break;
}
}
exitMutex( MUTEX_SESSIONCACHE );
}
/* Initialise and shut down the session cache */
int initSessionCache( void )
{
int i, status;
enterMutex( MUTEX_SESSIONCACHE );
/* Initialise the session cache */
if( ( sessionCacheIndex = clAlloc( "initSessionCache", \
SESSIONCACHE_SIZE * sizeof( SESSIONCACHE_INDEX ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
status = krnlMemalloc( ( void ** ) &sessionCacheData,
SESSIONCACHE_SIZE * sizeof( SESSIONCACHE_DATA ) );
if( cryptStatusError( status ) )
{
clFree( "initSessionCache", sessionCacheIndex );
return( status );
}
for( i = 0; i < SESSIONCACHE_SIZE; i++ )
sessionCacheIndex[ i ] = SESSIONCACHE_INDEX_TEMPLATE;
memset( sessionCacheData, 0, SESSIONCACHE_SIZE * \
sizeof( SESSIONCACHE_DATA ) );
sessionCacheLastEntry = 0;
sesionCacheUniqueID = 1;
exitMutex( MUTEX_SESSIONCACHE );
return( CRYPT_OK );
}
void endSessionCache( void )
{
int i;
enterMutex( MUTEX_SESSIONCACHE );
/* Clear and free the session cache */
krnlMemfree( ( void ** ) &sessionCacheData );
for( i = 0; i < SESSIONCACHE_SIZE; i++ )
sessionCacheIndex[ i ] = SESSIONCACHE_INDEX_TEMPLATE;
clFree( "endSessionCache", sessionCacheIndex );
exitMutex( MUTEX_SESSIONCACHE );
}
/****************************************************************************
* *
* Server-side Connect Functions *
* *
****************************************************************************/
/* Perform the initial part of the handshake with the client */
int beginServerHandshake( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo )
{
RESOURCE_DATA msgData;
BYTE *bufPtr, *lengthPtr;
const void *sessionIDptr, *suitePtr;
int length, suiteLength, sessionIDlength, resumedSessionID = 0, status;
BOOLEAN isV2handshake = FALSE, isExtendedHello = FALSE;
/* Wait for the hello packet from the client */
status = readPacketSSL( sessionInfoPtr, handshakeInfo,
SSL_MSG_SPECIAL_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
/* Process the client hello. Although this should be a v3 hello,
Netscape always sends a v2 hello (even if SSLv2 is disabled) so we
have to process both types. The v2 type and version have already
been processed in readPacketSSL() since this information, which is
moved into the header in v3, is part of the body in v2. What's
left for the v2 hello is the remainder of the payload, however we
need to know the minor version in order to know whether we can use
SSL or TLS, so the header-read code inserts this information at the
start of the SSLv2 data:
SSLv2 SSLv3/TLS
[ byte minorVersion ] byte ID = 1
uint16 suiteLen uint24 len
uint16 sessIDlen byte[2] version = { 0x03, 0x0n }
uint16 nonceLen uint32 time | Client nonce
uint24[] suites byte[28] nonce |
byte[] sessID byte sessIDlen | May receive nonzero len +
byte[] nonce byte[] sessID | <len> bytes data
uint16 suiteLen
uint16[] suites
byte coprLen = 1
byte copr = 0 */
bufPtr = sessionInfoPtr->receiveBuffer;
if( *bufPtr == SSL_HAND_CLIENT_HELLO )
{
/* SSLv3/TLS hello */
length = checkPacketHeader( sessionInfoPtr, &bufPtr,
SSL_HAND_CLIENT_HELLO,
VERSIONINFO_SIZE + SSL_NONCE_SIZE + 1 + \
( UINT16_SIZE * 2 ) + 1 + 1,
SSL_MAJOR_VERSION );
if( cryptStatusError( length ) )
return( length );
handshakeInfo->clientOfferedVersion = *bufPtr++;
status = processVersionInfo( sessionInfoPtr,
handshakeInfo->clientOfferedVersion );
if( cryptStatusError( status ) )
return( status );
memcpy( handshakeInfo->clientNonce, bufPtr, SSL_NONCE_SIZE );
bufPtr += SSL_NONCE_SIZE;
sessionIDlength = *bufPtr++;
sessionIDptr = bufPtr;
if( sessionIDlength < 0 || sessionIDlength > MAX_SESSIONID_SIZE )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid session ID length %d", sessionIDlength );
bufPtr += sessionIDlength;
suiteLength = mgetWord( bufPtr );
if( suiteLength < 2 || ( suiteLength % 2 ) != 0 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid handshake cipher suite length %d",
suiteLength );
length -= VERSIONINFO_SIZE + SSL_NONCE_SIZE + \
1 + sessionIDlength + UINT16_SIZE + suiteLength + 1 + 1;
if( length < 0 )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid header data length %d", length );
suitePtr = bufPtr;
bufPtr += suiteLength;
if( *bufPtr++ != 1 || *bufPtr++ )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid compression suite info 0x%02X",
bufPtr[ -1 ] );
if( length > 0 )
{
int extListLen;
/* There's extra data present in the request which (according to
RFC 3546's rather optimistic assumptions) should be TLS
extension data. Make sure that it's valid:
uint16 extListLen | RFC 3546
byte extType
uint16 extLen
byte[] extData ] */
if( length < UINT16_SIZE + 1 + UINT16_SIZE )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Client hello contains %d bytes extraneous data",
length );
extListLen = mgetWord( bufPtr );
if( length != UINT16_SIZE + extListLen )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid TLS extension length %d, extension list "
"length %d", length, extListLen );
isExtendedHello = TRUE;
status = processExtensions( sessionInfoPtr, bufPtr, extListLen );
if( cryptStatusError( status ) )
return( status );
}
}
else
{
int nonceLength;
/* SSLv2 hello with SSLv3/TLS contents */
assert( *bufPtr & 0x80 );
/* Extract the minor version information that was inserted by the
header-read code. We also need to reset the high bit, which was
set to ensure that the version doesn't get confused with a
standard SSL packet type */
handshakeInfo->clientOfferedVersion = *bufPtr++ & 0x7F;
status = processVersionInfo( sessionInfoPtr,
handshakeInfo->clientOfferedVersion );
if( cryptStatusError( status ) )
return( status );
/* SSLv2 hello from Netscape */
isV2handshake = TRUE;
suiteLength = mgetWord( bufPtr );
sessionIDlength = mgetWord( bufPtr );
nonceLength = mgetWord( bufPtr );
if( suiteLength < 3 || ( suiteLength % 3 ) != 0 || \
sessionIDlength < 0 || sessionIDlength > MAX_SESSIONID_SIZE || \
nonceLength < 16 || nonceLength > SSL_NONCE_SIZE || \
( 3 * UINT16_SIZE ) + suiteLength + sessionIDlength + \
nonceLength > sessionInfoPtr->receiveBufEnd )
retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
"Invalid SSLv2 handshake info, suite length %d, session "
"ID length %d, nonce length %d", suiteLength,
sessionIDlength, nonceLength );
suitePtr = bufPtr;
bufPtr += suiteLength;
sessionIDptr = bufPtr;
bufPtr += sessionIDlength;
memcpy( handshakeInfo->clientNonce + SSL_NONCE_SIZE - nonceLength,
bufPtr, nonceLength );
}
if( sessionIDlength == SESSIONID_SIZE )
{
/* There's a resumed session ID present and it's of the right size to
have come from a cryptlib server, remember it for later */
memcpy( handshakeInfo->sessionID, sessionIDptr, sessionIDlength );
handshakeInfo->sessionIDlength = sessionIDlength;
/* Check whether this session is cached */
resumedSessionID = findSessionCacheEntry( handshakeInfo->sessionID,
handshakeInfo->sessionIDlength,
handshakeInfo->premasterSecret );
}
if( resumedSessionID )
{
/* It's a resumed session, if it's a fixed entry that was added
manually store the session ID as the user name */
if( resumedSessionID < 0 )
{
length = handshakeInfo->sessionIDlength;
memcpy( sessionInfoPtr->userName, handshakeInfo->sessionID,
handshakeInfo->sessionIDlength );
while( length > 0 && !sessionInfoPtr->userName[ length - 1 ] )
length--; /* Strip zero-padding */
sessionInfoPtr->userNameLength = length;
resumedSessionID = -resumedSessionID; /* Fix ID polarity */
}
}
else
{
/* It's a new session or the session data has expired from the cache,
generate a new session ID */
setMessageData( &msgData, handshakeInfo->sessionID, SESSIONID_SIZE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
handshakeInfo->sessionIDlength = SESSIONID_SIZE;
}
handshakeInfo->cipherSuite = chooseCipherSuite( suitePtr,
suiteLength / ( isV2handshake ? 3 : 2 ),
isV2handshake );
if( handshakeInfo->cipherSuite == SSL_NULL_WITH_NULL )
retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
"No crypto algorithm compatible with the remote system "
"could be found" );
status = initCiphersuiteInfo( sessionInfoPtr, handshakeInfo,
handshakeInfo->cipherSuite );
if( cryptStatusError( status ) )
return( status );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -