📄 ssl.c
字号:
if( cryptStatusError( status ) || !isInitiator )
return( status );
return( readHandshakeCompletionData( sessionInfoPtr, responderHashes ) );
}
/****************************************************************************
* *
* Init/Shutdown Functions *
* *
****************************************************************************/
/* Close a previously-opened SSL session */
static void shutdownFunction( SESSION_INFO *sessionInfoPtr )
{
sendCloseAlert( sessionInfoPtr, FALSE );
sNetDisconnect( &sessionInfoPtr->stream );
}
/* Connect to an SSL server/client */
static int abortStartup( SESSION_INFO *sessionInfoPtr,
SSL_HANDSHAKE_INFO *handshakeInfo,
const BOOLEAN cleanupSecurityContexts,
const int status )
{
sendHandshakeFailAlert( sessionInfoPtr );
if( cleanupSecurityContexts )
destroySecurityContextsSSL( sessionInfoPtr );
if( handshakeInfo != NULL )
destroyHandshakeInfo( handshakeInfo );
sNetDisconnect( &sessionInfoPtr->stream );
return( status );
}
static int commonStartup( SESSION_INFO *sessionInfoPtr,
const BOOLEAN isServer )
{
SSL_HANDSHAKE_INFO handshakeInfo;
BOOLEAN resumedSession = FALSE;
int status;
/* Initialise the handshake info and begin the handshake */
status = initHandshakeInfo( sessionInfoPtr, &handshakeInfo, isServer );
if( cryptStatusOK( status ) )
status = handshakeInfo.beginHandshake( sessionInfoPtr,
&handshakeInfo );
if( status == OK_SPECIAL )
resumedSession = TRUE;
else
if( cryptStatusError( status ) )
return( abortStartup( sessionInfoPtr, &handshakeInfo, FALSE,
status ) );
/* Exchange keys with the server */
if( !resumedSession )
{
status = handshakeInfo.exchangeKeys( sessionInfoPtr,
&handshakeInfo );
if( cryptStatusError( status ) )
return( abortStartup( sessionInfoPtr, &handshakeInfo, TRUE,
status ) );
}
/* Complete the handshake */
status = completeHandshake( sessionInfoPtr, &handshakeInfo, !isServer,
resumedSession );
destroyHandshakeInfo( &handshakeInfo );
if( cryptStatusError( status ) )
return( abortStartup( sessionInfoPtr, NULL, TRUE, status ) );
return( CRYPT_OK );
}
static int clientStartup( SESSION_INFO *sessionInfoPtr )
{
/* Complete the handshake using the common client/server code */
return( commonStartup( sessionInfoPtr, FALSE ) );
}
static int serverStartup( SESSION_INFO *sessionInfoPtr )
{
#if 0 /* Old PSK mechanism */
/* Clear any user name/password information that may be present from
a previous session or from the manual addition of keys to the session
cache */
resetSessionAttribute( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME );
resetSessionAttribute( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_PASSWORD );
#endif /* 0 */
/* Complete the handshake using the common client/server code */
return( commonStartup( sessionInfoPtr, TRUE ) );
}
/****************************************************************************
* *
* Control Information Management Functions *
* *
****************************************************************************/
static int getAttributeFunction( SESSION_INFO *sessionInfoPtr,
void *data, const CRYPT_ATTRIBUTE_TYPE type )
{
CRYPT_CERTIFICATE *certPtr = ( CRYPT_CERTIFICATE * ) data;
CRYPT_CERTIFICATE iCryptCert = \
( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
sessionInfoPtr->iKeyexAuthContext : sessionInfoPtr->iKeyexCryptContext;
assert( type == CRYPT_SESSINFO_RESPONSE );
/* If we didn't get a client/server cert there's nothing to return */
if( iCryptCert == CRYPT_ERROR )
return( CRYPT_ERROR_NOTFOUND );
/* Return the information to the caller */
krnlSendNotifier( iCryptCert, IMESSAGE_INCREFCOUNT );
*certPtr = iCryptCert;
return( CRYPT_OK );
}
#if 0 /* Old PSK mechanism */
static int setAttributeFunction( SESSION_INFO *sessionInfoPtr,
const void *data,
const CRYPT_ATTRIBUTE_TYPE type )
{
const ATTRIBUTE_LIST *userNamePtr = \
findSessionAttribute( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME );
BYTE premasterSecret[ ( UINT16_SIZE + CRYPT_MAX_TEXTSIZE ) * 2 + 8 ];
BYTE sessionID[ SESSIONID_SIZE + 8 ];
int uniqueID, premasterSecretLength, status;
assert( type == CRYPT_SESSINFO_USERNAME || \
type == CRYPT_SESSINFO_PASSWORD );
/* At the moment only the server maintains a true session cache, so if
it's a client session we return without any further checking, there
can never be a duplicate entry in this case */
if( !( sessionInfoPtr->flags & SESSION_ISSERVER ) )
return( CRYPT_OK );
/* If we're setting the password, we have to have a session ID present to
set it for */
if( type == CRYPT_SESSINFO_PASSWORD && userNamePtr == NULL )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_USERNAME,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Wait for any async network driver binding to complete. This is
required because the session cache is initialised as part of the
asynchronous startup (since it's tied to the session object class
rather than a particular session object), so we have to wait until
this has completed before we can access it */
krnlWaitSemaphore( SEMAPHORE_DRIVERBIND );
/* Format the session ID in the appropriate manner and check whether it's
present in the cache */
memset( sessionID, 0, SESSIONID_SIZE );
memcpy( sessionID, userNamePtr->value,
min( userNamePtr->valueLength, SESSIONID_SIZE ) );
uniqueID = findSessionCacheEntryID( sessionID, SESSIONID_SIZE );
/* If we're adding or deleting a user name, check whether something
identified by the name is present in the cache */
if( type == CRYPT_SESSINFO_USERNAME )
{
if( data != NULL )
{
/* User name add, presence is an error */
if( uniqueID )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_USERNAME,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( CRYPT_ERROR_INITED );
}
}
else
{
/* User name delete, absence is an error */
if( !uniqueID )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_USERNAME,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
deleteSessionCacheEntry( uniqueID );
}
return( CRYPT_OK );
}
/* Create the premaster secret from the user-supplied password */
status = createSharedPremasterSecret( premasterSecret,
&premasterSecretLength,
sessionInfoPtr );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't create SSL master secret from shared "
"secret/password value" );
/* Add the entry to the session cache */
addSessionCacheEntry( sessionID, SESSIONID_SIZE, premasterSecret,
premasterSecretLength, TRUE );
zeroise( premasterSecret, SSL_SECRET_SIZE );
return( CRYPT_OK );
}
#endif /* 0 */
/****************************************************************************
* *
* Get/Put Data Functions *
* *
****************************************************************************/
/* Read/write data over the SSL link */
static int readHeaderFunction( SESSION_INFO *sessionInfoPtr,
READSTATE_INFO *readInfo )
{
STREAM stream;
const BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
sessionInfoPtr->receiveBufEnd;
int length, status;
/* Clear return value */
*readInfo = READINFO_NONE;
/* Read the SSL packet header data */
status = length = readFixedHeader( sessionInfoPtr,
sessionInfoPtr->receiveBufStartOfs );
if( status <= 0 )
return( status );
assert( status == sessionInfoPtr->receiveBufStartOfs );
/* Since data errors are always fatal, we make all errors fatal until
we've finished handling the header */
*readInfo = READINFO_FATAL;
/* Check for an SSL alert message */
if( bufPtr[ 0 ] == SSL_MSG_ALERT )
{
*readInfo = READINFO_FATAL;
return( processAlert( sessionInfoPtr, bufPtr, length ) );
}
/* Process the header data */
sMemConnect( &stream, bufPtr, length );
status = length = checkPacketHeaderSSL( sessionInfoPtr, &stream );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
/* Determine how much data we'll be expecting */
sessionInfoPtr->pendingPacketLength = \
sessionInfoPtr->pendingPacketRemaining = length;
/* Indicate that we got the header */
*readInfo = READINFO_NOOP;
return( OK_SPECIAL );
}
static int processBodyFunction( SESSION_INFO *sessionInfoPtr,
READSTATE_INFO *readInfo )
{
STREAM stream;
int length;
assert( sessionInfoPtr->pendingPacketLength > 0 );
assert( sessionInfoPtr->receiveBufPos + \
sessionInfoPtr->pendingPacketLength <= \
sessionInfoPtr->receiveBufEnd );
assert( sessionInfoPtr->receiveBufEnd <= sessionInfoPtr->receiveBufSize );
/* All errors processing the payload are fatal */
*readInfo = READINFO_FATAL;
/* Unwrap the payload */
sMemConnect( &stream, sessionInfoPtr->receiveBuffer + \
sessionInfoPtr->receiveBufPos,
sessionInfoPtr->pendingPacketLength );
length = unwrapPacketSSL( sessionInfoPtr, &stream,
SSL_MSG_APPLICATION_DATA );
sMemDisconnect( &stream );
if( cryptStatusError( length ) )
return( length );
/* Adjust the data size indicators to account for the stripped padding
and MAC info */
sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos + length;
sessionInfoPtr->receiveBufPos = sessionInfoPtr->receiveBufEnd;
sessionInfoPtr->pendingPacketLength = 0;
assert( sessionInfoPtr->receiveBufEnd <= sessionInfoPtr->receiveBufSize );
/* If we only got a partial packet, let the caller know that they should
try again */
if( length < 1 )
{
*readInfo = READINFO_PARTIAL;
return( OK_SPECIAL );
}
*readInfo = READINFO_NONE;
return( length );
}
static int preparePacketFunction( SESSION_INFO *sessionInfoPtr )
{
STREAM stream;
int status;
assert( sessionInfoPtr->sendBufPos - \
sessionInfoPtr->sendBufStartOfs > 0 && \
sessionInfoPtr->sendBufPos - \
sessionInfoPtr->sendBufStartOfs <= MAX_PACKET_SIZE );
assert( !( sessionInfoPtr->flags & SESSION_SENDCLOSED ) );
assert( !( sessionInfoPtr->protocolFlags & SSL_PFLAG_ALERTSENT ) );
/* Wrap up the payload ready for sending. Since this is wrapping in-
place data we first open a write stream to add the header, then open
a read stream covering the full buffer in preparation for wrapping
the packet. Note that we connect the stream to the full send buffer
(bufSize) even though we only advance the current stream position to
the end of the stream contents (bufPos), since the packet-wrapping
process adds further data to the stream that exceeds the current
stream position */
openPacketStreamSSL( &stream, sessionInfoPtr, 0,
SSL_MSG_APPLICATION_DATA );
sMemDisconnect( &stream );
sMemConnect( &stream, sessionInfoPtr->sendBuffer,
sessionInfoPtr->sendBufSize );
sSkip( &stream, sessionInfoPtr->sendBufPos );
status = wrapPacketSSL( sessionInfoPtr, &stream, 0 );
if( cryptStatusOK( status ) )
status = stell( &stream );
sMemDisconnect( &stream );
return( status );
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
int setAccessMethodSSL( SESSION_INFO *sessionInfoPtr )
{
static const ALTPROTOCOL_INFO altProtocolInfo = {
/* SSL tunnelled via an HTTP proxy. This is a special case in that
the initial connection is made using HTTP, but subsequent
communications are via a direct TCP/IP connection that goes
through the proxy */
STREAM_PROTOCOL_TCPIP, /* Alt.protocol type */
"https://", /* Alt.protocol URI type */
80, /* Alt.protocol port */
0, /* Protocol flags to replace */
SESSION_USEHTTPTUNNEL /* Alt.protocol flags */
};
static const PROTOCOL_INFO protocolInfo = {
/* General session information */
FALSE, /* Request-response protocol */
SESSION_NONE, /* Flags */
SSL_PORT, /* SSL port */
SESSION_NEEDS_PRIVKEYSIGN, /* Client attributes */
/* The client private key is optional but if present, it has to
be signature-capable */
SESSION_NEEDS_PRIVATEKEY | /* Server attributes */
SESSION_NEEDS_PRIVKEYCRYPT | \
SESSION_NEEDS_PRIVKEYCERT | \
SESSION_NEEDS_KEYORPASSWORD,
SSL_MINOR_VERSION_TLS, /* TLS 1.0 */
SSL_MINOR_VERSION_SSL, SSL_MINOR_VERSION_TLS11,
/* We default to TLS 1.0 rather than TLS 1.1 because it's likely
that support for the latter will be hit-and-miss for some
time */
NULL, NULL, /* Content-type */
/* Protocol-specific information */
EXTRA_PACKET_SIZE + \
MAX_PACKET_SIZE, /* Send/receive buffer size */
SSL_HEADER_SIZE, /* Payload data start */
/* This may be adjusted during the handshake if we're talking
TLS 1.1, which prepends extra data in the form of an IV to
the payload */
MAX_PACKET_SIZE, /* (Default) maximum packet size */
&altProtocolInfo /* Alt.transport protocol */
};
/* Set the access method pointers */
sessionInfoPtr->protocolInfo = &protocolInfo;
sessionInfoPtr->shutdownFunction = shutdownFunction;
sessionInfoPtr->transactFunction = \
( sessionInfoPtr->flags & SESSION_ISSERVER ) ? \
serverStartup : clientStartup;
sessionInfoPtr->getAttributeFunction = getAttributeFunction;
sessionInfoPtr->readHeaderFunction = readHeaderFunction;
sessionInfoPtr->processBodyFunction = processBodyFunction;
sessionInfoPtr->preparePacketFunction = preparePacketFunction;
return( CRYPT_OK );
}
#endif /* USE_SSL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -