📄 cryptses.c
字号:
STREAM_PROTOCOL_HTTP_TRANSACTION,
&connectInfo, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
else
{
if( sessionInfoPtr->flags & SESSION_USEALTTRANSPORT )
{
const ALTPROTOCOL_INFO *altProtocolInfoPtr = \
protocolInfoPtr->altProtocolInfo;
/* If we're using the HTTP port for a session-specific protocol,
change it to the default port for the session-specific
protocol instead */
if( connectInfo.port == 80 )
connectInfo.port = altProtocolInfoPtr->port;
status = sNetConnect( &sessionInfoPtr->stream,
altProtocolInfoPtr->type,
&connectInfo, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
}
else
status = sNetConnect( &sessionInfoPtr->stream,
STREAM_PROTOCOL_TCPIP,
&connectInfo, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
}
if( cryptStatusError( status ) )
return( status );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_HANDSHAKETIMEOUT, NULL, 0 );
if( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT )
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONTENTTYPE,
( void * ) protocolInfoPtr->clientContentType,
strlen( protocolInfoPtr->clientContentType ) );
return( CRYPT_OK );
}
static int defaultServerStartupFunction( SESSION_INFO *sessionInfoPtr )
{
const PROTOCOL_INFO *protocolInfoPtr = sessionInfoPtr->protocolInfo;
NET_CONNECT_INFO connectInfo;
int status;
/* Wait for a client connection */
initSessionNetConnectInfo( sessionInfoPtr, &connectInfo );
if( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT )
status = sNetListen( &sessionInfoPtr->stream,
STREAM_PROTOCOL_HTTP_TRANSACTION,
&connectInfo, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
else
{
if( sessionInfoPtr->flags & SESSION_USEALTTRANSPORT )
{
const ALTPROTOCOL_INFO *altProtocolInfoPtr = \
protocolInfoPtr->altProtocolInfo;
/* If we're using the HTTP port for a session-specific protocol,
change it to the default port for the session-specific
protocol instead */
if( connectInfo.port == 80 )
connectInfo.port = altProtocolInfoPtr->port;
status = sNetListen( &sessionInfoPtr->stream,
altProtocolInfoPtr->type,
&connectInfo, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
}
else
status = sNetListen( &sessionInfoPtr->stream,
STREAM_PROTOCOL_TCPIP,
&connectInfo, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
}
if( cryptStatusError( status ) )
return( status );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_HANDSHAKETIMEOUT, NULL, 0 );
if( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT )
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONTENTTYPE,
( void * ) protocolInfoPtr->serverContentType,
strlen( protocolInfoPtr->serverContentType ) );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_GETCLIENTNAME,
sessionInfoPtr->clientName, 0 );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_GETCLIENTPORT,
&sessionInfoPtr->clientPort, 0 );
return( CRYPT_OK );
}
static void defaultShutdownFunction( SESSION_INFO *sessionInfoPtr )
{
sNetDisconnect( &sessionInfoPtr->stream );
}
/* Default get-attribute function used when no session-specific ones is
provided */
static int defaultGetAttributeFunction( SESSION_INFO *sessionInfoPtr,
void *data,
const CRYPT_ATTRIBUTE_TYPE type )
{
CRYPT_CERTIFICATE *responsePtr = ( CRYPT_CERTIFICATE * ) data;
assert( type == CRYPT_SESSINFO_RESPONSE );
/* If we didn't get a response there's nothing to return */
if( sessionInfoPtr->iCertResponse == CRYPT_ERROR )
return( CRYPT_ERROR_NOTFOUND );
/* Return the info to the caller */
krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_INCREFCOUNT );
*responsePtr = sessionInfoPtr->iCertResponse;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Secure Session Data Handling 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 helper function tryRead() that either reads
everything which is available or to the end of the current packet. In
other words it's an atomic, all-or-nothing function that can be used by
higher-level code to handle network-level packetisation. Buffer
management is handled as follows: The bPos index always points to the end
of the decoded data (i.e. data that 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, pendingPacketRemaining contains the
number of bytes required to complete the packet and bEnd points to the
end of the received data, and is advanced as more data is read:
<----> pPR
----+-------------------+----+----
////|///////////////////|....|
----+-------------------+----+----
^ ^
| |
bPos bEnd
Once the complete packet is read (pPR reaches 0), it's decrypted, and
bPos and bEnd are adjusted to point to the end of the new data:
----+------------------------+----
////|////////////////////////|
----+------------------------+----
^
|
bEnd/bPos
The handling of any header data present at the start of the packet
depends on the packet format, if the header is independent of the
encrypted data it's handled entirely by readHeaderFunction() and there's
no need to provide special-case handling. If the header is part of the
encrypted data, decryption is a two-stage operation in which
readHeaderFunction() decrypts just enough of the packet to extract and
process the header (depositing any leftover non-header data at the start
of the buffer), and processBodyFunction() processes the rest of the data.
Errors in the readHeaderFunction() are fatal if they come from the session
protocol level (e.g. a MAC failure or bad packet) and nonfatal if they
come from the network layer below the session (the stream-level code has
its own handling of fatal vs. nonfatal errors, so we don't try and get
down to that level).
Errors in the processBodyFunction() and writeDataFunction() are always
fatal. In theory we could try to recover, however the functions update
assorted crypto state such as packet sequence numbers and IVs that would
be tricky to roll back, and in practice recoverable errors are likely to
be extremely rare (at best perhaps a CRYPT_ERROR_TIMEOUT for a context
tied to a device, however even this won't occur since the conventional
encryption and MAC contexts are all internal native contexts), so there's
little point in trying to make the functions recoverable */
static int tryRead( SESSION_INFO *sessionInfoPtr, READSTATE_INFO *readInfo )
{
int bytesLeft, status;
/* Clear return value */
*readInfo = READINFO_NONE;
/* If there's no pending packet information present, try and read it.
This can return one of four classes of values:
1. An error code.
2. Zero, to indicate that nothing was read.
3. OK_SPECIAL and read info READINFO_NOOP to indicate that header
data but no payload data was read.
4. A byte count and read info READINFO_HEADERPAYLOAD to indicate
that some payload data was read as part of the header */
if( sessionInfoPtr->pendingPacketLength <= 0 )
{
status = sessionInfoPtr->readHeaderFunction( sessionInfoPtr, readInfo );
if( status <= 0 && status != OK_SPECIAL )
return( status );
assert( ( status == OK_SPECIAL && *readInfo == READINFO_NOOP ) || \
( status > 0 && *readInfo == READINFO_HEADERPAYLOAD ) );
if( *readInfo == READINFO_HEADERPAYLOAD )
{
/* Some protocols treat the header information for a secured
data packet as part of the data, so when we read the header we
can get part of the payload included in the read. When the
protocol-specific header read code obtained some payload data
alongside the header, it returns READINFO_HEADERPAYLOAD to
indicate that the packet info needs to be adjusted for the
packet header data that was just read */
sessionInfoPtr->receiveBufEnd += status;
sessionInfoPtr->pendingPacketPartialLength = status;
sessionInfoPtr->pendingPacketRemaining -= status;
}
}
bytesLeft = sessionInfoPtr->receiveBufSize - sessionInfoPtr->receiveBufEnd;
assert( sessionInfoPtr->partialHeaderLength == 0 );
assert( sessionInfoPtr->receiveBufEnd <= sessionInfoPtr->receiveBufSize );
assert( sessionInfoPtr->receiveBufPos <= sessionInfoPtr->receiveBufEnd );
/* Sanity-check the read state */
if( sessionInfoPtr->pendingPacketLength < 0 || \
sessionInfoPtr->pendingPacketRemaining < 0 || \
sessionInfoPtr->pendingPacketPartialLength < 0 )
{
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
/* 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( bytesLeft < min( sessionInfoPtr->pendingPacketRemaining, 1024 ) )
return( 0 );
/* Try and read more of the packet */
status = sread( &sessionInfoPtr->stream,
sessionInfoPtr->receiveBuffer + sessionInfoPtr->receiveBufEnd,
min( sessionInfoPtr->pendingPacketRemaining, bytesLeft ) );
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 */
*readInfo = READINFO_PARTIAL;
return( OK_SPECIAL );
}
assert( sessionInfoPtr->pendingPacketRemaining == 0 );
/* We've got a complete packet in the buffer, process it */
return( sessionInfoPtr->processBodyFunction( sessionInfoPtr, readInfo ) );
}
/* Get data from the remote system */
static int getData( SESSION_INFO *sessionInfoPtr, void *data,
const int length )
{
BYTE *dataPtr = data;
int bytesCopied = 0, savedTimeout, status;
/* If there's an error pending (which will always be fatal, see the
comment after the tryRead() call below), set the current error state
to the pending state and return */
if( cryptStatusError( sessionInfoPtr->pendingErrorState ) )
{
assert( sessionInfoPtr->receiveBufPos == 0 );
status = sessionInfoPtr->readErrorState = \
sessionInfoPtr->pendingErrorState;
sessionInfoPtr->pendingErrorState = CRYPT_OK;
return( status );
}
/* Update the stream timeout to the current user-selected timeout in case
the user has changed the timeout setting */
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, &savedTimeout, 0 );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_TIMEOUT, NULL,
sessionInfoPtr->timeout );
while( bytesCopied < length )
{
const int bytesToCopy = min( length - bytesCopied, \
sessionInfoPtr->receiveBufPos );
READSTATE_INFO readInfo = READINFO_NONE;
int remainder;
assert( bytesToCopy >= 0 );
/* Sanity-check the read state */
if( sessionInfoPtr->receiveBufPos < 0 || \
sessionInfoPtr->receiveBufPos > sessionInfoPtr->receiveBufEnd || \
sessionInfoPtr->receiveBufEnd < 0 || \
sessionInfoPtr->receiveBufEnd > sessionInfoPtr->receiveBufSize )
{
assert( NOTREACHED );
return( CRYPT_ERROR_BADDATA );
}
/* Copy as much data as we can across and move any remaining data down
to the start of the receive buffer */
if( bytesToCopy > 0 )
{
memcpy( dataPtr, sessionInfoPtr->receiveBuffer, bytesToCopy );
remainder = sessionInfoPtr->receiveBufEnd - bytesToCopy;
assert( remainder >= 0 );
if( remainder > 0 )
memmove( sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBuffer + bytesToCopy, remainder );
sessionInfoPtr->receiveBufPos -= bytesToCopy;
sessionInfoPtr->receiveBufEnd = remainder;
assert( sessionInfoPtr->receiveBufPos >= 0 );
/* Adjust the byte count info and, if we've satisfied the request,
exit */
bytesCopied += bytesToCopy;
dataPtr += bytesToCopy;
if( bytesCopied >= length )
break;
}
assert( sessionInfoPtr->receiveBufPos == 0 );
/* Try and read a complete packet. This can return one of four classes
of values:
1. An error code.
2. Zero to indicate that nothing was read.
3a.OK_SPECIAL and read info READINFO_PARTIAL to indicate that a
partial packet (not enough to process) was read.
3b.OK_SPECIAL and read info READINFO_NOOP to indicate that a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -