📄 tsp.c
字号:
/****************************************************************************
* *
* cryptlib TSP Session Management *
* Copyright Peter Gutmann 1999-2002 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "asn1_rw.h"
#include "asn1s_rw.h"
#include "objinfo.h"
#include "session.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../misc/asn1_rw.h"
#include "../misc/asn1s_rw.h"
#include "../misc/objinfo.h"
#include "../session/session.h"
#else
#include "crypt.h"
#include "misc/asn1_rw.h"
#include "misc/asn1s_rw.h"
#include "misc/objinfo.h"
#include "session/session.h"
#endif /* Compiler-specific includes */
#ifdef USE_TSP
/* TSP constants */
#define TSP_PORT 318 /* Default port number */
#define TSP_VERSION 1 /* Version number */
#define TSP_HEADER_SIZE 5 /* 4-byte length + 1-byte type */
#define MIN_MSGIMPRINT_SIZE 20 /* Min.and max.size for message imprint */
#define MAX_MSGIMPRINT_SIZE ( 32 + CRYPT_MAX_HASHSIZE )
/* TSP socket protocol message types. This is a mutant variant of the CMP
socket protocol (but incompatible, obviously), with no-one involved in the
standard really able to explain why it exists, since it doesn't actually
serve any purpose */
enum { TSP_MESSAGE_REQUEST, TSP_MESSAGE_POLLREP, TSP_MESSAGE_POLLREQ,
TSP_MESSAGE_NEGPOLLREP, TSP_MESSAGE_PARTIALMSGREP, TSP_MESSAGE_RESPONSE,
TSP_MESSAGE_ERROR };
/* Dummy policy OID for the TSA ('snooze policy, "Anything that arrives, we
sign") */
#define OID_TSP_POLICY MKOID( "\x06\x0B\x2B\x06\x01\x04\x01\x97\x55\x36\xDD\x24\x36" )
/* TSP protocol state information. This is passed around the various
subfunctions that handle individual parts of the protocol */
typedef struct {
BYTE msgImprint[ MAX_MSGIMPRINT_SIZE ];
int msgImprintSize; /* Message imprint */
BYTE nonce[ CRYPT_MAX_HASHSIZE ];
int nonceSize; /* Nonce (if present) */
BOOLEAN includeSigCerts; /* Whether to include signer certs */
} TSP_PROTOCOL_INFO;
/* Prototypes for functions in cmp.c. This code is shared due to TSP's use
of random elements cut&pasted from CMP */
int readPkiStatusInfo( STREAM *stream, int *errorCode, char *errorMessage );
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Read a TSP request */
static int readTSPRequest( STREAM *stream, TSP_PROTOCOL_INFO *protocolInfo,
void *errorInfo )
{
BYTE *bufPtr;
long value;
int length, status;
/* Read the request header and make sure everything is in order */
readSequence( stream, NULL );
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) || value != TSP_VERSION )
retExt( errorInfo, CRYPT_ERROR_BADDATA,
"Invalid request version %d", value );
/* Read the message imprint. We don't really care what this is so we
just treat it as a blob */
bufPtr = sMemBufPtr( stream );
status = readSequence( stream, &length );
if( cryptStatusError( status ) || \
length < MIN_MSGIMPRINT_SIZE || length > MAX_MSGIMPRINT_SIZE || \
cryptStatusError( sSkip( stream, length ) ) )
retExt( errorInfo, CRYPT_ERROR_BADDATA,
"Invalid request data length %d", length );
length = ( int ) sizeofObject( length );
memcpy( protocolInfo->msgImprint, bufPtr, length );
protocolInfo->msgImprintSize = length;
/* Check for the presence of the assorted optional fields */
if( peekTag( stream ) == BER_OBJECT_IDENTIFIER )
/* This could be anything since it's defined as "by prior agreement"
so we ignore it and give them whatever policy we happen to
implement, if they don't like it they're free to ignore it */
status = readUniversal( stream );
if( cryptStatusOK( status ) && peekTag( stream ) == BER_INTEGER )
status = readRawObject( stream, protocolInfo->nonce,
&protocolInfo->nonceSize, CRYPT_MAX_HASHSIZE,
BER_INTEGER );
if( cryptStatusOK( status ) && peekTag( stream ) == BER_BOOLEAN )
status = readBoolean( stream, &protocolInfo->includeSigCerts );
if( cryptStatusOK( status ) && peekTag( stream ) == MAKE_CTAG( 0 ) )
/* The TSP RFC specifies a truly braindamaged interpretation of
extension handling, added at the last minute with no debate or
discussion. This says that extensions are handled just like RFC
2459 except when they're not. In particular it requires that you
reject all extensions that you don't recognise, even if they
don't have the critical bit set (in violation of RFC 2459).
Since "recognise" is never defined and the spec doesn't specify
any particular extensions that must be handled (via MUST/SHALL/
SHOULD), any extension at all is regarded as unrecognised in the
context of the RFC. For example if a request with a
subjectAltName is submitted then although the TSA knows perfectly
well what a subjectAltName, it has no idea what it's supposed to
do with it when it sees it in the request. Since the semantics of
all extensions are unknown (in the context of the RFC), any
request with extensions has to be rejected.
Along with assorted other confusing and often contradictory terms
added in the last-minute rewrite, cryptlib ignores this
requirement and instead uses the common-sense interpretation of
allowing any extension that the RFC doesn't specifically provide
semantics for. Since it doesn't provide semantics for any
extension, we allow anything */
status = readUniversal( stream );
if( cryptStatusError( status ) )
retExt( errorInfo, CRYPT_ERROR_BADDATA, "Invalid request data" );
return( CRYPT_OK );
}
/* Sign a timestamp token */
static int signTSToken( BYTE *tsaResp, int *tsaRespLength,
const int tsaRespMaxLength, const BYTE *tstInfo,
const int tstInfoLength,
const CRYPT_CONTEXT privateKey,
const BOOLEAN includeCerts )
{
CRYPT_CERTIFICATE iCmsAttributes;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
DYNBUF essCertDB;
static const int minBufferSize = MIN_BUFFER_SIZE;
static const int contentType = CRYPT_CONTENT_TSTINFO;
int status;
/* Create the signing attributes. We don't have to set the content-type
attribute since it'll be set automatically based on the envelope
content type */
setMessageCreateObjectInfo( &createInfo, CRYPT_CERTTYPE_CMS_ATTRIBUTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
iCmsAttributes = createInfo.cryptHandle;
status = dynCreate( &essCertDB, privateKey, CRYPT_IATTRIBUTE_ESSCERTID );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, dynData( essCertDB ),
dynLength( essCertDB ) );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_CMS_SIGNINGCERT_ESSCERTID );
dynDestroy( &essCertDB );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Create a cryptlib envelope to sign the data. If we're not being
asked to include signer certs, we have to explicitly disable the
inclusion of certs in the signature since S/MIME includes them by
default */
setMessageCreateObjectInfo( &createInfo, CRYPT_FORMAT_CMS );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_ENVELOPE );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
return( status );
}
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
( void * ) &minBufferSize,
CRYPT_ATTRIBUTE_BUFFERSIZE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE, ( void * ) &tstInfoLength,
CRYPT_ENVINFO_DATASIZE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE, ( void * ) &contentType,
CRYPT_ENVINFO_CONTENTTYPE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE, ( void * ) &privateKey,
CRYPT_ENVINFO_SIGNATURE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE, &iCmsAttributes,
CRYPT_ENVINFO_SIGNATURE_EXTRADATA );
if( cryptStatusOK( status ) && !includeCerts )
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_FALSE,
CRYPT_IATTRIBUTE_INCLUDESIGCERT );
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Push in the data and pop the signed result */
setMessageData( &msgData, ( void * ) tstInfo, tstInfoLength );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
}
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, tsaResp, tsaRespMaxLength );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_ENV_POPDATA, &msgData, 0 );
*tsaRespLength = msgData.length;
}
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
/****************************************************************************
* *
* Client-side Functions *
* *
****************************************************************************/
/* Send a request to a TSP server */
static int sendClientRequest( SESSION_INFO *sessionInfoPtr,
TSP_PROTOCOL_INFO *protocolInfo )
{
STREAM stream;
BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
void *msgImprintPtr;
/* Create the encoded request. We never ask for the inclusion of
signing certs (which is the default behaviour for TSP) because the
CMS signature-generation code needs to perform two passes over the
data (to get the signed data size for encoding purposes), however
we can't get the size without generating a timestamp. Since the
basic TST is compact and fixed-length, we can manage this, but can't
easily handle having arbitrary amounts of signing certs being
returned */
protocolInfo->msgImprintSize = \
sizeofMessageDigest( sessionInfoPtr->tspImprintAlgo,
sessionInfoPtr->tspImprintSize );
sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
writeSequence( &stream, sizeofShortInteger( TSP_VERSION ) + \
protocolInfo->msgImprintSize + \
( protocolInfo->includeSigCerts ? \
sizeofBoolean() : 0 ) );
writeShortInteger( &stream, TSP_VERSION, DEFAULT_TAG );
msgImprintPtr = sMemBufPtr( &stream );
writeMessageDigest( &stream, sessionInfoPtr->tspImprintAlgo,
sessionInfoPtr->tspImprint,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -