📄 rtcs.c
字号:
/****************************************************************************
* *
* cryptlib RTCS Session Management *
* Copyright Peter Gutmann 1999-2003 *
* *
****************************************************************************/
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "asn1_rw.h"
#include "asn1s_rw.h"
#include "session.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../misc/asn1_rw.h"
#include "../misc/asn1s_rw.h"
#include "../session/session.h"
#else
#include "crypt.h"
#include "misc/asn1_rw.h"
#include "misc/asn1s_rw.h"
#include "session/session.h"
#endif /* Compiler-specific includes */
#ifdef USE_RTCS
/* Uncomment the following to read predefined requests/responses from disk
instead of communicating with the client/server */
/* #define SKIP_IO /* Don't communicate with server */
#ifdef SKIP_IO
#define readPkiDatagram( dummy ) CRYPT_OK
#define writePkiDatagram( dummy ) CRYPT_OK
#endif /* SKIP_IO */
/* The action to take to process an RTCS request/response */
typedef enum {
ACTION_NONE, /* No processing */
ACTION_UNWRAP, /* Unwrap raw data */
ACTION_CRYPT, /* Decrypt data */
ACTION_SIGN, /* Sig.check data */
ACTION_LAST /* Last valid action type */
} ACTION_TYPE;
/* RTCS protocol state information. This is passed around various
subfunctions that handle individual parts of the protocol */
typedef struct {
/* State variable information. The nonce is copied from the request to
the response to prevent replay attacks */
BYTE nonce[ CRYPT_MAX_HASHSIZE ];
int nonceSize;
} RTCS_PROTOCOL_INFO;
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Check for a valid-looking RTCS request/response header */
static const FAR_BSS OID_SELECTION envelopeOIDselection[] = {
{ OID_CRYPTLIB_RTCSREQ, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_UNWRAP },
{ OID_CRYPTLIB_RTCSRESP, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_UNWRAP },
{ OID_CRYPTLIB_RTCSRESP_EXT, CRYPT_UNUSED, CRYPT_UNUSED, ACTION_UNWRAP },
{ OID_CMS_SIGNEDDATA, 0, 3, ACTION_SIGN },
{ OID_CMS_ENVELOPEDDATA, 0, 2, ACTION_CRYPT },
{ NULL, 0, 0, 0 }
};
static int checkRtcsHeader( const void *rtcsData, const int rtcsDataLength,
ACTION_TYPE *actionType )
{
STREAM stream;
int status;
*actionType = ACTION_NONE;
/* We've got a valid response, check the CMS encapsulation */
sMemConnect( &stream, rtcsData, rtcsDataLength );
status = readCMSheader( &stream, envelopeOIDselection, NULL, FALSE );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
*actionType = status;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Client-side Functions *
* *
****************************************************************************/
/* Send a request to an RTCS server */
static int sendClientRequest( SESSION_INFO *sessionInfoPtr )
{
RESOURCE_DATA msgData;
int status;
/* Get the encoded request data and wrap it up for sending */
setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_ICERTFORMAT_DATA );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't get RTCS request data from RTCS request object" );
status = envelopeWrap( sessionInfoPtr->receiveBuffer, msgData.length,
sessionInfoPtr->receiveBuffer,
&sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->receiveBufSize,
CRYPT_FORMAT_CMS, CRYPT_CONTENT_RTCSREQUEST,
CRYPT_UNUSED );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't CMS wrap RTCS request data" );
DEBUG_DUMP( "rtcs_req", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
/* Send the request to the responder */
return( writePkiDatagram( sessionInfoPtr ) );
}
/* Read the response from the RTCS server */
static int readServerResponse( SESSION_INFO *sessionInfoPtr )
{
CRYPT_CERTIFICATE iCmsAttributes;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
ACTION_TYPE actionType;
BYTE nonceBuffer[ CRYPT_MAX_HASHSIZE ];
int dataLength, sigResult, status;
/* Read the response from the responder */
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusError( status ) )
return( status );
DEBUG_DUMP( "rtcs_resp", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
status = checkRtcsHeader( sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd, &actionType );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status, "Invalid RTCS response header" );
if( actionType != ACTION_SIGN )
retExt( sessionInfoPtr, status,
"Unexpected RTCS encapsulation type %d", actionType );
/* Sig.check the data using the responder's key */
status = envelopeSigCheck( sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->receiveBuffer, &dataLength,
sessionInfoPtr->receiveBufSize,
CRYPT_UNUSED, &sigResult, NULL,
&iCmsAttributes );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Invalid RTCS response data (CMS enveloped data)" );
/* Make sure that the nonce in the response matches the one in the
request */
setMessageData( &msgData, nonceBuffer, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_CMS_NONCE );
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA responseMsgData;
BYTE responseNonceBuffer[ CRYPT_MAX_HASHSIZE ];
setMessageData( &responseMsgData, responseNonceBuffer,
CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_GETATTRIBUTE_S, &responseMsgData,
CRYPT_CERTINFO_CMS_NONCE );
if( cryptStatusOK( status ) && \
( msgData.length < 4 || \
msgData.length != responseMsgData.length || \
memcmp( msgData.data, responseMsgData.data, msgData.length ) ) )
status = CRYPT_ERROR_SIGNATURE;
}
krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertRequest = CRYPT_ERROR;
if( cryptStatusError( status ) )
/* The response doesn't contain a nonce or it doesn't match what
we sent, we can't trust it. The best error that we can return
here is a signature error to indicate that the integrity check
failed */
retExt( sessionInfoPtr, status,
( status != CRYPT_ERROR_SIGNATURE ) ? \
"RTCS response doesn't contain a nonce" : \
"RTCS response nonce doesn't match the one in the request" );
/* Everything is OK, import the response */
setMessageCreateObjectIndirectInfo( &createInfo,
sessionInfoPtr->receiveBuffer, dataLength,
CRYPT_CERTTYPE_RTCS_RESPONSE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status, "Invalid RTCS response contents" );
sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Server-side Functions *
* *
****************************************************************************/
/* Read a request from an RTCS client */
static int readClientRequest( SESSION_INFO *sessionInfoPtr,
RTCS_PROTOCOL_INFO *protocolInfo )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
ACTION_TYPE actionType;
int dataLength, status;
/*-----------------------------------------------------------------------*/
#ifdef SKIP_IO
{
FILE *filePtr = fopen( "/tmp/rtcs_sreq.der", "rb" );
sessionInfoPtr->receiveBufEnd = fread( sessionInfoPtr->receiveBuffer, 1,
sessionInfoPtr->receiveBufSize, filePtr );
fclose( filePtr );
status = sessionInfoPtr->receiveBufEnd;
}
#endif /* SKIP_IO */
/*-----------------------------------------------------------------------*/
/* Read the request data from the client. We don't write an error
response at this initial stage to prevent scanning/DOS attacks
(vir sapit qui pauca loquitur) */
status = readPkiDatagram( sessionInfoPtr );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -