📄 scep.c
字号:
/* Complete the user-supplied PKCS #10 request by adding SCEP-internal
attributes and information */
static int createScepRequest( SESSION_INFO *sessionInfoPtr )
{
RESOURCE_DATA msgData;
int status;
/* Add the password to the PKCS #10 request as a ChallengePassword
attribute and sign the request. We always send this in its
ASCII string form even if it's an encoded value because the
ChallengePassword attribute has to be a text string */
setMessageData( &msgData, sessionInfoPtr->password,
sessionInfoPtr->passwordLength );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_CHALLENGEPASSWORD );
if( cryptStatusOK( status ) )
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_CRT_SIGN, NULL,
sessionInfoPtr->privateKey );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't finalise PKCS #10 cert request" );
return( CRYPT_OK );
}
/* Create SCEP signing attributes */
static int createScepAttributes( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo,
CRYPT_CERTIFICATE *iScepAttributes,
const BOOLEAN isInitiator,
const int scepStatus )
{
CRYPT_CERTIFICATE iCmsAttributes;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
int status;
/* Clear return value */
*iScepAttributes = CRYPT_ERROR;
/* Create the signing attributes needed by SCEP and add the user name/
transaction ID and message 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;
setMessageData( &msgData, sessionInfoPtr->userName,
sessionInfoPtr->userNameLength );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_TRANSACTIONID );
if( cryptStatusOK( status ) )
{
const char *messageType = isInitiator ? MESSAGETYPE_PKCSREQ : \
MESSAGETYPE_CERTREP;
setMessageData( &msgData, ( void * ) messageType,
strlen( messageType ) );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_MESSAGETYPE );
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Add the message status */
if( !isInitiator && cryptStatusError( scepStatus ) )
{
const char *failInfo = ( scepStatus == CRYPT_ERROR_SIGNATURE ) ? \
MESSAGEFAILINFO_BADMESSAGECHECK : MESSAGEFAILINFO_BADREQUEST;
/* SCEP provides an extremely limited set of error codes so there's
not much that we can return in the way of additional failure
info */
setMessageData( &msgData, ( void * ) failInfo, strlen( failInfo ) );
krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_FAILINFO );
setMessageData( &msgData, MESSAGESTATUS_FAILURE,
strlen( MESSAGESTATUS_FAILURE ) );
}
else
setMessageData( &msgData, MESSAGESTATUS_SUCCESS,
strlen( MESSAGESTATUS_SUCCESS ) );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_PKISTATUS );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Add the nonce, identified as a sender nonce if we're the initiator and
a recipient nonce if we're the responder */
if( isInitiator )
{
/* If we're the initiator, generate a new nonce */
setMessageData( &msgData, protocolInfo->nonce, SCEP_NONCE_SIZE );
krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
protocolInfo->nonceSize = SCEP_NONCE_SIZE;
}
else
/* We're the responder, use the initiator's nonce */
setMessageData( &msgData, protocolInfo->nonce,
protocolInfo->nonceSize );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
&msgData, isInitiator ? \
CRYPT_CERTINFO_SCEP_SENDERNONCE : \
CRYPT_CERTINFO_SCEP_RECIPIENTNONCE );
if( cryptStatusError( status ) )
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
else
*iScepAttributes = iCmsAttributes;
return( status );
}
/* 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, and we don't return extended error information since
this would overwrite the information for the error that caused us to
return an error response */
static int sendErrorResponse( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo,
const int scepStatus )
{
CRYPT_CERTIFICATE iCmsAttributes;
int status;
/* Sign the error response using the CA key and SCEP attributes */
status = createScepAttributes( sessionInfoPtr, protocolInfo,
&iCmsAttributes, FALSE, scepStatus );
if( cryptStatusError( status ) )
return( status );
status = envelopeSign( sessionInfoPtr->receiveBuffer, 0,
sessionInfoPtr->receiveBuffer,
&sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->receiveBufSize,
CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey,
iCmsAttributes );
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
DEBUG_DUMP( "scep_srespx", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
/* Return the response to the client */
sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, NULL, TRUE );
writePkiDatagram( sessionInfoPtr );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Client-side Functions *
* *
****************************************************************************/
/* Create an SCEP request message */
static int createPkcsRequest( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo )
{
CRYPT_CERTIFICATE iCmsAttributes;
RESOURCE_DATA msgData;
int dataLength, status;
/* Extract the request data into the session buffer */
setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufSize );
status = krnlSendMessage( sessionInfoPtr->iCertRequest,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't get PKCS #10 request data from SCEP request object" );
DEBUG_DUMP( "scep_req0", sessionInfoPtr->receiveBuffer, msgData.length );
/* Phase 1: Encrypt the data using the CA's key */
status = envelopeWrap( sessionInfoPtr->receiveBuffer, msgData.length,
sessionInfoPtr->receiveBuffer, &dataLength,
sessionInfoPtr->receiveBufSize,
CRYPT_FORMAT_CMS, CRYPT_UNUSED,
sessionInfoPtr->iAuthInContext );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't encrypt request data with CA key" );
DEBUG_DUMP( "scep_req1", sessionInfoPtr->receiveBuffer, dataLength );
/* Create the SCEP signing attributes */
status = createScepAttributes( sessionInfoPtr, protocolInfo,
&iCmsAttributes, TRUE, CRYPT_OK );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't create SCEP request signing attributes" );
/* Phase 2: Sign the data using the self-signed cert and SCEP attributes */
status = envelopeSign( sessionInfoPtr->receiveBuffer, dataLength,
sessionInfoPtr->receiveBuffer,
&sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->receiveBufSize,
CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey,
iCmsAttributes );
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't sign request data with ephemeral SCEP "
"certificate" );
DEBUG_DUMP( "scep_req2", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
return( CRYPT_OK );
}
/* Check an SCEP response message */
static int checkPkcsResponse( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo )
{
CRYPT_CERTIFICATE iCmsAttributes;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
BYTE buffer[ CRYPT_MAX_HASHSIZE ];
int dataLength, sigResult, value, status;
/* Phase 1: Sig.check the data using the CA's key */
DEBUG_DUMP( "scep_resp2", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
status = envelopeSigCheck( sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->receiveBuffer, &dataLength,
sessionInfoPtr->receiveBufSize,
sessionInfoPtr->iAuthInContext, &sigResult,
NULL, &iCmsAttributes );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Invalid CMS signed data in CA response" );
DEBUG_DUMP( "scep_res1", sessionInfoPtr->receiveBuffer, dataLength );
if( cryptStatusError( sigResult ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
retExt( sessionInfoPtr, sigResult,
"Bad signature on CA response data" );
}
/* Check that the returned nonce matches our initial nonce. It's now
identified as a recipient nonce since it's coming from the
responder */
setMessageData( &msgData, buffer, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_SCEP_RECIPIENTNONCE );
if( cryptStatusError( status ) || \
msgData.length != protocolInfo->nonceSize || \
memcmp( buffer, protocolInfo->nonce, protocolInfo->nonceSize ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
"Returned nonce doesn't match our original nonce" );
}
/* Check that the operation succeeded */
status = getStatusValue( iCmsAttributes,
CRYPT_CERTINFO_SCEP_MESSAGETYPE, &value );
if( cryptStatusOK( status ) && value != MESSAGETYPE_CERTREP_VALUE )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusOK( status ) )
status = getStatusValue( iCmsAttributes,
CRYPT_CERTINFO_SCEP_PKISTATUS, &value );
if( cryptStatusOK( status ) && value != MESSAGESTATUS_SUCCESS_VALUE )
{
sessionInfoPtr->errorCode = value;
status = getStatusValue( iCmsAttributes,
CRYPT_CERTINFO_SCEP_FAILINFO, &value );
if( cryptStatusOK( status ) )
sessionInfoPtr->errorCode = value;
status = CRYPT_ERROR_FAILED;
}
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"SCEP server reports that certificate issue operation "
"failed" );
/* Phase 2: Decrypt the data using our self-signed key */
status = envelopeUnwrap( sessionInfoPtr->receiveBuffer, dataLength,
sessionInfoPtr->receiveBuffer, &dataLength,
sessionInfoPtr->receiveBufSize,
sessionInfoPtr->privateKey );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Couldn't decrypt CMS enveloped data in CA response" );
DEBUG_DUMP( "scep_res0", sessionInfoPtr->receiveBuffer, dataLength );
/* Finally, import the returned cert(s) as a PKCS #7 chain */
setMessageCreateObjectIndirectInfo( &createInfo,
sessionInfoPtr->receiveBuffer, dataLength,
CRYPT_CERTTYPE_CERTCHAIN );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Invalid PKCS #7 certificate chain in CA response" );
sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Server-side Functions *
* *
****************************************************************************/
/* Check an SCEP request message */
static int checkPkcsRequest( SESSION_INFO *sessionInfoPtr,
SCEP_PROTOCOL_INFO *protocolInfo )
{
CRYPT_CERTIFICATE iCmsAttributes;
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
int dataLength, sigResult, value, status;
/* Phase 1: Sig.check the self-signed data */
DEBUG_DUMP( "scep_sreq2", sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd );
status = envelopeSigCheck( sessionInfoPtr->receiveBuffer,
sessionInfoPtr->receiveBufEnd,
sessionInfoPtr->receiveBuffer, &dataLength,
sessionInfoPtr->receiveBufSize,
CRYPT_UNUSED, &sigResult,
&protocolInfo->iScepCert, &iCmsAttributes );
if( cryptStatusError( status ) )
retExt( sessionInfoPtr, status,
"Invalid CMS signed data in client request" );
DEBUG_DUMP( "scep_sreq1", sessionInfoPtr->receiveBuffer, dataLength );
if( cryptStatusError( sigResult ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
retExt( sessionInfoPtr, sigResult,
"Bad signature on client request data" );
}
/* Make sure that the client cert is valid for signing and decryption.
In effect the signing capability has already been checked by the fact
that the cert signed the request, but we do an explicit check here
just to be thorough */
status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK,
NULL, MESSAGE_CHECK_PKC_SIGCHECK );
if( cryptStatusOK( status ) )
status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK,
NULL, MESSAGE_CHECK_PKC_ENCRYPT );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
"Ephemeral SCEP client certificate isn't valid for "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -