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

📄 cmp.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:
	   session this will already have been checked in clientStartup(), but
	   if it's coming from the PnPPKI wrapper it doesn't go through the
	   startup checks each time so we double-check here.  Since any problem
	   is just a one-off programming error, we only need a debug assertion
	   rather than a hardcoded check */
	assert( cmpInfo->requestType != CRYPT_REQUESTTYPE_NONE );
	assert( cmpInfo->requestType == CRYPT_REQUESTTYPE_PKIBOOT || \
			sessionInfoPtr->iCertRequest != CRYPT_ERROR );
	assert( cmpInfo->requestType == CRYPT_REQUESTTYPE_PKIBOOT || \
			sessionInfoPtr->iAuthInContext != CRYPT_ERROR );

	/* Initialise the client-side protocol state info */
	initProtocolInfo( &protocolInfo, 
					  sessionInfoPtr->flags & SESSION_ISCRYPTLIB );
	status = initClientInfo( sessionInfoPtr, &protocolInfo );
	if( cryptStatusError( status ) )
		{
		destroyProtocolInfo( &protocolInfo );
		return( status );
		}

	/* Write the message into the session buffer and send it to the server */
	status = writePkiMessage( sessionInfoPtr, &protocolInfo, 
							  ( cmpInfo->requestType == \
									CRYPT_REQUESTTYPE_PKIBOOT ) ? \
							  CMPBODY_GENMSG : CMPBODY_NORMAL );
	if( cryptStatusOK( status ) )
		{
		DEBUG_DUMP_CMP( protocolInfo.operation, 1, sessionInfoPtr );
		if( ( protocolInfo.operation == CTAG_PB_GENM || \
			  protocolInfo.operation == CTAG_PB_RR ) && \
			!( sessionInfoPtr->protocolFlags & CMP_PFLAG_RETAINCONNECTION ) )
			/* There's no confirmation handshake for PKIBoot or a revocation 
			   request so we mark this as the last message if required */
			sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, NULL,
					TRUE );
		status = writePkiDatagram( sessionInfoPtr );
		}
	if( cryptStatusError( status ) )
		{
		destroyProtocolInfo( &protocolInfo );
		return( status );
		}

	/* Read the server response */
	status = readPkiDatagram( sessionInfoPtr );
	if( cryptStatusOK( status ) )
		{
		DEBUG_DUMP_CMP( protocolInfo.operation, 2, sessionInfoPtr );
		status = readPkiMessage( sessionInfoPtr, &protocolInfo, 
								 reqToResp( protocolInfo.operation ) );
		}
	if( cryptStatusOK( status ) && protocolInfo.operation == CTAG_PB_GENM )
		{
		/* It's a PKIBoot, add the trusted certs.  If the user wants the 
		   setting made permanent, they need to flush the config to disk 
		   after the session has completed */
		status = krnlSendMessage( sessionInfoPtr->ownerHandle,
								  IMESSAGE_SETATTRIBUTE, 
								  &sessionInfoPtr->iCertResponse,
								  CRYPT_IATTRIBUTE_CTL );
		if( status == CRYPT_ERROR_INITED )
			/* If the certs are already present, trying to add them again
			   isn't an error */
			status = CRYPT_OK;
		}
	if( cryptStatusError( status ) )
		{
		destroyProtocolInfo( &protocolInfo );
		return( status );
		}

	/* If it's a transaction type that doesn't need a confirmation, we're 
	   done */
	if( protocolInfo.operation == CTAG_PB_GENM || \
		protocolInfo.operation == CTAG_PB_RR )
		{
		if( protocolInfo.iMacContext != CRYPT_ERROR )
			{
			/* 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 );
		}

	/* Exchange confirmation data with the server */
	if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_RETAINCONNECTION ) )
		sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, NULL, 
				TRUE );
	status = writePkiMessage( sessionInfoPtr, &protocolInfo,
							  CMPBODY_CONFIRMATION );
	if( cryptStatusOK( status ) )
		{
		DEBUG_DUMP_CMP( protocolInfo.operation, 3, sessionInfoPtr );
		status = writePkiDatagram( sessionInfoPtr );
		}
	if( cryptStatusOK( status ) )
		status = readPkiDatagram( sessionInfoPtr );
	if( cryptStatusOK( status ) )
		{
		DEBUG_DUMP_CMP( protocolInfo.operation, 4, sessionInfoPtr );
		status = readPkiMessage( sessionInfoPtr, &protocolInfo, CTAG_PB_PKICONF );
		}
	if( cryptStatusOK( status ) && protocolInfo.iMacContext != CRYPT_ERROR )
		{
		/* Remember the authentication context in case we can reuse it for 
		   another transaction */
		cmpInfo->savedMacContext = protocolInfo.iMacContext;
		protocolInfo.iMacContext = CRYPT_ERROR;
		}
	destroyProtocolInfo( &protocolInfo );
	return( status );
	}

static int clientTransactWrapper( SESSION_INFO *sessionInfoPtr )
	{
	if( sessionInfoPtr->sessionCMP->flags & CMP_PFLAG_PNPPKI )
		{
		int status;

		/* If we're doing plug-and-play PKI, point the transaction function 
		   at the client-transact function to execute the PnP steps, then 
		   reset it back to the PnP wrapper after we're done */
		sessionInfoPtr->transactFunction = clientTransact;
		status = pnpPkiSession( sessionInfoPtr );
		sessionInfoPtr->transactFunction = clientTransactWrapper;
		return( status );
		}
	return( clientTransact( sessionInfoPtr ) );
	}

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 = \
				findSessionAttribute( sessionInfoPtr->attributeList,
									  CRYPT_SESSINFO_USERNAME );
	int status;

	/* 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 */
			protocolInfo.userIDsize = \
					decodePKIUserValue( protocolInfo.userID,
										userNamePtr->value,
										userNamePtr->valueLength );
		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( cryptStatusError( status ) )
		{
		sendErrorResponse( sessionInfoPtr, &protocolInfo, status );
		destroyProtocolInfo( &protocolInfo );
		return( status );
		}
	DEBUG_DUMP_CMP( protocolInfo.operation, 1, sessionInfoPtr );
	cmpInfo->requestType = reqToClibReq( protocolInfo.operation );

	/* 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 );
			}
		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( sessionInfoPtr, status, "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 )
			retExtEx( sessionInfoPtr, status, sessionInfoPtr->cryptKeyset,
					  "Initialisation request couldn't be added to the "
					  "cert store because another initialisation request "
					  "has already been processed for this user" );
		retExtEx( sessionInfoPtr, status, 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 );
		retExtEx( sessionInfoPtr, status, 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 );
		}
	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 )
			{

⌨️ 快捷键说明

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