📄 session.c
字号:
/****************************************************************************
* *
* cryptlib Session Support Routines *
* Copyright Peter Gutmann 1998-2005 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "session.h"
#else
#include "crypt.h"
#include "session/session.h"
#endif /* Compiler-specific includes */
#ifdef USE_SESSIONS
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Initialise network connection information based on the contents of the
session object */
void initSessionNetConnectInfo( const SESSION_INFO *sessionInfoPtr,
NET_CONNECT_INFO *connectInfo )
{
const ATTRIBUTE_LIST *attributeListPtr;
initNetConnectInfo( connectInfo, sessionInfoPtr->ownerHandle,
sessionInfoPtr->readTimeout, sessionInfoPtr->connectTimeout,
( sessionInfoPtr->transportSession != CRYPT_ERROR ) ? \
NET_OPTION_TRANSPORTSESSION : \
( sessionInfoPtr->networkSocket != CRYPT_ERROR ) ? \
NET_OPTION_NETWORKSOCKET : \
( sessionInfoPtr->flags & SESSION_USEHTTPTUNNEL ) ? \
NET_OPTION_HOSTNAME_TUNNEL : \
NET_OPTION_HOSTNAME );
/* If there's an explicit server name set, connect to it if we're the
client or bind to the named interface if we're the server */
if( ( attributeListPtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_SERVER_NAME ) ) != NULL )
{
connectInfo->name = attributeListPtr->value;
connectInfo->nameLength = attributeListPtr->valueLength;
}
/* If there's an explicit port set, connect/bind to it, otherwise use the
default port for the protocol */
if( ( attributeListPtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_SERVER_PORT ) ) != NULL )
connectInfo->port = attributeListPtr->intValue;
else
connectInfo->port = sessionInfoPtr->protocolInfo->port;
/* Set the user-supplied transport session or socket if required */
connectInfo->iCryptSession = sessionInfoPtr->transportSession;
connectInfo->networkSocket = sessionInfoPtr->networkSocket;
}
/* Make sure that mutually exclusive session attributes haven't been set.
The checks performed are:
CRYPT_SESSINFO_REQUEST -> !CRYPT_SESSINFO_REQUEST,
!CRYPT_SESSINFO_PRIVATEKEY,
!CRYPT_SESSINFO_CMP_PRIVKEYSET
CRYPT_SESSINFO_PRIVATEKEY -> !CRYPT_SESSINFO_PRIVATEKEY,
!CRYPT_SESSINFO_CMP_PRIVKEYSET
CRYPT_SESSINFO_CACERTIFICATE-> !CRYPT_SESSINFO_CACERTIFICATE,
!CRYPT_SESSINFO_SERVER_FINGERPRINT
CRYPT_SESSINFO_SERVER_FINGERPRINT
-> !CRYPT_SESSINFO_SERVER_FINGERPRINT,
!CRYPT_SESSINFO_CACERTIFICATE */
#define CHECK_ATTR_NONE 0x00
#define CHECK_ATTR_REQUEST 0x01
#define CHECK_ATTR_PRIVKEY 0x02
#define CHECK_ATTR_PRIVKEYSET 0x04
#define CHECK_ATTR_CACERT 0x08
#define CHECK_ATTR_FINGERPRINT 0x10
typedef struct {
const CRYPT_ATTRIBUTE_TYPE attribute;
const int flags;
} EXCLUDED_ATTRIBUTE_INFO;
BOOLEAN checkAttributesConsistent( SESSION_INFO *sessionInfoPtr,
const CRYPT_ATTRIBUTE_TYPE attribute )
{
static const EXCLUDED_ATTRIBUTE_INFO excludedAttrInfo[] = {
{ CRYPT_SESSINFO_REQUEST,
CHECK_ATTR_REQUEST | CHECK_ATTR_PRIVKEY | CHECK_ATTR_PRIVKEYSET },
{ CRYPT_SESSINFO_PRIVATEKEY,
CHECK_ATTR_PRIVKEY | CHECK_ATTR_PRIVKEYSET },
{ CRYPT_SESSINFO_CACERTIFICATE,
CHECK_ATTR_CACERT | CHECK_ATTR_FINGERPRINT },
{ CRYPT_SESSINFO_SERVER_FINGERPRINT,
CHECK_ATTR_FINGERPRINT | CHECK_ATTR_CACERT },
{ CRYPT_ATTRIBUTE_NONE, CHECK_ATTR_NONE },
{ CRYPT_ATTRIBUTE_NONE, CHECK_ATTR_NONE }
};
int flags = 0, i;
assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
assert( attribute == CRYPT_SESSINFO_REQUEST || \
attribute == CRYPT_SESSINFO_PRIVATEKEY || \
attribute == CRYPT_SESSINFO_CACERTIFICATE || \
attribute == CRYPT_SESSINFO_SERVER_FINGERPRINT );
/* Find the excluded-attribute info for this attribute */
for( i = 0; excludedAttrInfo[ i ].attribute != CRYPT_ATTRIBUTE_NONE && \
i < FAILSAFE_ARRAYSIZE( excludedAttrInfo, EXCLUDED_ATTRIBUTE_INFO );
i++ )
{
if( excludedAttrInfo[ i ].attribute == attribute )
{
flags = excludedAttrInfo[ i ].flags;
break;
}
}
if( i >= FAILSAFE_ARRAYSIZE( excludedAttrInfo, EXCLUDED_ATTRIBUTE_INFO ) )
retIntError();
/* Make sure that none of the excluded attributes are present */
if( ( flags & CHECK_ATTR_REQUEST ) && \
sessionInfoPtr->iCertRequest != CRYPT_ERROR )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_REQUEST,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( FALSE );
}
if( ( flags & CHECK_ATTR_PRIVKEYSET ) && \
sessionInfoPtr->privKeyset != CRYPT_ERROR )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_CMP_PRIVKEYSET,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( FALSE );
}
if( ( flags & CHECK_ATTR_CACERT ) && \
sessionInfoPtr->iAuthInContext != CRYPT_ERROR )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_CACERTIFICATE,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( FALSE );
}
if( ( flags & CHECK_ATTR_FINGERPRINT ) && \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_SERVER_FINGERPRINT ) != NULL )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_SERVER_FINGERPRINT,
CRYPT_ERRTYPE_ATTR_PRESENT );
return( FALSE );
}
return( TRUE );
}
/****************************************************************************
* *
* Session Activation Functions *
* *
****************************************************************************/
/* Check client/server-specific required values */
static CRYPT_ATTRIBUTE_TYPE checkClientParameters( const SESSION_INFO *sessionInfoPtr )
{
/* Make sure that the network comms parameters are present */
if( sessionInfoPtr->transportSession == CRYPT_ERROR && \
sessionInfoPtr->networkSocket == CRYPT_ERROR && \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_SERVER_NAME ) == NULL )
return( CRYPT_SESSINFO_SERVER_NAME );
/* Make sure that the username + password and/or user private key are
present if required */
if( ( sessionInfoPtr->clientReqAttrFlags & SESSION_NEEDS_USERID ) && \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME ) == NULL )
return( CRYPT_SESSINFO_USERNAME );
if( ( sessionInfoPtr->clientReqAttrFlags & SESSION_NEEDS_PASSWORD ) && \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_PASSWORD ) == NULL )
{
/* There's no password present, see if we can use a private key as
an alternative */
if( !( sessionInfoPtr->clientReqAttrFlags & \
SESSION_NEEDS_KEYORPASSWORD ) || \
sessionInfoPtr->privateKey == CRYPT_ERROR )
return( CRYPT_SESSINFO_PASSWORD );
}
if( ( sessionInfoPtr->clientReqAttrFlags & SESSION_NEEDS_PRIVATEKEY ) && \
sessionInfoPtr->privateKey == CRYPT_ERROR )
{
/* There's no private key present, see if we can use a password as
an alternative */
if( !( sessionInfoPtr->clientReqAttrFlags & \
SESSION_NEEDS_KEYORPASSWORD ) || \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_PASSWORD ) == NULL )
return( CRYPT_SESSINFO_PRIVATEKEY );
}
/* Make sure that request/response protocol data is present if required */
if( ( sessionInfoPtr->clientReqAttrFlags & SESSION_NEEDS_REQUEST ) && \
sessionInfoPtr->iCertRequest == CRYPT_ERROR )
return( CRYPT_SESSINFO_REQUEST );
return( CRYPT_ATTRIBUTE_NONE );
}
static CRYPT_ATTRIBUTE_TYPE checkServerParameters( const SESSION_INFO *sessionInfoPtr )
{
/* Make sure that server key and keyset information is present if
required */
if( ( sessionInfoPtr->serverReqAttrFlags & SESSION_NEEDS_PRIVATEKEY ) && \
sessionInfoPtr->privateKey == CRYPT_ERROR )
{
/* There's no private key present, see if we can use a username +
password as an alternative. In the special case of password-
based SSL this isn't completely foolproof since the passwords are
entered into a pool from which they can be deleted explicitly if
the session is aborted in a non-resumable manner (but see the
note in ssl_rw.c) or implicitly over time as they're displaced by
other entries, however this is an extremely unlikely case and
it's too tricky trying to track what is and isn't still active to
handle this fully */
if( !( sessionInfoPtr->serverReqAttrFlags & \
SESSION_NEEDS_KEYORPASSWORD ) || \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_PASSWORD ) == NULL )
return( CRYPT_SESSINFO_PRIVATEKEY );
}
if( ( sessionInfoPtr->serverReqAttrFlags & SESSION_NEEDS_KEYSET ) && \
sessionInfoPtr->cryptKeyset == CRYPT_ERROR )
return( CRYPT_SESSINFO_KEYSET );
return( CRYPT_ATTRIBUTE_NONE );
}
/* Activate the network connection for a session */
static int activateConnection( SESSION_INFO *sessionInfoPtr )
{
CRYPT_ATTRIBUTE_TYPE errorAttribute;
int status;
/* Make sure that everything is set up ready to go */
errorAttribute = isServer( sessionInfoPtr ) ? \
checkServerParameters( sessionInfoPtr ) : \
checkClientParameters( sessionInfoPtr );
if( errorAttribute != CRYPT_ATTRIBUTE_NONE )
{
setErrorInfo( sessionInfoPtr, errorAttribute,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Allocate the send and receive buffers if necessary. The send buffer
isn't used for request-response session types that use the receive
buffer for both outgoing and incoming data, so we only allocate it if
it's actually required */
if( sessionInfoPtr->sendBuffer == NULL )
{
assert( sessionInfoPtr->receiveBufSize >= MIN_BUFFER_SIZE && \
( sessionInfoPtr->sendBufSize >= MIN_BUFFER_SIZE || \
sessionInfoPtr->sendBufSize == CRYPT_UNUSED ) );
if( ( sessionInfoPtr->receiveBuffer = \
clAlloc( "activateConnection", \
sessionInfoPtr->receiveBufSize + 8 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
if( sessionInfoPtr->sendBufSize != CRYPT_UNUSED )
{
/* When allocating the send buffer we use the size for the
receive buffer since the user may have overridden the default
buffer size */
if( ( sessionInfoPtr->sendBuffer = \
clAlloc( "activateConnection", \
sessionInfoPtr->receiveBufSize + 8 ) ) == NULL )
{
clFree( "activateConnection", sessionInfoPtr->receiveBuffer );
sessionInfoPtr->receiveBuffer = NULL;
return( CRYPT_ERROR_MEMORY );
}
sessionInfoPtr->sendBufSize = sessionInfoPtr->receiveBufSize;
}
}
assert( isServer( sessionInfoPtr ) || \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_SERVER_NAME ) != NULL || \
sessionInfoPtr->networkSocket != CRYPT_ERROR );
assert( findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_SERVER_PORT ) != NULL || \
sessionInfoPtr->protocolInfo->port > 0 );
assert( sessionInfoPtr->receiveBuffer != NULL );
/* Set timeouts if they're not set yet */
if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
{
int timeout;
status = krnlSendMessage( sessionInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &timeout,
CRYPT_OPTION_NET_CONNECTTIMEOUT );
sessionInfoPtr->connectTimeout = cryptStatusOK( status ) ? \
timeout : 30;
}
if( sessionInfoPtr->readTimeout == CRYPT_ERROR )
{
int timeout;
status = krnlSendMessage( sessionInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &timeout,
CRYPT_OPTION_NET_READTIMEOUT );
sessionInfoPtr->readTimeout = cryptStatusOK( status ) ? \
timeout : 30;
}
if( sessionInfoPtr->writeTimeout == CRYPT_ERROR )
{
int timeout;
status = krnlSendMessage( sessionInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &timeout,
CRYPT_OPTION_NET_WRITETIMEOUT );
sessionInfoPtr->writeTimeout = cryptStatusOK( status ) ? \
timeout : 30;
}
/* Wait for any async driver binding to complete. We can delay this
until this very late stage because no networking functionality is
used until this point */
if( !krnlWaitSemaphore( SEMAPHORE_DRIVERBIND ) )
{
/* The kernel is shutting down, bail out */
return( CRYPT_ERROR_PERMISSION );
}
/* If this is the first time we've got here, activate the session */
if( !( sessionInfoPtr->flags & SESSION_PARTIALOPEN ) )
{
status = sessionInfoPtr->connectFunction( sessionInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
assert( !sIsNullStream( &sessionInfoPtr->stream ) );
/* If it's a secure data transport session, complete the session state
setup. Note that some sessions dynamically change the protocol info
during the handshake to accommodate parameters negotiated during the
handshake, so we can only access the protocol info after the handshake
has completed */
if( !sessionInfoPtr->protocolInfo->isReqResp )
{
/* Complete the session handshake to set up the secure state */
status = sessionInfoPtr->transactFunction( sessionInfoPtr );
if( cryptStatusError( status ) )
{
/* If we need a check of a resource (for example a user name and
password or cert supplied by the other side) before we can
complete the handshake, we remain in the handshake state so
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -