📄 tsp.c
字号:
tspInfo->imprint, tspInfo->imprintSize );
memcpy( protocolInfo->msgImprint, msgImprintPtr,
protocolInfo->msgImprintSize );
if( protocolInfo->includeSigCerts )
writeBoolean( &stream, TRUE, DEFAULT_TAG );
sessionInfoPtr->receiveBufEnd = stell( &stream );
sMemDisconnect( &stream );
DEBUG_DUMP( "tsa_req", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
#ifdef USE_CMP_TRANSPORT
/* If we're using the socket protocol, add the TSP header:
uint32 length of type + data
byte type
byte[] data */
if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
{
memmove( bufPtr + TSP_HEADER_SIZE, bufPtr,
sessionInfoPtr->receiveBufEnd );
mputLong( bufPtr, sessionInfoPtr->receiveBufEnd + 1 );
*bufPtr = TSP_MESSAGE_REQUEST;
sessionInfoPtr->receiveBufEnd += TSP_HEADER_SIZE;
}
#endif /* USE_CMP_TRANSPORT */
/* Send the request to the server */
return( writePkiDatagram( sessionInfoPtr, TSP_CONTENT_TYPE_REQ,
TSP_CONTENT_TYPE_REQ_LEN ) );
}
/* Read the response from the TSP server */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readServerResponse( SESSION_INFO *sessionInfoPtr,
TSP_PROTOCOL_INFO *protocolInfo )
{
STREAM stream;
#ifdef USE_CMP_TRANSPORT
const int oldBufSize = sessionInfoPtr->receiveBufSize;
#endif /* USE_CMP_TRANSPORT */
int status;
/* Reset the buffer position indicators to clear any old data in the
buffer from previous transactions */
sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos = 0;
#ifdef USE_CMP_TRANSPORT
/* If we're using the socket protocol, read back the header and make
sure that it's in order. The check for a response labelled as a
request is necessary because some buggy implementations use the
request message type for any normal communication (in fact since the
socket protocol arose from a botched cut & paste of the equivalent
CMP protocol it serves no actual purpose and so some implementations
just memcpy() in a fixed header) */
if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
{
BYTE buffer[ TSP_HEADER_SIZE + 8 ], *bufPtr = buffer;
long packetLength;
status = sread( &sessionInfoPtr->stream, buffer, TSP_HEADER_SIZE );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
&sessionInfoPtr->errorInfo );
return( status );
}
packetLength = mgetLong( bufPtr );
if( packetLength < 16 || \
packetLength > sessionInfoPtr->receiveBufSize || \
( *bufPtr != TSP_MESSAGE_REQUEST && \
*bufPtr != TSP_MESSAGE_RESPONSE ) )
{
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TSP socket protocol data" ) );
}
/* Fiddle the read buffer size to make sure we only try and read as
much as the wrapper protocol has told us is present. This kludge
is necessary because the wrapper protocol isn't any normal
transport mechanism like HTTP but a botched cut & paste from CMP
that can't easily be accommodated by the network-layer code */
sessionInfoPtr->receiveBufSize = ( int ) packetLength - 1;
}
#endif /* USE_CMP_TRANSPORT */
/* Read the response data from the server */
status = readPkiDatagram( sessionInfoPtr );
#ifdef USE_CMP_TRANSPORT
if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
{
/* Reset the receive buffer size to its true value */
sessionInfoPtr->receiveBufSize = oldBufSize;
}
#endif /* USE_CMP_TRANSPORT */
if( cryptStatusError( status ) )
return( status );
if( sessionInfoPtr->receiveBufEnd < 16 )
{
/* If the length is tiny, it's an error response. We don't even
bother trying to feed it to the cert handling code, in theory to
save a few cycles but mostly to avoid triggering sanity checks
within the code for too-short objects */
retExt( CRYPT_ERROR_INVALID,
( CRYPT_ERROR_INVALID, SESSION_ERRINFO,
"TSA returned error response" ) );
}
/* Strip off the header and check the PKIStatus wrapper to make sure
everything is OK */
sMemConnect( &stream, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
readSequence( &stream, NULL );
status = readPkiStatusInfo( &stream, &sessionInfoPtr->errorInfo );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
/* Remember where the encoded timestamp payload starts in the buffer so
that we can return it to the caller */
sessionInfoPtr->receiveBufPos = stell( &stream );
/* Make sure that we got back a timestamp of the value we sent. This
check means that it works with and without nonces (in theory someone
could repeatedly contersign the same signature rather than
countersigning the last timestamp as they're supposed to, but (a)
that's rather unlikely and (b) cryptlib doesn't support it so they'd
have to make some rather serious changes to the code to do it) */
readSequence( &stream, NULL ); /* contentInfo */
readUniversal( &stream ); /* contentType */
readConstructed( &stream, NULL, 0 );/* content */
readSequence( &stream, NULL ); /* signedData */
readShortInteger( &stream, NULL ); /* version */
readUniversal( &stream ); /* digestAlgos */
readSequence( &stream, NULL ); /* encapContent */
readUniversal( &stream ); /* contentType */
readConstructed( &stream, NULL, 0 ); /* content */
readOctetStringHole( &stream, NULL, 16,
DEFAULT_TAG ); /* OCTET STRING hole */
readSequence( &stream, NULL ); /* tstInfo */
readShortInteger( &stream, NULL ); /* version */
status = readUniversal( &stream ); /* policy */
if( cryptStatusError( status ) )
status = CRYPT_ERROR_BADDATA;
else
{
void *msgImprintPtr;
status = sMemGetDataBlock( &stream, &msgImprintPtr,
protocolInfo->msgImprintSize );
if( cryptStatusOK( status ) && \
memcmp( protocolInfo->msgImprint, msgImprintPtr,
protocolInfo->msgImprintSize ) )
status = CRYPT_ERROR_INVALID;
}
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
retExt( status,
( status, SESSION_ERRINFO,
( status == CRYPT_ERROR_BADDATA || \
status == CRYPT_ERROR_UNDERFLOW ) ? \
"Invalid timestamp data" : \
"Timestamp message imprint doesn't match message "
"imprint" ) );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Server-side Functions *
* *
****************************************************************************/
/* Send an error response back to the client. Since there are only a small
number of these, we write back a fixed blob rather than encoding each
one */
#ifdef USE_CMP_TRANSPORT
#define respSize( data ) ( data[ 3 ] + 4 )
static const BYTE FAR_BSS respBadGeneric[] = {
0x00, 0x00, 0x00, 0x08, /* Length */
0x05, /* Type */
0x30, 0x05, 0x30, 0x03, 0x02, 0x01, 0x02
}; /* Rejection, unspecified reason */
static const BYTE FAR_BSS respBadData[] = {
0x00, 0x00, 0x00, 0x0C, /* Length */
0x05, /* Type */
0x30, 0x09, 0x30, 0x07, 0x02, 0x01, 0x02, 0x03,
0x02, 0x05, 0x20 /* Rejection, badDataFormat */
};
static const BYTE FAR_BSS respBadExtension[] = {
0x00, 0x00, 0x00, 0x0E, /* Length */
0x05, /* Type */
0x30, 0x0B, 0x30, 0x09, 0x02, 0x01, 0x02, 0x03,
0x04, 0x07, 0x00, 0x00, 0x80 /* Rejection, unacceptedExtension */
};
#else
#define respSize( data ) ( data[ 1 ] + 2 )
static const BYTE FAR_BSS respBadGeneric[] = {
0x30, 0x05,
0x30, 0x03,
0x02, 0x01, 0x02 /* Rejection, unspecified reason */
};
static const BYTE FAR_BSS respBadData[] = {
0x30, 0x09,
0x30, 0x07,
0x02, 0x01, 0x02,
0x03, 0x02, 0x05, 0x20 /* Rejection, badDataFormat */
};
static const BYTE FAR_BSS respBadExtension[] = {
0x30, 0x0B,
0x30, 0x09,
0x02, 0x01, 0x02,
0x03, 0x04, 0x07, 0x00, 0x00, 0x80 /* Rejection, unacceptedExtension */
};
#endif /* USE_CMP_TRANSPORT */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int sendErrorResponse( INOUT SESSION_INFO *sessionInfoPtr,
const BYTE *errorResponse, const int status )
{
/* Since we're already in an error state there's not much that we can do
in terms of alerting the user if a further error occurs when writing
the error response, so we ignore any potential write errors that occur
at this point */
#ifdef USE_CMP_TRANSPORT
if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
{
memcpy( sessionInfoPtr->receiveBuffer, errorResponse,
respSize( errorResponse ) );
sessionInfoPtr->receiveBufEnd = respSize( errorResponse );
}
else
#endif /* USE_CMP_TRANSPORT */
{
memcpy( sessionInfoPtr->receiveBuffer, errorResponse,
respSize( errorResponse ) );
sessionInfoPtr->receiveBufEnd = respSize( errorResponse );
}
( void ) writePkiDatagram( sessionInfoPtr, TSP_CONTENT_TYPE_RESP,
TSP_CONTENT_TYPE_RESP_LEN );
return( status );
}
/* Read a request from a TSP client */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readClientRequest( INOUT SESSION_INFO *sessionInfoPtr,
INOUT TSP_PROTOCOL_INFO *protocolInfo )
{
STREAM stream;
#ifdef USE_CMP_TRANSPORT
BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
const int oldBufSize = sessionInfoPtr->receiveBufSize;
#endif /* USE_CMP_TRANSPORT */
int status;
#ifdef USE_CMP_TRANSPORT
/* If we're using the socket protocol, read the request header and make
sure it's in order. We don't write an error response at this initial
stage to prevent scanning/DOS attacks (vir sapit qui pauca
loquitur) */
if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
{
long packetLength;
status = sread( &sessionInfoPtr->stream, bufPtr, TSP_HEADER_SIZE );
if( cryptStatusError( status ) )
{
sNetGetErrorInfo( &sessionInfoPtr->stream,
&sessionInfoPtr->errorInfo );
return( status );
}
packetLength = mgetLong( bufPtr );
if( packetLength < 16 || \
packetLength > sessionInfoPtr->receiveBufSize || \
( *bufPtr != TSP_MESSAGE_REQUEST && \
*bufPtr != TSP_MESSAGE_RESPONSE ) )
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid TSP socket protocol data" ) );
/* Fiddle the read buffer size to make sure we only try and read as
much as the wrapper protocol has told us is present. This kludge
is necessary because the wrapper protocol isn't any normal
transport mechanism like HTTP but a botched cut&paste from CMP
that can't easily be accommodated by the network-layer code */
sessionInfoPtr->receiveBufSize = ( int ) packetLength - 1;
}
#endif /* USE_CMP_TRANSPORT */
/* Read the request data from the client */
status = readPkiDatagram( sessionInfoPtr );
#ifdef USE_CMP_TRANSPORT
if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
{
/* Reset the receive buffer size to its true value */
sessionInfoPtr->receiveBufSize = oldBufSize;
}
#endif /* USE_CMP_TRANSPORT */
if( cryptStatusError( status ) )
return( sendErrorResponse( sessionInfoPtr, respBadGeneric, status ) );
sMemConnect( &stream, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
status = readTSPRequest( &stream, protocolInfo, SESSION_ERRINFO );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
return( sendErrorResponse( sessionInfoPtr, \
( status == CRYPT_ERROR_BADDATA || \
status == CRYPT_ERROR_UNDERFLOW ) ? respBadData : \
( status == CRYPT_ERROR_INVALID ) ? respBadExtension : \
respBadGeneric, status ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -