📄 tsp.c
字号:
one */
#define respSize( data ) ( data[ 3 ] + 4 )
static const BYTE respBadGeneric[] = {
0x00, 0x00, 0x00, 0x08, /* Length */
0x05, /* Type */
0x30, 0x05, 0x30, 0x03, 0x02, 0x01, 0x02
}; /* Rejection, unspecified reason */
static const BYTE respBadData[] = {
0x00, 0x00, 0x00, 0x0C, /* Length */
0x05, /* Type */
0x30, 0x09, 0x30, 0x07, 0x02, 0x01, 0x02, 0x03,
0x02, 0x05, 0x20 /* Rejection, badDataFormat */
};
static const BYTE respBadPolicy[] = {
0x00, 0x00, 0x00, 0x0D, /* Length */
0x05, /* Type */
0x30, 0x0A, 0x30, 0x08, 0x02, 0x01, 0x02, 0x03,
0x03, 0x00, 0x00, 0x01 /* Rejection, unacceptedPolicy */
};
static const BYTE respBadExtension[] = {
0x00, 0x00, 0x00, 0x0E, /* Length */
0x05, /* Type */
0x30, 0x0B, 0x30, 0x09, 0x02, 0x01, 0x02, 0x03,
0x04, 0x07, 0x00, 0x00, 0x80 /* Rejection, unacceptedExtension */
};
/* Exchange a datagram with a TSP client */
static int exchangeServerDatagram( SESSION_INFO *sessionInfoPtr )
{
TSPREQUEST_INFO requestInfo;
STREAM stream;
BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
long length;
int responseLength, status;
/* Read the request header and make sure it's is in order */
status = sread( &sessionInfoPtr->stream, bufPtr, TSP_HEADER_SIZE );
if( cryptStatusError( status ) )
return( status );
length = mgetBLong( bufPtr );
if( length < 16 || length > sessionInfoPtr->receiveBufSize || \
( *bufPtr != TSP_MESSAGE_REQUEST && \
*bufPtr != TSP_MESSAGE_RESPONSE ) )
{
swrite( &sessionInfoPtr->stream, respBadData,
respSize( respBadData ) );
return( CRYPT_ERROR_BADDATA );
}
/* Read the request data from the client */
status = sread( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer,
length - 1 );
if( cryptStatusError( status ) )
{
swrite( &sessionInfoPtr->stream, respBadGeneric,
respSize( respBadGeneric ) );
return( status );
}
sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length - 1 );
status = readTSPRequest( &stream, &requestInfo );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
if( status == CRYPT_ERROR_BADDATA || \
status == CRYPT_ERROR_UNDERFLOW )
swrite( &sessionInfoPtr->stream, respBadData,
respSize( respBadData ) );
if( status == CRYPT_ERROR_INVALID )
swrite( &sessionInfoPtr->stream, respBadExtension,
respSize( respBadExtension ) );
else
swrite( &sessionInfoPtr->stream, respBadGeneric,
respSize( respBadGeneric ) );
return( status );
}
/* Create a timestamp token and sign it */
sMemOpen( &stream, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize );
status = writeTSToken( &stream, &requestInfo );
length = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusOK( status ) )
status = signTSToken( sessionInfoPtr->receiveBuffer + TSP_HEADER_SIZE + 9,
&responseLength, sessionInfoPtr->receiveBufSize,
sessionInfoPtr->receiveBuffer, length,
sessionInfoPtr->privateKey,
requestInfo.includeSigCerts );
if( cryptStatusError( status ) )
{
swrite( &sessionInfoPtr->stream, respBadGeneric,
respSize( respBadGeneric ) );
return( status );
}
assert( responseLength >= 256 );
/* Add the TSA response wrapper and response header and send the response
to the client. This assumes that the TSA response will be >= 256
bytes (for a 4-byte SEQUENCE header encoding) which is always the case
since it uses PKCS #7 signed data */
bufPtr = sessionInfoPtr->receiveBuffer;
mputBLong( bufPtr, 1 + 9 + responseLength );
*bufPtr++ = TSP_MESSAGE_RESPONSE;
sMemOpen( &stream, bufPtr, 4 + 5 ); /* SEQ + resp.header */
writeSequence( &stream, 5 + responseLength );
swrite( &stream, "\x30\x03\x02\x01\x00", 5 );
sMemDisconnect( &stream );
return( swrite( &sessionInfoPtr->stream, sessionInfoPtr->receiveBuffer,
5 + 9 + responseLength ) );
}
/****************************************************************************
* *
* Init/Shutdown Functions *
* *
****************************************************************************/
/* Init/shutdown functions. Since TSP is stateless there isn't much to do */
static int initFunction( SESSION_INFO *sessionInfoPtr )
{
/* Set various TSP session parameters */
sessionInfoPtr->requiredAttributeFlags |= \
SESSION_SERVER_NEEDSPRIVATEKEY | SESSION_SERVER_NEEDSPRIVKEYCERT;
sessionInfoPtr->requiredCertAttribute = CRYPT_CERTINFO_EXTKEY_TIMESTAMPING;
sessionInfoPtr->sendBufSize = CRYPT_UNUSED;
sessionInfoPtr->receiveBufSize = MIN_BUFFER_SIZE;
sessionInfoPtr->serverPort = TSP_PORT;
return( CRYPT_OK );
}
/* Exchange data with a TSP server */
static int clientStartup( SESSION_INFO *sessionInfoPtr )
{
STREAM stream;
BYTE msgImprint[ 32 + CRYPT_MAX_HASHSIZE ], *msgImprintPtr;
const BOOLEAN useHTTP = !strnicmp( sessionInfoPtr->serverName,
"http://", 7 );
long value;
int timeout, msgImprintLength, startPos, length, status;
krnlSendMessage( sessionInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &timeout,
CRYPT_OPTION_NET_CONNECTTIMEOUT );
/* Make sure we have all the needed information */
if( sessionInfoPtr->tspImprintSize == 0 )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_TSP_MSGIMPRINT,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Create the encoded request */
msgImprintLength = sizeofMessageDigest( sessionInfoPtr->tspImprintAlgo,
sessionInfoPtr->tspImprintSize );
sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
writeSequence( &stream, sizeofShortInteger( TSP_VERSION ) + \
msgImprintLength );
writeShortInteger( &stream, TSP_VERSION, DEFAULT_TAG );
msgImprintPtr = sMemBufPtr( &stream );
writeMessageDigest( &stream, sessionInfoPtr->tspImprintAlgo,
sessionInfoPtr->tspImprint,
sessionInfoPtr->tspImprintSize );
memcpy( msgImprint, msgImprintPtr, msgImprintLength );
length = stell( &stream );
sMemDisconnect( &stream );
/* Exchange data with the TSP server */
if( useHTTP )
status = sNetConnect( &sessionInfoPtr->stream,
STREAM_PROTOCOL_HTTP_TRANSACTION,
sessionInfoPtr->serverName,
( sessionInfoPtr->serverPort == TSP_PORT ) ? \
80 : sessionInfoPtr->serverPort, timeout,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
else
status = sNetConnect( &sessionInfoPtr->stream,
STREAM_PROTOCOL_TCPIP,
sessionInfoPtr->serverName,
sessionInfoPtr->serverPort, timeout,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
if( cryptStatusError( status ) )
return( status );
status = exchangeClientDatagram( &sessionInfoPtr->stream,
sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize, length,
useHTTP );
if( cryptStatusError( status ) )
sNetGetErrorInfo( &sessionInfoPtr->stream,
sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
sNetDisconnect( &sessionInfoPtr->stream );
if( cryptStatusError( status ) )
return( status );
/* Find out how much data we got and perform a firewall check that
everything is OK. We rely on this rather than the read byte count
since checking the ASN.1, which is the data which will actually be
processed, avoids any vagaries of server implementation oddities
which may send extra null bytes or CRLFs or do who knows what else */
length = checkObjectEncoding( sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize );
if( cryptStatusError( length ) )
return( length );
if( length < 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, both to
save a few cycles but mostly to avoid triggering sanity checks
within the code for too-short objects */
return( CRYPT_ERROR_INVALID );
sessionInfoPtr->receiveBufEnd = length;
/* Strip off the header and PKIStatus wrapper and make sure everything is
OK */
sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
readSequence( &stream, NULL );
readSequence( &stream, &length );
startPos = ( int ) stell( &stream );
status = readShortInteger( &stream, &value );
if( cryptStatusOK( status ) )
{
if( stell( &stream ) < startPos + length )
/* Skip extraneous data */
readUniversal( &stream );
if( value != 0 )
{
/* A PKI status code is a bit difficult to turn into anything
useful, the best we can do is to report that that operation
failed and let the user get the exact details from the PKI
status */
status = CRYPT_ERROR_FAILED;
sessionInfoPtr->errorCode = ( int ) value;
}
else
/* Remember where the payload starts in the buffer */
sessionInfoPtr->receiveBufPos = stell( &stream );
}
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
/* Make sure we got back a timestamp of the value we sent. This check
means 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, DEFAULT_TAG );/* OCTET STRING hole */
readSequence( &stream, NULL ); /* tstInfo */
readShortInteger( &stream, NULL ); /* version */
status = readUniversal( &stream ); /* policy */
if( cryptStatusError( status ) || \
memcmp( msgImprint, sMemBufPtr( &stream ), msgImprintLength ) )
status = CRYPT_ERROR_BADDATA;
sMemDisconnect( &stream );
return( status );
}
/* Start a TSP server */
static int serverStartup( SESSION_INFO *sessionInfoPtr )
{
int timeout, status;
krnlSendMessage( sessionInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &timeout,
CRYPT_OPTION_NET_CONNECTTIMEOUT );
/* Open a local socket and listen on it */
status = sNetListenSocket( &sessionInfoPtr->stream,
STREAM_PROTOCOL_TCPIP, sessionInfoPtr->serverName,
sessionInfoPtr->serverPort, sessionInfoPtr->errorMessage,
&sessionInfoPtr->errorCode );
if( cryptStatusError( status ) )
return( status );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_GETCLIENTNAME,
sessionInfoPtr->clientName, 0 );
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_GETCLIENTPORT,
&sessionInfoPtr->clientPort, 0 );
/* Exchange a timestamp datagram with the client */
status = exchangeServerDatagram( sessionInfoPtr );
sNetDisconnect( &sessionInfoPtr->stream );
return( status );
}
static int connectFunction( SESSION_INFO *sessionInfoPtr )
{
if( sessionInfoPtr->flags & SESSION_ISSERVER )
return( serverStartup( sessionInfoPtr ) );
return( clientStartup( sessionInfoPtr ) );
}
/****************************************************************************
* *
* Control Information Management Functions *
* *
****************************************************************************/
static int getAttributeFunction( SESSION_INFO *sessionInfoPtr,
void *data, const CRYPT_ATTRIBUTE_TYPE type )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) data;
assert( type == CRYPT_IATTRIBUTE_ENC_TIMESTAMP );
/* Return the encoded timestamp data to the caller */
return( attributeCopy( msgData,
sessionInfoPtr->receiveBuffer + sessionInfoPtr->receiveBufPos,
sessionInfoPtr->receiveBufEnd - sessionInfoPtr->receiveBufPos ) );
}
static int setAttributeFunction( SESSION_INFO *sessionInfoPtr,
const void *data,
const CRYPT_ATTRIBUTE_TYPE type )
{
CRYPT_CONTEXT hashContext = *( ( CRYPT_CONTEXT * ) data );
RESOURCE_DATA msgData = { NULL, 0 };
int status;
assert( type == CRYPT_SESSINFO_TSP_MSGIMPRINT );
/* Get the message imprint from the hash context */
status = krnlSendMessage( hashContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&sessionInfoPtr->tspImprintAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA msgData;
setResourceData( &msgData, sessionInfoPtr->tspImprint,
CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( hashContext, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusError( status ) )
return( status );
sessionInfoPtr->tspImprintSize = msgData.length;
}
return( cryptStatusError( status ) ? CRYPT_ARGERROR_NUM1 : CRYPT_OK );
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
int setAccessMethodTSP( SESSION_INFO *sessionInfoPtr )
{
/* Set the access method pointers */
sessionInfoPtr->initFunction = initFunction;
sessionInfoPtr->connectFunction = connectFunction;
sessionInfoPtr->getAttributeFunction = getAttributeFunction;
sessionInfoPtr->setAttributeFunction = setAttributeFunction;
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -