⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scep.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -