?? cryptses.c
字號:
/****************************************************************************
* *
* cryptlib Secure Session Routines *
* Copyright Peter Gutmann 1998-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "crypt.h"
#ifdef INC_ALL
#include "stream.h"
#include "session.h"
#else
#include "keymgmt/stream.h"
#include "session/session.h"
#endif /* Compiler-specific includes */
/* Some session types aren't supported on some platforms so we alias the
calls out */
#ifndef NET_TCP
#define setAccessMethodSSL( x ) CRYPT_ARGERROR_NUM1
#define setAccessMethodSSH( x ) CRYPT_ARGERROR_NUM1
#define setAccessMethodCMP( x ) CRYPT_ARGERROR_NUM1
#define setAccessMethodOCSP( x ) CRYPT_ARGERROR_NUM1
#define setAccessMethodTSP( x ) CRYPT_ARGERROR_NUM1
#endif /* NET_TCP */
/****************************************************************************
* *
* Get/Put Data Functions *
* *
****************************************************************************/
/* Common code to read and write data over the secure connection. This
is called by the protocol-specific handlers, which supply three functions:
readHeaderFunction() - Reads the header for a packet and sets up
length information.
processBodyFunction() - Processes the body of a packet.
writeDataFunction() - Wraps and sends a packet.
The read data code uses a help function which either reads everything
which is available or to the end of the current packet. If it runs out
of data before reading the end of the packet it returns 0, otherwise it
returns a positive value to indicate that it's read a complete packet and
should be called again to try for further packets.
Buffer management is handled as follows: The bPos index always points to
the end of the decoded data (ie data which can be used by the user), if
there's no partial packet present this index is the same as bEnd:
----+------------------------
////|
----+------------------------
^
|
bEnd/bPos
If there's a partial packet present, bEnd points to the end of the
received data, and is advanced as more data is read:
----+-----+-------------+----
////| hdr |/////////////|....
----+-----+-------------+----
^ ^
| |
bPos bEnd
Once the complete packet is read, it's decrypted and moved down to bPos,
and bPos and bEnd are adjusted to point to the end of the new data */
static int tryRead( SESSION_INFO *sessionInfoPtr )
{
int status;
/* If there's no pending packet information present, try and read it */
if( !sessionInfoPtr->pendingPacketLength )
{
status = sessionInfoPtr->readHeaderFunction( sessionInfoPtr );
if( status <= 0 )
{
/* Some protocols treat the header information for a secured
data packet as part of the data to be secured and some don't.
When we read the header and don't want it to be processed as
part of the packet, we indicate this by returning OK_SPECIAL */
if( status != OK_SPECIAL )
return( status );
}
else
{
sessionInfoPtr->receiveBufEnd += status;
sessionInfoPtr->pendingPacketPartialLength = status;
sessionInfoPtr->pendingPacketRemaining -= status;
}
}
/* If there's not enough room in the receive buffer to read at least 1K
of packet data, don't try anything until the user has emptied more
data from the buffer */
if( sessionInfoPtr->receiveBufSize - sessionInfoPtr->receiveBufEnd < \
min( sessionInfoPtr->pendingPacketRemaining, 1024 ) )
return( 0 );
/* Try and read more of the packet */
status = sread( &sessionInfoPtr->stream,
sessionInfoPtr->receiveBuffer + sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->pendingPacketRemaining );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
return( status );
}
if( status == 0 )
/* Nothing read, try again later */
return( 0 );
sessionInfoPtr->receiveBufEnd += status;
sessionInfoPtr->pendingPacketRemaining -= status;
if( sessionInfoPtr->pendingPacketRemaining > 0 )
/* We got some but not all of the data, try again later */
return( 0 );
/* We've got a complete packet in the buffer, process it */
return( sessionInfoPtr->processBodyFunction( sessionInfoPtr ) );
}
/* Get data from the remote system */
static int getData( SESSION_INFO *sessionInfoPtr, void *data,
const int length )
{
int bytesToCopy = length, remainder, timeout, savedTimeout, status;
/* If there's an error pending and we've exhausted what was still present
from earlier reads, set the current error state to the pending state
and return */
if( cryptStatusError( sessionInfoPtr->pendingErrorState ) && \
!sessionInfoPtr->receiveBufPos )
return( sessionInfoPtr->pendingErrorState );
/* Set the stream to the appropriate timeout value (usually zero so we
can see whether there's anything there without blocking, but kul
takhira fi'khira) and see if there's any more data available to
return to the user. We save the previous value around the access in
case other administrative code needs to perform reads without being
affected by a user-set timeout */
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_GETTIMEOUT,
&savedTimeout, 0 );
krnlSendMessage( sessionInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &timeout,
CRYPT_OPTION_NET_TIMEOUT );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL, timeout );
do
{
status = tryRead( sessionInfoPtr );
if( status > 0 )
/* If we've got some data to return to the caller, reset the
stream to be nonblocking. This is necessary to avoid having
the stream always block for the set timeout value on the last
read */
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL, 0 );
}
while( status > 0 );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL,
savedTimeout );
if( cryptStatusError( status ) )
{
/* If there's an error reading data, only return an error status if
there's no further data in the buffer which can be returned, this
lets the caller drain out any remaining data from the session
buffer before they start getting error returns */
sessionInfoPtr->pendingErrorState = status;
if( sessionInfoPtr->receiveBufPos <= 0 )
return( status );
}
/* Adjust the data to copy length by the amount we have available */
if( bytesToCopy > sessionInfoPtr->receiveBufPos )
bytesToCopy = sessionInfoPtr->receiveBufPos;
/* Copy the data across and move any remaining data down to the start of
the receive buffer */
memcpy( data, sessionInfoPtr->receiveBuffer, bytesToCopy );
remainder = sessionInfoPtr->receiveBufEnd - bytesToCopy;
if( remainder )
memmove( sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBuffer + bytesToCopy, remainder );
sessionInfoPtr->receiveBufPos -= bytesToCopy;
sessionInfoPtr->receiveBufEnd = remainder;
return( bytesToCopy );
}
/* Send data to the remote system */
static int putData( SESSION_INFO *sessionInfoPtr, const void *data,
const int length )
{
BYTE *dataPtr = ( BYTE * ) data;
int dataLength = length;
assert( sessionInfoPtr->sendBufPos >= 4 && \
sessionInfoPtr->sendBufPos <= sessionInfoPtr->sendBufSize );
/* If it's a flush, send the data through to the server */
if( !dataLength )
return( sessionInfoPtr->writeDataFunction( sessionInfoPtr ) );
/* If there's too much data to fit in the buffer, send it through to the
host */
while( dataLength >= sessionInfoPtr->sendBufSize - \
sessionInfoPtr->sendBufPos )
{
const int bytesToCopy = sessionInfoPtr->sendBufSize - \
sessionInfoPtr->sendBufPos;
int status;
assert( bytesToCopy >= 0 && bytesToCopy <= dataLength );
/* Copy in as much data as we have room for and send it through */
memcpy( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufPos,
dataPtr, bytesToCopy );
dataPtr += bytesToCopy;
dataLength -= bytesToCopy;
status = sessionInfoPtr->writeDataFunction( sessionInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
/* If there's anything left, it'll fit in the buffer, just copy it in */
if( dataLength > 0 )
{
assert( dataLength < sessionInfoPtr->sendBufSize - \
sessionInfoPtr->sendBufPos );
memcpy( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufPos,
dataPtr, dataLength );
sessionInfoPtr->sendBufPos += dataLength;
}
return( length );
}
/****************************************************************************
* *
* General Session API Functions *
* *
****************************************************************************/
/* Handle data sent to or read from a session object */
static int processGetAttribute( SESSION_INFO *sessionInfoPtr,
void *messageDataPtr, const int messageValue )
{
int *valuePtr = ( int * ) messageDataPtr;
/* Handle the various information types */
switch( messageValue )
{
case CRYPT_ATTRIBUTE_ERRORTYPE:
*valuePtr = sessionInfoPtr->errorType;
return( CRYPT_OK );
case CRYPT_ATTRIBUTE_ERRORLOCUS:
*valuePtr = sessionInfoPtr->errorLocus;
return( CRYPT_OK );
case CRYPT_ATTRIBUTE_BUFFERSIZE:
*valuePtr = sessionInfoPtr->receiveBufSize;
return( CRYPT_OK );
case CRYPT_ATTRIBUTE_INT_ERRORCODE:
*valuePtr = sessionInfoPtr->errorCode;
return( CRYPT_OK );
case CRYPT_SESSINFO_ACTIVE:
*valuePtr = sessionInfoPtr->sessionOpen;
return( CRYPT_OK );
case CRYPT_SESSINFO_SERVER_PORT:
*valuePtr = sessionInfoPtr->serverPort;
return( CRYPT_OK );
case CRYPT_SESSINFO_CLIENT_PORT:
if( !sessionInfoPtr->clientPort )
return( CRYPT_ERROR_NOTINITED );
*valuePtr = sessionInfoPtr->clientPort;
return( CRYPT_OK );
case CRYPT_SESSINFO_PROTOCOLVERSION:
*valuePtr = sessionInfoPtr->version;
return( CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
static int processSetAttribute( SESSION_INFO *sessionInfoPtr,
void *messageDataPtr, const int messageValue )
{
const int value = *( int * ) messageDataPtr;
int status;
/* Handle the various information types */
switch( messageValue )
{
case CRYPT_ATTRIBUTE_BUFFERSIZE:
assert( !sessionInfoPtr->sessionOpen );
sessionInfoPtr->receiveBufSize = value;
return( CRYPT_OK );
case CRYPT_SESSINFO_ACTIVE:
assert( !sessionInfoPtr->sessionOpen );
if( value == FALSE )
return( CRYPT_OK ); /* Noop */
/* Make sure everything is set up ready to go */
if( !sessionInfoPtr->serverPort )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_SERVER_PORT,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
if( sessionInfoPtr->flags & SESSION_ISSERVER )
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -