📄 ocsp.c
字号:
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENC_OBJDATA );
if( cryptStatusError( status ) )
return( status );
length = msgData.length;
DEBUG_DUMP( "ocsp_req", length );
/* Exchange data with the OCSP responder */
status = sNetConnect( &sessionInfoPtr->stream, STREAM_PROTOCOL_HTTP_TRANSACTION,
sessionInfoPtr->serverName, 80, timeout,
sessionInfoPtr->errorMessage, &sessionInfoPtr->errorCode );
if( cryptStatusError( status ) )
return( status );
status = exchangeClientDatagram( &sessionInfoPtr->stream,
sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize, length );
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 );
DEBUG_DUMP( "ocsp_resp", length );
/* Try and extract an OCSP status code from the returned object */
sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
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 va response) */
switch( value )
{
case OCSP_RESP_SUCCESSFUL:
status = CRYPT_OK;
break;
case OCSP_RESP_TRYLATER:
status = CRYPT_ERROR_BUSY;
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 );
readOID( &stream, OID_OCSP_RESPONSE ); /* responseType */
status = readGenericHole( &stream, NULL ); /* response */
dataStartPos = ( int ) stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* Import the response into an OCSP cert object */
setMessageCreateObjectIndirectInfo( &createInfo,
sessionInfoPtr->receiveBuffer + dataStartPos,
length - dataStartPos );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
/* If the request went out with a nonce included (which it does by
default), make sure it matches the nonce in the response. The
comparison is somewhat complex because the nonce is encoded using
the integer analog to an OCTET STRING hole so it 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 */
setResourceData( &msgData, nonceBuffer, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_OCSP_NONCE );
if( cryptStatusOK( status ) )
{
RESOURCE_DATA responseMsgData;
BYTE responseNonceBuffer[ CRYPT_MAX_HASHSIZE ];
setResourceData( &responseMsgData, responseNonceBuffer,
CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&responseMsgData, CRYPT_CERTINFO_OCSP_NONCE );
if( cryptStatusError( status ) || \
!( ( 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 we can return here
is a signature error to indicate that the integrity check
failed */
krnlSendNotifier( createInfo.cryptHandle,
RESOURCE_IMESSAGE_DECREFCOUNT );
return( CRYPT_ERROR_SIGNATURE );
}
}
sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
return( CRYPT_OK );
}
/* Start an OCSP 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_HTTP, 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 );
/* Read the client request */
status = readOcspRequest( sessionInfoPtr );
if( cryptStatusError( status ) )
{
sNetDisconnect( &sessionInfoPtr->stream );
return( status );
}
/* Generate a response and send it to the client */
status = sendOcspResponse( sessionInfoPtr );
krnlSendNotifier( sessionInfoPtr->iCertResponse,
RESOURCE_IMESSAGE_DECREFCOUNT );
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 )
{
CRYPT_CERTIFICATE *ocspResponsePtr = ( CRYPT_CERTIFICATE * ) data;
RESOURCE_DATA msgData = { NULL, 0 };
assert( type == CRYPT_SESSINFO_RESPONSE );
/* If we didn't get a response there's nothing to return */
if( sessionInfoPtr->iCertResponse == CRYPT_ERROR )
return( CRYPT_ERROR_NOTFOUND );
/* Make the information externally visible */
krnlSendNotifier( sessionInfoPtr->iCertResponse,
RESOURCE_IMESSAGE_INCREFCOUNT );
krnlSendMessage( sessionInfoPtr->iCertResponse,
RESOURCE_IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_FALSE,
CRYPT_IATTRIBUTE_INTERNAL );
*ocspResponsePtr = sessionInfoPtr->iCertResponse;
return( CRYPT_OK );
}
static int setAttributeFunction( SESSION_INFO *sessionInfoPtr,
const void *data,
const CRYPT_ATTRIBUTE_TYPE type )
{
CRYPT_CERTIFICATE ocspRequest = *( ( CRYPT_CERTIFICATE * ) data );
RESOURCE_DATA msgData = { NULL, 0 };
int requestType, status;
assert( type == CRYPT_SESSINFO_REQUEST );
/* Make sure we've been passed the correct request type */
status = krnlSendMessage( ocspRequest, RESOURCE_IMESSAGE_GETATTRIBUTE,
&requestType, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( status ) || \
requestType != CRYPT_CERTTYPE_OCSP_REQUEST )
return( CRYPT_ARGERROR_NUM1 );
/* Make sure everything is set up ready to go. Since OCSP requests
aren't signed like normal cert objects we can't just check the
immutable attribute but have to perform a dummy export for which
the cert export code will return an error status if there's a
problem with the request. Note that at this point the caller may
not have specified yet whether they want this encoded as a v1 or v2
request so we'll end up with the default format, however this
shouldn't be a problem since we're not asking for any data */
status = krnlSendMessage( ocspRequest, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENC_OBJDATA );
if( cryptStatusError( status ) )
return( CRYPT_ARGERROR_NUM1 );
/* If we haven't already got a server name explicitly set, try and get
it from the request */
if( !*sessionInfoPtr->serverName )
{
setResourceData( &msgData, sessionInfoPtr->serverName, MAX_URL_SIZE );
status = krnlSendMessage( ocspRequest, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_OCSPSERVER );
if( cryptStatusOK( status ) )
sessionInfoPtr->serverName[ msgData.length ] = '\0';
}
/* Add the request and increment its usage count */
krnlSendNotifier( ocspRequest, RESOURCE_IMESSAGE_INCREFCOUNT );
sessionInfoPtr->iCertRequest = ocspRequest;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
int setAccessMethodOCSP( 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 + -