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

📄 cmp_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
						  INOUT ERROR_INFO *errorInfo,
						  const BOOLEAN isServerInitialMessage )
	{
	CRYPT_ALGO_TYPE cryptAlgo, hashAlgo;
	BYTE buffer[ CRYPT_MAX_HASHSIZE + 8 ];
	int length, streamPos, endPos, status;

	/* Clear per-message state information */
	protocolInfo->userIDchanged = protocolInfo->certIDchanged = FALSE;
	protocolInfo->macInfoPos = CRYPT_ERROR;
	protocolInfo->senderDNPtr = NULL;
	protocolInfo->senderDNlength = 0;
	protocolInfo->headerRead = FALSE;

	/* Read the wrapper and skip the static info, which matches what we sent
	   and is protected by the MAC so there's little point in looking at
	   it */
	readSequence( stream, &length );
	endPos = stell( stream ) + length;
	readShortInteger( stream, NULL );		/* Version */
	if( !protocolInfo->isCryptlib )
		{
		/* The ID of the key used for integrity protection (or in general
		   the identity of the sender) can be specified either as the sender
		   DN or the senderKID or both, or in some cases even indirectly via
		   the transaction ID.  With no real guidance as to which one to use,
		   implementors are using any of these options to identify the key.
		   Since we need to check that the integrity-protection key we're
		   using is correct so that we can report a more appropriate error
		   than bad signature or bad data, we need to remember the sender DN
		   for later in case this is the only form of key identification
		   provided.  Unfortunately since the sender DN can't uniquely
		   identify a cert, if this is all we get then the caller can still
		   get a bad signature error, yet another one of CMPs many wonderful
		   features */
		status = readConstructed( stream, &protocolInfo->senderDNlength, 4 );
		if( cryptStatusOK( status ) && protocolInfo->senderDNlength > 0 )
			{
			status = sMemGetDataBlock( stream, &protocolInfo->senderDNPtr, 
									   protocolInfo->senderDNlength );
			if( cryptStatusOK( status ) )
				status = readUniversal( stream );/* Sender DN */
			}
		}
	else
		{
		/* cryptlib includes a proper certID so the whole signer
		   identification mess is avoided and we can ignore the sender DN */
		status = readUniversal( stream );	/* Sender DN */
		}
	if( cryptStatusOK( status ) )
		status = readUniversal( stream );	/* Recipient */
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_MESSAGETIME ) )
		status = readUniversal( stream );	/* Message time */
	if( cryptStatusError( status ) )
		{
		retExt( CRYPT_ERROR_BADDATA, 
				( CRYPT_ERROR_BADDATA, errorInfo, "Invalid PKI header" ) );
		}
	if( peekTag( stream ) != MAKE_CTAG( CTAG_PH_PROTECTIONALGO ) )
		{
		/* The message was sent without integrity protection, report it as
		   a signature error rather than the generic bad data error that
		   we'd get from the following read */
		retExt( CRYPT_ERROR_SIGNATURE,
				( CRYPT_ERROR_SIGNATURE, errorInfo, 
				  "Message was sent without integrity protection" ) );
		}
	status = readConstructed( stream, NULL, CTAG_PH_PROTECTIONALGO );
	if( cryptStatusError( status ) )
		{
		/* If there was a problem we should exit now since an error status
		   from the following readAlgoIDex() is interpreted to indicate the
		   presence of the weird Entrust MAC rather than a real error */
		retExt( status,
				( status, errorInfo, 
				  "Invalid integrity protection info in PKI header" ) );
		}
	streamPos = stell( stream );
	status = readAlgoIDext( stream, &cryptAlgo, &hashAlgo );
	if( cryptStatusOK( status ) )
		{
		/* It's a known signature algorithm, use the CA cert to verify it
		   rather than the MAC */
		protocolInfo->useMACreceive = FALSE;
		protocolInfo->hashAlgo = hashAlgo;
		}
	else
		{
		/* It's nothing normal, it must be the Entrust MAC algorithm info,
		   remember where it starts so that we can process it later */
		sClearError( stream );
		protocolInfo->macInfoPos = streamPos;
		readUniversal( stream );
		protocolInfo->useMACreceive = TRUE;
		}
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_SENDERKID ) )
		{								/* Sender protection keyID */
		if( isServerInitialMessage )
			{
			BYTE userID[ CRYPT_MAX_HASHSIZE + 8 ];
			int userIDsize;

			/* Read the PKI user ID that we'll need to handle the integrity
			   protection on the message */
			readConstructed( stream, NULL, CTAG_PH_SENDERKID );
			status = readOctetString( stream, userID, &userIDsize,
									  8, CRYPT_MAX_HASHSIZE );
			if( cryptStatusError( status ) )
				retExt( status,
						( status, errorInfo, 
						  "Invalid user ID in PKI header" ) );

			/* If there's already been a previous transaction (which means
			   that we have PKI user info present) and the current
			   transaction matches what was used in the previous one, we
			   don't have to update the user info */
			if( protocolInfo->userIDsize <= 0 || \
				protocolInfo->userIDsize != userIDsize || \
				memcmp( protocolInfo->userID, userID, userIDsize ) )
				{
				memcpy( protocolInfo->userID, userID, userIDsize );
				protocolInfo->userIDsize = userIDsize;
				protocolInfo->userIDchanged = TRUE;
				if( protocolInfo->iMacContext != CRYPT_ERROR )
					{
					krnlSendNotifier( protocolInfo->iMacContext,
									  IMESSAGE_DECREFCOUNT );
					protocolInfo->iMacContext = CRYPT_ERROR;
					}
				}
			}
		else
			{
			/* We're in the middle of an ongoing transaction, skip the user
			   ID, which we already know */
			readUniversal( stream );
			}
		}
	else
		{
		/* If we're the server, the client must provide a PKI user ID in the
		   first message unless we got one in an earlier transaction */
		if( isServerInitialMessage && protocolInfo->userIDsize <= 0 )
			{
			retExt( status, 
					( status, errorInfo, "Missing user ID in PKI header" ) );
			}
		}
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_RECIPKID ) )
		readUniversal( stream );			/* Recipient protection keyID */

	/* Record the transaction ID or make sure that it matches the one that
	   we sent.  There's no real need to do an explicit duplicate check
	   since a replay attempt will be rejected as a duplicate by the cert
	   store and the locking performed at that level makes it a much better
	   place to catch duplicates, but we do it anyway */
	status = readConstructed( stream, NULL, CTAG_PH_TRANSACTIONID );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, errorInfo, 
				  "Missing transaction ID in PKI header" ) );
		}
	if( isServerInitialMessage )
		{
		/* This is the first message and we're the server, record the
		   transaction ID for later */
		status = readOctetString( stream, protocolInfo->transID,
								  &protocolInfo->transIDsize,
								  4, CRYPT_MAX_HASHSIZE );
		}
	else
		{
		/* Make sure that the transaction ID for this message matches the
		   recorded value (the bad recipient nonce/bad signature error code
		   is the best that we can provide here) */
		status = readOctetString( stream, buffer, &length,
								  4, CRYPT_MAX_HASHSIZE );
		if( cryptStatusOK( status ) && \
			( protocolInfo->transIDsize < 4 || \
			  protocolInfo->transIDsize != length || \
			  memcmp( protocolInfo->transID, buffer, length ) ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADRECIPIENTNONCE;
			retExt( CRYPT_ERROR_SIGNATURE,
					( CRYPT_ERROR_SIGNATURE, errorInfo, 
					  "Returned message transaction ID doesn't match our "
					  "transaction ID" ) );
			}
		}
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, errorInfo, 
				  "Invalid transaction ID in PKI header" ) );
		}

	/* Read the sender nonce, which becomes the new recipient nonce, and skip
	   the recipient nonce if there's one present.  These values may be
	   absent, either because the other side doesn't implement them or
	   because they're not available, for example because it's sending a
	   response to an error that occurred before it could read the nonce from
	   a request.  In any case we don't bother checking the nonce values
	   since the transaction ID serves the same purpose */
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_SENDERNONCE ) )
		{
		readConstructed( stream, NULL, CTAG_PH_SENDERNONCE );
		status = readOctetString( stream, protocolInfo->recipNonce,
								  &protocolInfo->recipNonceSize,
								  4, CRYPT_MAX_HASHSIZE );
		if( cryptStatusError( status ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADSENDERNONCE;
			retExt( status,
					( status, errorInfo, 
					  "Invalid sender nonce in PKI header" ) );
			}
		}
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_RECIPNONCE ) )
		{
		readConstructed( stream, NULL, CTAG_PH_RECIPNONCE );
		status = readUniversal( stream );
		if( cryptStatusError( status ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADRECIPIENTNONCE;
			retExt( status,
					( status, errorInfo, 
					  "Invalid recipient nonce in PKI header" ) );
			}
		}

	/* Remember that we've successfully read the header information, or at
	   least the information that we need to generate a response */
	protocolInfo->headerRead = TRUE;

	/* Generate a new sender nonce (unless this is the first message and
	   we're still setting things up) and see if there's anything useful
	   present in the general info */
	if( protocolInfo->senderNonceSize > 0 )
		{
		MESSAGE_DATA msgData;

		setMessageData( &msgData, protocolInfo->senderNonce,
						protocolInfo->senderNonceSize );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		}
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_FREETEXT ) )
		status = readUniversal( stream );	/* Junk */
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_GENERALINFO ) )
		{
		status = readGeneralInfo( stream, protocolInfo );
		if( cryptStatusError( status ) )
			retExt( status,
					( status, errorInfo, 
					  "Invalid generalInfo information in PKI header" ) );
		}
	if( stell( stream ) < endPos )
		{
		/* Skip any remaining junk */
		status = sseek( stream, endPos );
		}

	return( status );
	}

