📄 ocsp.c
字号:
/****************************************************************************
* *
* cryptlib OCSP 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_OCSP
/* 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 */
/* OCSP query/response types */
typedef enum {
OCSPRESPONSE_TYPE_NONE, /* No response type */
OCSPRESPONSE_TYPE_OCSP, /* OCSP standard response */
OCSPRESPONSE_TYPE_LAST /* Last valid response type */
} OCSPRESPONSE_TYPE;
/* OCSP response status values */
enum { OCSP_RESP_SUCCESSFUL, OCSP_RESP_MALFORMEDREQUEST,
OCSP_RESP_INTERNALERROR, OCSP_RESP_TRYLATER, OCSP_RESP_DUMMY,
OCSP_RESP_SIGREQUIRED, OCSP_RESP_UNAUTHORISED };
/* OCSP protocol state information. This is passed around various
subfunctions that handle individual parts of the protocol */
typedef struct {
OCSPRESPONSE_TYPE responseType; /* Response type to return */
} OCSP_PROTOCOL_INFO;
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Deliver an Einladung betreff Kehrseite to the client. We don't bother
checking the return value since there's nothing that we can do in the
case of an error except close the connection, which we do anyway since
this is the last message */
static void sendErrorResponse( SESSION_INFO *sessionInfoPtr,
const void *responseData,
const int responseDataLength )
{
memcpy( sessionInfoPtr->receiveBuffer, responseData,
responseDataLength );
sessionInfoPtr->receiveBufEnd = responseDataLength;
writePkiDatagram( sessionInfoPtr );
}
/****************************************************************************
* *
* Client-side Functions *
* *
****************************************************************************/
/* OID information used to read responses */
static const FAR_BSS OID_SELECTION ocspOIDselection[] = {
{ OID_OCSP_RESPONSE_OCSP, CRYPT_UNUSED, CRYPT_UNUSED, OCSPRESPONSE_TYPE_OCSP },
{ NULL, 0, 0, 0 }
};
/* Send a request to an OCSP server */
static int sendClientRequest( SESSION_INFO *sessionInfoPtr )
{
RESOURCE_DATA msgData;
int status;
/* Get the encoded request data. We store this in the send buffer, which
at its minimum size is roughly two orders of magnitude larger than the
request */
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 OCSP request data from OCSP request object" );
sessionInfoPtr->receiveBufEnd = msgData.length;
DEBUG_DUMP( "ocsp_req", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
/* Send the request to the responder */
return( writePkiDatagram( sessionInfoPtr ) );
}
/* Read the response from the OCSP server */
static int readServerResponse( SESSION_INFO *sessionInfoPtr )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
STREAM stream;
BYTE nonceBuffer[ CRYPT_MAX_HASHSIZE ];
int value, dataStartPos, responseType, status;
/* Read the response from the responder */
status = readPkiDatagram( sessionInfoPtr );
if( cryptStatusError( status ) )
return( status );
DEBUG_DUMP( "ocsp_resp", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
/* Try and extract an OCSP status code from the returned object */
sMemConnect( &stream, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
readSequence( &stream, NULL );
status = readEnumerated( &stream, &value );
if( cryptStatusOK( status ) )
{
sessionInfoPtr->errorCode = value;
/* If it's an error status, try and translate it into something a
bit more meaningful (some of the translations are a bit
questionable, but it's better than the generic no vas response) */
switch( value )
{
case OCSP_RESP_SUCCESSFUL:
status = CRYPT_OK;
break;
case OCSP_RESP_TRYLATER:
status = CRYPT_ERROR_NOTAVAIL;
break;
case OCSP_RESP_SIGREQUIRED:
status = CRYPT_ERROR_SIGNATURE;
break;
case OCSP_RESP_UNAUTHORISED:
status = CRYPT_ERROR_PERMISSION;
break;
default:
status = CRYPT_ERROR_INVALID;
break;
}
}
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
/* We've got a valid response, read the [0] EXPLICIT SEQUENCE { OID,
OCTET STRING { encapsulation */
readConstructed( &stream, NULL, 0 ); /* responseBytes */
readSequence( &stream, NULL );
readOIDSelection( &stream, ocspOIDselection,/* responseType */
&responseType );
status = readGenericHole( &stream, NULL, DEFAULT_TAG );
dataStartPos = stell( &stream ); /* response */
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status, "Invalid OCSP response header" );
/* Import the response into an OCSP cert object */
setMessageCreateObjectIndirectInfo( &createInfo,
sessionInfoPtr->receiveBuffer + dataStartPos,
sessionInfoPtr->receiveBufEnd - dataStartPos,
CRYPT_CERTTYPE_OCSP_RESPONSE );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status, "Invalid OCSP response data" );
/* If the request went out with a nonce included (which it does by
default), make sure that it matches the nonce in the response. The
comparison is somewhat complex because for no known reason OCSP uses
integers rather than octet strings as nonces, so the nonce is encoded
using the integer analog to an OCTET STRING hole and may have a
leading zero byte if the high bit is set. Because of this we treat the
two as equal if they really are equal or if they differ only by a
leading zero byte (in practice the cert-handling code ensures that
the high bit is never set, but we leave the extra checking in there
just in case) */
setMessageData( &msgData, nonceBuffer, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_OCSP_NONCE );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA responseMsgData;
BYTE responseNonceBuffer[ CRYPT_MAX_HASHSIZE ];
setMessageData( &responseMsgData, responseNonceBuffer,
CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_GETATTRIBUTE_S, &responseMsgData,
CRYPT_CERTINFO_OCSP_NONCE );
if( cryptStatusError( status ) || msgData.length < 4 || \
!( ( msgData.length == responseMsgData.length && \
!memcmp( msgData.data, responseMsgData.data, msgData.length ) ) || \
( msgData.length == responseMsgData.length - 1 && \
responseNonceBuffer[ 0 ] == 0 && \
!memcmp( msgData.data, responseNonceBuffer + 1, msgData.length ) ) ) )
{
/* 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 */
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
cryptStatusError( status ) ? \
"OCSP response doesn't contain a nonce" : \
"OCSP response nonce doesn't match the one in the "
"request" );
}
}
krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT );
sessionInfoPtr->iCertRequest = CRYPT_ERROR;
sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
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 */
#define RESPONSE_SIZE 5
static const FAR_BSS BYTE respBadRequest[] = {
0x30, 0x03, 0x0A, 0x01, 0x01 /* Rejection, malformed request */
};
static const FAR_BSS BYTE respIntError[] = {
0x30, 0x03, 0x0A, 0x01, 0x02 /* Rejection, internal error */
};
/* Read a request from an OCSP client */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -