📄 ssl.c
字号:
/* 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 */
resetSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME );
resetSessionInfo( 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 = isServer( sessionInfoPtr ) ? \
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 = \
findSessionInfo( 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( !isServer( sessionInfoPtr ) )
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( status,
( status, SESSION_ERRINFO,
"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 )
{
SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
STREAM stream;
int packetLength, status;
/* Clear return value */
*readInfo = READINFO_NONE;
/* Read the SSL packet header data */
status = readFixedHeader( sessionInfoPtr, sslInfo->headerBuffer,
sessionInfoPtr->receiveBufStartOfs );
if( cryptStatusError( status ) )
{
/* OK_SPECIAL means that we got a soft timeout before the entire
header was read */
return( ( status == OK_SPECIAL ) ? 0 : status );
}
/* 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( sslInfo->headerBuffer[ 0 ] == SSL_MSG_ALERT )
return( processAlert( sessionInfoPtr, sslInfo->headerBuffer,
sessionInfoPtr->receiveBufStartOfs ) );
/* Process the header data */
sMemConnect( &stream, sslInfo->headerBuffer,
sessionInfoPtr->receiveBufStartOfs );
status = checkPacketHeaderSSL( sessionInfoPtr, &stream, &packetLength );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
/* Determine how much data we'll be expecting */
sessionInfoPtr->pendingPacketLength = \
sessionInfoPtr->pendingPacketRemaining = packetLength;
/* Indicate that we got the header */
*readInfo = READINFO_NOOP;
return( OK_SPECIAL );
}
static int processBodyFunction( SESSION_INFO *sessionInfoPtr,
READSTATE_INFO *readInfo )
{
int length, status;
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 */
status = unwrapPacketSSL( sessionInfoPtr,
sessionInfoPtr->receiveBuffer + \
sessionInfoPtr->receiveBufPos,
sessionInfoPtr->pendingPacketLength,
&length, SSL_MSG_APPLICATION_DATA );
if( cryptStatusError( status ) )
return( status );
/* 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 */
status = openPacketStreamSSL( &stream, sessionInfoPtr, 0,
SSL_MSG_APPLICATION_DATA );
if( cryptStatusError( status ) )
return( status );
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://", 8, /* 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,
/* In theory we need neither a private key nor a password
because the caller can provide the password during the
handshake in response to a CRYPT_ENVELOPE_RESOURCE
notification, however this facility is likely to be
barely-used in comparison to users forgetting to add server
certs and the like, so we require some sort of server-side
key set in advance */
SSL_MINOR_VERSION_TLS, /* TLS 1.0 */
SSL_MINOR_VERSION_SSL, SSL_MINOR_VERSION_TLS12,
/* We default to TLS 1.0 rather than TLS 1.1 or 1.2 because it's
likely that support for the latter will be hit-and-miss for
some time */
/* 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 pointer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -