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

📄 cmp_rd.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Read the client's returned confirmation information */
	status = readSequence( stream, &length );
	if( cryptStatusOK( status ) && length <= 0 )
		{
		/* Missing certStatus, the client has rejected the cert.  This isn't 
		   an explicit error since it's a valid protocol outcome, so we 
		   return an OK status but set the overall protocol status to a 
		   generic error value to indicate that we don't want to continue 
		   normally */
		protocolInfo->status = CRYPT_ERROR;
		return( CRYPT_OK );
		}
	readSequence( stream, NULL );
	status = readOctetString( stream, certHash, &length, 
							  CRYPT_MAX_HASHSIZE );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, status, "Invalid cert confirmation" );

	/* Get the local cert hash and compare it to the client's one.  Since 
	   we're the server, this is a cryptlib-issued cert so we know that 
	   it'll always use SHA-1 */
	setMessageData( &msgData, certHash, length );
	status = krnlSendMessage( sessionInfoPtr->iCertResponse, 
							  IMESSAGE_COMPARE, &msgData,
							  MESSAGE_COMPARE_FINGERPRINT );
	if( cryptStatusError( status ) )
		{
		/* The user is confirming an unknown cert, the best that we can do 
		   is return a generic cert-mismatch error */
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADCERTID;
		retExt( sessionInfoPtr, CRYPT_ERROR_NOTFOUND,
				"Returned cert hash doesn't match issued certificate" );
		}
	return( CRYPT_OK );
	}

/* Read genMsg body */

static int readGenMsgBody( STREAM *stream, SESSION_INFO *sessionInfoPtr, 
						   const BOOLEAN isRequest )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	void *bodyInfoPtr;
	int bodyLength, status;

	status = readSequence( stream, &bodyLength );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid genMsg header" );
	if( !isRequest )
		/* The InfoTypeAndValue is handled as CMS content (see the comment 
		   for writeGenMsgBody()) so we remember where the CMS payload 
		   starts if it's a PKIBoot response */
		bodyInfoPtr = sMemBufPtr( stream );
	if( bodyLength < 8 || bodyLength > sMemDataLeft( stream ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid genMsg length %d", bodyLength );
	readSequence( stream, NULL );
	status = readOID( stream, isRequest ? OID_PKIBOOT : OID_CMS_SIGNEDDATA );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
				"Invalid genMsg type, expected PKIBoot request or "
				"response" );

	/* If it's a PKIBoot request, we're done */
	if( isRequest )
		return( CRYPT_OK );

	/* It's a PKIBoot response, import the cert trust list.  Since this 
	   isn't a true cert chain and isn't used as such, we use data-only 
	   certs (specified using the special-case CERTFORMAT_CTL format 
	   specifier) */
	setMessageCreateObjectIndirectInfo( &createInfo, bodyInfoPtr, 
										bodyLength, CERTFORMAT_CTL );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT_INDIRECT, 
							  &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, status, "Invalid PKIBoot response" );
	sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
	return( CRYPT_OK );
	}

/* Read error body */

static int readErrorBody( STREAM *stream, SESSION_INFO *sessionInfoPtr )
	{
	int endPos, length, status;

	/* Read the outer wrapper and PKI status info.  An error return status
	   is valid when we read the status info since we're reading an error
	   status and converting it into a cryptlib status, so we don't exit
	   unless it's a problem with the status info itself */
	readConstructed( stream, NULL, CTAG_PB_ERROR );
	readSequence( stream, &length );	/* Outer wrapper */
	endPos = stell( stream ) + length;
	status = readPkiStatusInfo( stream, &sessionInfoPtr->errorCode,
								sessionInfoPtr->errorMessage );
	if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_UNDERFLOW )
		return( status );

	/* In addition to the PKI status info there can be another layer of
	   error information wrapped around it which is exactly the same only
	   different, so if we haven't got anything from the status info we
	   check to see whether this layer can give us anything */
	if( stell( stream ) < endPos && peekTag( stream ) == BER_INTEGER )
		{
		/* If there's an error code present and we haven't already set the
		   error code from the pkiStatusInfo, set it now */
		if( !sessionInfoPtr->errorCode )
			{
			long value;

			status = readShortInteger( stream, &value );
			if( cryptStatusOK( status ) )
				sessionInfoPtr->errorCode = ( int ) value;
			}
		else
			readUniversal( stream );
		}
	if( stell( stream ) < endPos && peekTag( stream ) == BER_SEQUENCE && \
		!*sessionInfoPtr->errorMessage )
		/* Read the error text, ignoring any possible error status since the
		   overall error code from the status info is more meaningful than
		   a data format problem in trying to read the error text */
		readFreeText( stream, sessionInfoPtr->errorMessage,
					  MAX_ERRMSG_SIZE - 1 );

	return( status );
	}

/****************************************************************************
*																			*
*								Read a PKI Header							*
*																			*
****************************************************************************/

/* Read a PKI header and make sure that it matches the header that we sent 
   (for EE or non-initial CA/RA messages) or set up the EE information in 
   response to an initial message (for an initial CA/RA message).  We ignore 
   all the redundant fields in the header that don't directly affect the 
   protocol, based on the results of CMP interop testing this appears to be 
   standard practice among implementors.  This also helps get around problems 
   with implementations that get the fields wrong, since most of the fields
   aren't generally useful it doesn't affect the processing while making the
   code more tolerant of implementation errors:

	header				SEQUENCE {
		version			INTEGER (2),
		dummy		[4]	EXPLICIT DirectoryName,		-- Ignored
		senderDN	[4]	EXPLICIT DirectoryName,		-- Copied if non-clib
		protAlgo	[1]	EXPLICIT AlgorithmIdentifier,
		protKeyID	[2] EXPLICIT OCTET STRING,		-- Copied if changed
		dummy		[3] EXPLICIT OCTET STRING,		-- Ignored
		transID		[4] EXPLICIT OCTET STRING,
		nonce		[5] EXPLICIT OCTET STRING,		-- Copied if non-clib
		dummy		[6] EXPLICIT OCTET STRING,		-- Ignored
		dummy		[7] SEQUENCE OF UTF8String,		-- Ignored
		generalInfo	[8] EXPLICIT SEQUENCE OF Info OPT	-- cryptlib-specific info
		} */

static int readPkiHeader( STREAM *stream, CMP_PROTOCOL_INFO *protocolInfo,
						  void *errorInfo,
						  const BOOLEAN isServerInitialMessage )
	{
	CRYPT_ALGO_TYPE cryptAlgo, hashAlgo;
	BYTE buffer[ CRYPT_MAX_HASHSIZE ];
	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;

	/* 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 );
		protocolInfo->senderDNPtr = sMemBufPtr( stream );
		if( cryptStatusOK( status ) && protocolInfo->senderDNlength > 0 )
			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 */
		readUniversal( stream );			/* Sender DN */
	status = readUniversal( stream );		/* Recipient */
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_MESSAGETIME ) )
		status = readUniversal( stream );	/* Message time */
	if( cryptStatusError( status ) )
		retExt( errorInfo, CRYPT_ERROR_BADDATA, "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( errorInfo, CRYPT_ERROR_SIGNATURE,
				"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( errorInfo, status, 
				"Invalid integrity protection info in PKI header" );
	streamPos = stell( stream );
	status = readAlgoIDex( stream, &cryptAlgo, &hashAlgo, NULL );
	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 ];
			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, 
									  CRYPT_MAX_HASHSIZE );
			if( cryptStatusError( status ) )
				retExt( errorInfo, status, 
						"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( errorInfo, status, "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( errorInfo, status, "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,
								  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,
								  CRYPT_MAX_HASHSIZE );
		if( cryptStatusOK( status ) && \
			( protocolInfo->transIDsize < 4 || \
			  protocolInfo->transIDsize != length || \
			  memcmp( protocolInfo->transID, buffer, length ) ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADRECIPIENTNONCE;
			retExt( errorInfo, CRYPT_ERROR_SIGNATURE, 
					"Returned message transaction ID doesn't match our "
					"transaction ID" );
			}
		}
	if( cryptStatusError( status ) )
		retExt( errorInfo, status, "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,
								  CRYPT_MAX_HASHSIZE );
		if( cryptStatusError( status ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADSENDERNONCE;
			retExt( errorInfo, status, 
					"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( errorInfo, status, 
					"Invalid recipient nonce in PKI header" );
			}
		}

	/* 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 )
		{
		RESOURCE_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( errorInfo, status, 
					"Invalid generalInfo information in PKI header" );
		}
	if( stell( stream ) < endPos )
		/* Skip any remaining junk */

⌨️ 快捷键说明

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