/****************************************************************************
*																			*
*							Read a PKI Message								*
*																			*
****************************************************************************/

/* Read a PKI message:

	PkiMessage ::= SEQUENCE {
		header			PKIHeader,
		body			CHOICE { [0]... [24]... },
		protection	[0]	BIT STRING
		}

   Note that readPkiDatagram() has already performed an initial valid-ASN.1
   check before we get here */

int readPkiMessage( SESSION_INFO *sessionInfoPtr,
					CMP_PROTOCOL_INFO *protocolInfo,
					int messageType )
	{
	ERROR_INFO *errorInfo = &sessionInfoPtr->errorInfo;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
	const BOOLEAN isServerInitialMessage = ( messageType == CRYPT_UNUSED );
	BOOLEAN useMAC;
	void *integrityInfoPtr = DUMMY_INIT_PTR;
	int protPartStart, protPartSize, bodyStart = DUMMY_INIT;
	int length, integrityInfoLength, tag, status;

	/* Strip off the header and PKIStatus wrapper */
	sMemConnect( &stream, sessionInfoPtr->receiveBuffer,
				 sessionInfoPtr->receiveBufEnd );
	readSequence( &stream, NULL );		/* Outer wrapper */
	protPartStart = stell( &stream );
	status = readPkiHeader( &stream, protocolInfo, SESSION_ERRINFO,
							isServerInitialMessage );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}

	/* Set up state information based on the header that we've just read.  If
	   this is the first message from the client and we've been sent a new
	   user ID or cert ID, process the user/authentication info.  We
	   couldn't process this info before this point because we didn't know
	   what would be required, but now that we've read the header we can
	   set it up and get the user authentication information from the cert
	   store */
	useMAC = ( protocolInfo->macInfoPos > 0 ) ? TRUE : FALSE;
	if( protocolInfo->isCryptlib )
		sessionInfoPtr->flags |= SESSION_ISCRYPTLIB;
	if( protocolInfo->userIDchanged )
		{
		/* We've got a new PKI user ID, if it looks like a cryptlib encoded
		   ID save it in encoded form, otherwise save it as is */
		if( protocolInfo->isCryptlib && \
			protocolInfo->userIDsize == 9 )
			{
			BYTE encodedUserID[ CRYPT_MAX_TEXTSIZE + 8 ];
			int encodedUserIDLength;

			status = encodePKIUserValue( encodedUserID, CRYPT_MAX_TEXTSIZE,
										 &encodedUserIDLength, 
										 protocolInfo->userID, 
										 protocolInfo->userIDsize, 3 );
			if( cryptStatusOK( status ) )
				status = updateSessionInfo( &sessionInfoPtr->attributeList,
									CRYPT_SESSINFO_USERNAME, encodedUserID,
									encodedUserIDLength, CRYPT_MAX_TEXTSIZE,
									ATTR_FLAG_ENCODEDVALUE );
			}
		else
			{
			status = updateSessionInfo( &sessionInfoPtr->attributeList,
									CRYPT_SESSINFO_USERNAME,
									protocolInfo->userID,
									protocolInfo->userIDsize,

⌨️ 快捷键说明

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