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

📄 cmp.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
	return( status );
	}

static int serverTransact( SESSION_INFO *sessionInfoPtr )
	{
	CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
	MESSAGE_CERTMGMT_INFO certMgmtInfo;
	MESSAGE_KEYMGMT_INFO setkeyInfo;
	CMP_PROTOCOL_INFO protocolInfo;
	const ATTRIBUTE_LIST *userNamePtr = \
				findSessionInfo( sessionInfoPtr->attributeList,
								 CRYPT_SESSINFO_USERNAME );
	int status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );

	/* Initialise the server-side protocol state info.  Since the server 
	   doesn't have a user ID (it uses what the client sends it), we set the
	   userID-sent flag to indicate that it's been implicitly exchanged */
	initProtocolInfo( &protocolInfo,
					  sessionInfoPtr->flags & SESSION_ISCRYPTLIB );
	protocolInfo.authContext = sessionInfoPtr->privateKey;
	sessionInfoPtr->protocolFlags |= CMP_PFLAG_USERIDSENT;
	if( userNamePtr != NULL )
		{
		/* There's already user info present from a previous transaction, 
		   try and re-use the info from it (this can be overridden by the
		   client sending us new user info) */
		if( userNamePtr->flags & ATTR_FLAG_ENCODEDVALUE )
			{
			/* It's a cryptlib-style encoded user ID, decode it into its 
			   binary value */
			status = decodePKIUserValue( protocolInfo.userID,
										 CRYPT_MAX_TEXTSIZE,
										 &protocolInfo.userIDsize,
										 userNamePtr->value,
										 userNamePtr->valueLength );
			if( cryptStatusError( status ) )
				retIntError();
			}
		else
			{
			/* It's a standard user ID, use it as is */
			memcpy( protocolInfo.userID, userNamePtr->value, 
					userNamePtr->valueLength );
			protocolInfo.userIDsize = userNamePtr->valueLength;
			}
		protocolInfo.iMacContext = cmpInfo->savedMacContext;
		cmpInfo->savedMacContext = CRYPT_ERROR;
		}

	/* Read the initial message from the client.  We don't write an error
	   response at the initial read stage to prevent scanning/DOS attacks 
	   (vir sapit qui pauca loquitur) */
	status = readPkiDatagram( sessionInfoPtr );
	if( cryptStatusError( status ) )
		{
		destroyProtocolInfo( &protocolInfo );
		return( status );
		}
	status = readPkiMessage( sessionInfoPtr, &protocolInfo,
							 CRYPT_UNUSED );
	if( cryptStatusOK( status ) )
		{
		cmpInfo->requestType = reqToClibReq( protocolInfo.operation );
		if( cryptStatusError( cmpInfo->requestType ) )
			status = cmpInfo->requestType;
		}
	if( cryptStatusError( status ) )
		{
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroyProtocolInfo( &protocolInfo );
		return( status );
		}
	DEBUG_DUMP_CMP( protocolInfo.operation, 1, sessionInfoPtr );

	/* If it's a PKIBoot request, send the PKIBoot response and retry the 
	   read unless the client closes the stream.  This assumes that the 
	   client will generally send a PKIBoot request in conjunction with a 
	   cert management request (i.e. as part of a PnP PKI transaction), 
	   which allows us to reuse the user authentication info to process the 
	   request that follows the PKIBoot */
	if( cmpInfo->requestType == CRYPT_REQUESTTYPE_PKIBOOT )
		{
		int streamState;

		/* Handle the PKIBoot request */
		status = writePkiMessage( sessionInfoPtr, &protocolInfo, 
								  CMPBODY_GENMSG );
		if( cryptStatusOK( status ) )
			{
			DEBUG_DUMP_CMP( CTAG_PB_GENM, 2, sessionInfoPtr );
			status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
									   CMP_CONTENT_TYPE_LEN );
			}
		if( cryptStatusError( status ) )
			{
			sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
			destroyProtocolInfo( &protocolInfo );
			return( status );
			}

		/* Check whether the client left the stream open.  If they haven't,
		   it was a standalone PKIBoot request and we're done */
		sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONNSTATE, 
				&streamState, 0 );
		if( !streamState )
			{
			destroyProtocolInfo( &protocolInfo );
			return( CRYPT_OK );
			}

		/* Process the request that follows the PKIBoot.  If the client
		   was only performing a standardlone PKIBoot but left the 
		   connection open in case further transactions were necesary
		   later, but then shut down the connection without performing
		   any further transactions, we'll get a read error at this point,
		   which we convert into a OK status */
		status = readPkiDatagram( sessionInfoPtr );
		if( cryptStatusOK( status ) )
			status = readPkiMessage( sessionInfoPtr, &protocolInfo,
									 CRYPT_UNUSED );
		if( cryptStatusError( status ) )
			{
			sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_CONNSTATE, 
					&streamState, 0 );
			if( streamState )
				/* Only send an error response if the stream is still open */
				sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
			destroyProtocolInfo( &protocolInfo );
			return( streamState ? status : CRYPT_OK );
			}
		}

	/* Make sure that the signature on the request data is OK (unless it's a 
	   non-signed revocation request or a request for an encryption-only 
	   key) */
	if( protocolInfo.operation != CTAG_PB_RR && !protocolInfo.cryptOnlyKey )
		status = krnlSendMessage( sessionInfoPtr->iCertRequest,
								  IMESSAGE_CRT_SIGCHECK, NULL, CRYPT_UNUSED );
	if( cryptStatusError( status ) )
		{
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroyProtocolInfo( &protocolInfo );
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Request signature check failed" ) );
		}

	/* Add the request to the cert store */
	setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0,
						   ( protocolInfo.operation == CTAG_PB_KUR ) ? \
								KEYMGMT_FLAG_UPDATE : KEYMGMT_FLAG_NONE );
	setkeyInfo.cryptHandle = sessionInfoPtr->iCertRequest;
	status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
							  IMESSAGE_KEY_SETKEY, &setkeyInfo, 
							  KEYMGMT_ITEM_REQUEST );
	if( cryptStatusError( status ) )
		{
		/* If the cert store reports that there's a problem with the request,
		   convert it to an invalid request error */
		if( status == CRYPT_ARGERROR_NUM1 )
			status = CRYPT_ERROR_INVALID;

		/* A common error condition at this point arises when the user tries 
		   to submit a second initialisation request for a PKI user that has 
		   already had a cert issued for it, so we catch this condition and 
		   provide a more informative error response than the generic 
		   message */
		if( protocolInfo.operation == CTAG_PB_IR && \
			status == CRYPT_ERROR_DUPLICATE )
			protocolInfo.pkiFailInfo = CMPFAILINFO_DUPLICATECERTREQ;

		/* Clean up and return the appropriate error information to the
		   caller */
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroyProtocolInfo( &protocolInfo );
		if( protocolInfo.operation == CTAG_PB_IR && \
			status == CRYPT_ERROR_DUPLICATE )
			retExtObj( status, 
					   ( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
						 "Initialisation request couldn't be added to the "
						 "cert store because another initialisation request "
						 "has already been processed for this user" ) );
		retExtObj( status, 
				   ( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
					 "Request couldn't be added to the cert store" ) );
		}

	/* Create or revoke a cert from the request */
	if( protocolInfo.operation != CTAG_PB_RR )
		{
		setMessageCertMgmtInfo( &certMgmtInfo, sessionInfoPtr->privateKey,
								sessionInfoPtr->iCertRequest );
		status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
								  IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
								  CRYPT_CERTACTION_CERT_CREATION );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->iCertResponse = certMgmtInfo.cryptCert;
		}
	else
		{
		setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
								sessionInfoPtr->iCertRequest );
		status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
								  IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
								  CRYPT_CERTACTION_REVOKE_CERT );
		}
	if( cryptStatusError( status ) )
		{
		/* If the cert store reports that there's a problem with the request,
		   convert it to an invalid request error */
		if( status == CRYPT_ARGERROR_NUM1 )
			status = CRYPT_ERROR_INVALID;
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroyProtocolInfo( &protocolInfo );
		retExtObj( status, 
				   ( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
					 "%s was denied by cert store",
					 ( protocolInfo.operation != CTAG_PB_RR ) ? \
						"Cert issue" : "Revocation" ) );
		}

	/* Send the response to the client */
	status = writePkiMessage( sessionInfoPtr, &protocolInfo, CMPBODY_NORMAL );
	if( cryptStatusOK( status ) )
		{
		DEBUG_DUMP_CMP( protocolInfo.operation, 2, sessionInfoPtr );
		status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
								   CMP_CONTENT_TYPE_LEN );
		}
	if( cryptStatusError( status ) )
		{
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		if( protocolInfo.operation != CTAG_PB_RR )
			{
			/* If there was a problem, drop the partially-issued cert.  We
			   don't have to go all the way and do a full reversal because
			   it hasn't really been issued yet since we couldn't get it to
			   the client.  In addition we don't do anything with the return
			   status since we want to return the status that caused the
			   problem, not the result of the drop operation */
			setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
									sessionInfoPtr->iCertResponse );
			krnlSendMessage( sessionInfoPtr->cryptKeyset,
							 IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
							 CRYPT_CERTACTION_CERT_CREATION_DROP );
			}
		destroyProtocolInfo( &protocolInfo );
		return( status );
		}

	/* If it's a transaction type that doesn't need a confirmation, we're 
	   done */
	if( protocolInfo.operation == CTAG_PB_RR )
		{
		/* Remember the authentication context in case we can reuse it for 
		   another transaction */
		cmpInfo->savedMacContext = protocolInfo.iMacContext;
		protocolInfo.iMacContext = CRYPT_ERROR;
		destroyProtocolInfo( &protocolInfo );
		return( CRYPT_OK );
		}

	/* Read back the confirmation from the client */
	status = readPkiDatagram( sessionInfoPtr );
	if( cryptStatusOK( status ) )
		status = readPkiMessage( sessionInfoPtr, &protocolInfo,
								 CTAG_PB_CERTCONF );
	if( cryptStatusError( status ) || \
		protocolInfo.status == CRYPT_ERROR )
		{
		int localStatus;

		/* If the client rejected the cert this isn't a protocol error so we
		   send back a standard ack, otherwise we send back an error response */
		if( protocolInfo.status == CRYPT_ERROR )
			{
			localStatus = writePkiMessage( sessionInfoPtr, &protocolInfo, 
										   CMPBODY_ACK );
			if( cryptStatusOK( localStatus ) )
				localStatus = writePkiDatagram( sessionInfoPtr, 
												CMP_CONTENT_TYPE,
												CMP_CONTENT_TYPE_LEN );
			if( cryptStatusOK( status ) )
				{
				/* If we haven't already got an error status set from an 
				   earlier operation, remember the status from sending the 
				   ack */
				status = localStatus;
				}
			}
		else
			sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroyProtocolInfo( &protocolInfo );

		/* Reverse the cert issue operation by revoking the incompletely-
		   issued cert.  We only return the status from this operation if
		   we're performing the reversal at the request of the user (i.e. if
		   the earlier operations succeeded), if not we return the status
		   that caused the failure earlier on */
		setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
								sessionInfoPtr->iCertResponse );
		localStatus = krnlSendMessage( sessionInfoPtr->cryptKeyset,
									IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
									CRYPT_CERTACTION_CERT_CREATION_REVERSE );
		return( cryptStatusOK( status ) ? localStatus : status );
		}
	DEBUG_DUMP_CMP( protocolInfo.operation, 3, sessionInfoPtr );

	/* The client has confirmed the cert creation, finalise it */
	setMessageCertMgmtInfo( &certMgmtInfo, CRYPT_UNUSED,
							sessionInfoPtr->iCertResponse );
	status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
							  IMESSAGE_KEY_CERTMGMT, &certMgmtInfo,
							  CRYPT_CERTACTION_CERT_CREATION_COMPLETE );
	if( cryptStatusError( status ) )
		{
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroyProtocolInfo( &protocolInfo );
		retExtObj( status, 
				   ( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
					 "Cert issue completion failed" ) );
		}

	/* Send back the final ack and clean up.  We remember the authentication 
	   context in case we can reuse it for another transaction */
	status = writePkiMessage( sessionInfoPtr, &protocolInfo, CMPBODY_ACK );
	if( cryptStatusOK( status ) )
		{
		DEBUG_DUMP_CMP( protocolInfo.operation, 4, sessionInfoPtr );
		status = writePkiDatagram( sessionInfoPtr, CMP_CONTENT_TYPE,
								   CMP_CONTENT_TYPE_LEN );
		}
	cmpInfo->savedMacContext = protocolInfo.iMacContext;
	protocolInfo.iMacContext = CRYPT_ERROR;
	destroyProtocolInfo( &protocolInfo );

	return( status );
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -