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

📄 cmp_rd.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
		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
		} */

int readPkiMessage( SESSION_INFO *sessionInfoPtr,
					CMP_PROTOCOL_INFO *protocolInfo,
					int messageType )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
	const BOOLEAN isServerInitialMessage = ( messageType == CRYPT_UNUSED );
	BOOLEAN useMAC;
	int protPartStart, protPartSize, bodyStart;
	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, sessionInfoPtr, 
							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.  Note that 
		   the value passed to encodePKIUserValue() is the number of code
		   groups to produce in the encoded value, not the input length */
		if( protocolInfo->isCryptlib && \
			protocolInfo->userIDsize == 9 )
			{
			sessionInfoPtr->userNameLength = \
				encodePKIUserValue( sessionInfoPtr->userName, 
									protocolInfo->userID, 3 );
			sessionInfoPtr->flags |= SESSION_ISENCODEDUSERID;
			}
		else
			{
			memcpy( sessionInfoPtr->userName, protocolInfo->userID,
					protocolInfo->userIDsize );
			sessionInfoPtr->userNameLength = protocolInfo->userIDsize;
			}
		if( isServerInitialMessage && useMAC )
			status = initServerAuthentMAC( sessionInfoPtr, protocolInfo );
		}
	if( protocolInfo->certIDchanged )
		{
		memcpy( sessionInfoPtr->keyFingerprint, protocolInfo->certID,
				protocolInfo->certIDsize );
		sessionInfoPtr->keyFingerprintSize = protocolInfo->certIDsize;
		if( isServerInitialMessage )
			status = initServerAuthentSign( sessionInfoPtr, protocolInfo );
		}
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}
	
	/* Determine the message body type.  An error response can occur at any
	   point in an exchange so we process this immediately.  We don't do an
	   integrity verification at this point since it's not certain what we
	   should report if the check fails, and an unauthenticated error
	   message is better than an authenticated paketewhainau */
	tag = EXTRACT_CTAG( peekTag( &stream ) );
	if( tag == CTAG_PB_ERROR )
		{
		status = readErrorBody( &stream, sessionInfoPtr );
		sMemDisconnect( &stream );
		return( status );
		}

	/* If this is an initial message we don't know what to expect yet so we
	   set the type to whatever we find, as long as it's a valid message to
	   send to a CA */
	if( isServerInitialMessage && \
		( tag == CTAG_PB_IR || tag == CTAG_PB_CR || tag == CTAG_PB_P10CR || \
		  tag == CTAG_PB_KUR || tag == CTAG_PB_RR || tag == CTAG_PB_GENM ) )
		protocolInfo->operation = messageType = tag;

	/* If we're using a MAC for authentication, we can finally set up the
	   MAC info using the appropriate password */
	if( useMAC )
		{
		BYTE decodedValue[ CRYPT_MAX_TEXTSIZE ];
		const BYTE *decodedValuePtr = decodedValue;
		int decodedValueLength;

		if( sessionInfoPtr->flags & SESSION_ISENCODEDPW )
			{
			/* It's an encoded value, get the decoded form */
			decodedValueLength = decodePKIUserValue( decodedValue,
										sessionInfoPtr->password, 
										sessionInfoPtr->passwordLength );
			if( cryptStatusError( decodedValueLength ) )
				{
				assert( NOTREACHED );
				sMemDisconnect( &stream );
				retExt( sessionInfoPtr, decodedValueLength, 
						"Invalid PKI user password" );
				}
			}
		else
			{
			decodedValuePtr = sessionInfoPtr->password;
			decodedValueLength = sessionInfoPtr->passwordLength;
			}

		/* We couldn't initialise the MAC information when we read the 
		   header because the order of the information used to set this up 
		   is backwards, so we have to go back and re-process it now */
		if( cryptStatusOK( status ) )
			{
			const int streamPos = stell( &stream );

			sseek( &stream, protocolInfo->macInfoPos );
			status = readMacInfo( &stream, protocolInfo, decodedValuePtr,
								  decodedValueLength, sessionInfoPtr );
			sseek( &stream, streamPos );
			}
		zeroise( decodedValue, CRYPT_MAX_TEXTSIZE );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( status );
			}
		}

	/* Make sure that it's what we're after, remember where the message body
	   starts, and skip it (it'll be processed after we verify its integrity) */
	if( tag != messageType )
		{
		sMemDisconnect( &stream );
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADREQUEST;
		if( isServerInitialMessage )
			/* This is the first message and we got no recognisable message 
			   of any type */
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA, 
					"Invalid message type %d", tag );
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA, 
				"Invalid message type, expected %d, got %d", messageType, 
				 tag );
		}
	status = readConstructed( &stream, &length, messageType );
	if( cryptStatusOK ( status ) )
		{
		bodyStart = stell( &stream );
		status = sSkip( &stream, length );
		}
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADDATAFORMAT;
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA, 
				"Invalid message body start" );
		}

	/* Read the start of the message integrity info */
	protPartSize = stell( &stream ) - protPartStart;
	status = readConstructed( &stream, &integrityInfoLength, 
							  CTAG_PM_PROTECTION );
	if( cryptStatusOK( status ) && \
		integrityInfoLength > sMemDataLeft( &stream ) )
		{
		/* If there integrity protection is missing, report it as a wrong-
		   integrity-info problem, the closest we can get to the real 
		   error.  This has already been checked by the high-level PKI
		   datagram read code anyway, but we check gain here just to be
		   safe */
		protocolInfo->pkiFailInfo = CMPFAILINFO_WRONGINTEGRITY;
		strcpy( sessionInfoPtr->errorMessage, 
				"Signature/MAC data is missing or truncated" );
		status = CRYPT_ERROR_SIGNATURE;
		}
	if( cryptStatusOK( status ) && tag == CTAG_PB_IR && !useMAC )
		{
		/* An ir has to be MAC'ed, in theory this doesn't really matter but
		   the spec requires that we only allow a MAC.  If it's not MAC'ed it
		   has to be a cr, which is exactly the same only different */
		protocolInfo->pkiFailInfo = CMPFAILINFO_WRONGINTEGRITY;
		strcpy( sessionInfoPtr->errorMessage, 
				"Received signed ir, should be MAC'ed" );
		status = CRYPT_ERROR_SIGNATURE;
		}
	if( cryptStatusOK( status ) && tag == CTAG_PB_RR && useMAC )
		{
		/* An rr can't be MAC'ed because the trail from the original PKI 
		   user to the cert being revoked can become arbitrarily blurred, 
		   with the cert being revoked having a different DN,
		   issuerAndSerialNumber, and public key after various updates,
		   replacements, and reissues.  In fact cryptlib tracks the
		   resulting directed graph via the cert store log and allows
		   fetching the original authorising issuer of a cert using the
		   KEYMGMT_FLAG_GETISSUER option, however this requires that the
		   client also be running cryptlib, or specifically that it submit
		   a cert ID in the request, this being the only identifier that 
		   reliably identifies the cert being revoked.  Since it's somewhat 
		   unsound to assume this, we don't currently handle MAC'ed rr's, 
		   however everything is in place to allow them to be implemented 
		   if they're really needed */
		protocolInfo->pkiFailInfo = CMPFAILINFO_WRONGINTEGRITY;
		strcpy( sessionInfoPtr->errorMessage, 
				"Received MAC'ed rr, should be signed" );
		status = CRYPT_ERROR_SIGNATURE;
		}
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}

	/* Verify the message integrity */
	if( protocolInfo->useMACreceive )
		{
		const CRYPT_CONTEXT iMacContext = ( protocolInfo->useAltMAC ) ? \
					protocolInfo->iAltMacContext : protocolInfo->iMacContext;
		RESOURCE_DATA msgData;
		BYTE macBuffer[ CRYPT_MAX_HASHSIZE ];
		int protectionLength;

		/* Read the BIT STRING encapsulation, MAC the data, and make sure 
		   that it matches the value attached to the message */
		status = readBitStringHole( &stream, &protectionLength, DEFAULT_TAG );
		if( cryptStatusOK( status ) && \
			protectionLength > sMemDataLeft( &stream ) )
			status = CRYPT_ERROR_UNDERFLOW;
		if( cryptStatusOK( status ) )
			status = hashMessageContents( iMacContext,
							sessionInfoPtr->receiveBuffer + protPartStart,
							protPartSize );
		if( cryptStatusOK( status ) )
			{
			setMessageData( &msgData, macBuffer, CRYPT_MAX_HASHSIZE );
			status = krnlSendMessage( iMacContext, IMESSAGE_GETATTRIBUTE_S,
									  &msgData, CRYPT_CTXINFO_HASHVALUE );
			}
		if( cryptStatusError( status ) || \
			protectionLength != msgData.length || \
			memcmp( macBuffer, sMemBufPtr( &stream ), msgData.length ) )
			{
			sMemDisconnect( &stream );
			retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE, 
					"Bad message MAC" );
			}
		}
	else
		{
		if( !protocolInfo->isCryptlib )
			{
			RESOURCE_DATA msgData;

			/* Make sure that the sig-check key that we'll be using is the 
			   correct one.  Because of CMP's use of a raw signature format 
			   we have to do this manually rather than relying on the sig-
			   check code to do it for us, and because of the braindamaged 
			   way of identifying integrity-protection keys for non-cryptlib 
			   messages even this isn't enough to definitely tell us that 
			   we're using the right key, in which case we'll get a bad data 
			   or bad sig response from the sig check code */
			setMessageData( &msgData, protocolInfo->senderDNPtr,
							protocolInfo->senderDNlength );
			status = krnlSendMessage( sessionInfoPtr->iAuthInContext,
									  IMESSAGE_COMPARE, &msgData,
									  MESSAGE_COMPARE_SUBJECT );
			if( cryptStatusError( status ) )
				{
				/* A failed comparison is reported as a generic CRYPT_ERROR,
				   convert it into a wrong-key error if necessary */
				sMemDisconnect( &stream );
				retExt( sessionInfoPtr, ( status == CRYPT_ERROR ) ? \
										CRYPT_ERROR_WRONGKEY : status,
						"Message signature key doesn't match our signature "
						"check key, signature can't be checked" );
				}
			}

		/* Hash the data and verify the signature */
		setMessageCreateObjectInfo( &createInfo, protocolInfo->hashAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
								  OBJECT_TYPE_CONTEXT );
		if( cryptStatusOK( status ) )
			{
			status = hashMessageContents( createInfo.cryptHandle,
							sessionInfoPtr->receiveBuffer + protPartStart, 
							protPartSize );
			if( cryptStatusOK( status ) )
				status = checkRawSignature( sMemBufPtr( &stream ),
											integrityInfoLength,
											sessionInfoPtr->iAuthInContext,
											createInfo.cryptHandle );
			krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
			if( cryptStatusError( status ) )
				{
				sMemDisconnect( &stream );
				retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE, 
						"Bad message signature" );
				}
			}
		}
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}
	sseek( &stream, bodyStart );

	/* If it's a client request, import the encapsulated request data */
	switch( messageType )
		{
		case CTAG_PB_IR:
		case CTAG_PB_CR:
		case CTAG_PB_P10CR:
		case CTAG_PB_KUR:
		case CTAG_PB_RR:
			status = readRequestBody( &stream, sessionInfoPtr, protocolInfo,
									  messageType );
			break;
		
		case CTAG_PB_IP:
		case CTAG_PB_CP:
		case CTAG_PB_KUP:
		case CTAG_PB_RP:
			status = readResponseBody( &stream, sessionInfoPtr, 
									   protocolInfo );
			break;

		case CTAG_PB_CERTCONF:
			status = readConfBody( &stream, sessionInfoPtr, protocolInfo );
			break;

		case CTAG_PB_PKICONF:
			/* If it's a confirmation there's no message body and we're 
			   done */
			break;

		case CTAG_PB_GENM:
		case CTAG_PB_GENP:
			status = readGenMsgBody( &stream, sessionInfoPtr,
									 messageType == CTAG_PB_GENM );
			break;

		default:
			assert( NOTREACHED );
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA, 
					"Unexpected message type %d", messageType );
		}
	sMemDisconnect( &stream );
	return( status );
	}
#endif /* USE_CMP */

⌨️ 快捷键说明

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