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

📄 cmp.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
	assert( sessionInfoPtr->cmpRequestType != CRYPT_REQUESTTYPE_NONE );
	assert( sessionInfoPtr->cmpRequestType == CRYPT_REQUESTTYPE_PKIBOOT || \
			sessionInfoPtr->iCertRequest != CRYPT_ERROR );
	assert( sessionInfoPtr->cmpRequestType == 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, 
							  ( sessionInfoPtr->cmpRequestType == \
									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 */
			sessionInfoPtr->cmpSavedMacContext = 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 */
		sessionInfoPtr->cmpSavedMacContext = protocolInfo.iMacContext;
		protocolInfo.iMacContext = CRYPT_ERROR;
		}
	destroyProtocolInfo( &protocolInfo );
	return( status );
	}

static int clientTransactWrapper( SESSION_INFO *sessionInfoPtr )
	{
	if( sessionInfoPtr->flags & SESSION_ISPNPPKI )
		{
		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 )
	{
	MESSAGE_CERTMGMT_INFO certMgmtInfo;
	CMP_PROTOCOL_INFO protocolInfo;
	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( sessionInfoPtr->userNameLength > 0 )
		{
		/* 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( sessionInfoPtr->flags & SESSION_ISENCODEDUSERID )
			/* It's a cryptlib-style encoded user ID, decode it into its 
			   binary value */
			protocolInfo.userIDsize = \
					decodePKIUserValue( protocolInfo.userID,
										sessionInfoPtr->userName,
										sessionInfoPtr->userNameLength );
		else
			{
			/* It's a standard user ID, use it as is */
			memcpy( protocolInfo.userID, sessionInfoPtr->userName, 
					sessionInfoPtr->userNameLength );
			protocolInfo.userIDsize = sessionInfoPtr->userNameLength;
			}
		protocolInfo.iMacContext = sessionInfoPtr->cmpSavedMacContext;
		sessionInfoPtr->cmpSavedMacContext = 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 );
	sessionInfoPtr->cmpRequestType = 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( sessionInfoPtr->cmpRequestType == 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) and add it to the cert store */
	if( protocolInfo.operation != CTAG_PB_RR && !protocolInfo.cryptOnlyKey )
		status = krnlSendMessage( sessionInfoPtr->iCertRequest,
								  IMESSAGE_CRT_SIGCHECK, NULL, CRYPT_UNUSED );
	if( cryptStatusError( status ) )
		strcpy( sessionInfoPtr->errorMessage, 
				"Request signature check failed" );
	else
		{
		MESSAGE_KEYMGMT_INFO setkeyInfo;

		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 ) )
			strcpy( sessionInfoPtr->errorMessage, 
					"Request couldn't be added to cert store" );
		}
	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 );
		return( status );
		}

	/* 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 );
		retExt( sessionInfoPtr, status, "%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 */
		sessionInfoPtr->cmpSavedMacContext = 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 )
			{
			writePkiMessage( sessionInfoPtr, &protocolInfo, CMPBODY_ACK );
			writePkiDatagram( sessionInfoPtr );
			}
		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

⌨️ 快捷键说明

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