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

📄 cmp.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	}

/* Read a PKI header and make sure it matches the header 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 which don't directly affect the protocol,
   based on the results of CMP interop testing this appears to be standard
   practice among implementors (it also helps get around problems with
   implementations which 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) */

static int readPkiHeader( STREAM *stream, CMP_PROTOCOL_INFO *protocolInfo,
						  const BOOLEAN isInitialMessage )
	{
	CRYPT_ALGO cryptAlgo, hashAlgo;
	BYTE buffer[ CRYPT_MAX_HASHSIZE ];
	int length, streamPos, endPos, status;

	/* Clear per-message state information */
	protocolInfo->macInfoPos = protocolInfo->authKeyIDpos = CRYPT_ERROR;
	protocolInfo->authKeyIDlength = 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 can be specified
		   either as the sender DN or the senderKID or both, with no real
		   guidance as to which one to use implementors are using any of
		   these three options to identify the key.  Since we need to check
		   that the integrity-protection key we're using is correct so 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.  If all we've got
		   is the sender DN and it doesn't uniquely identify a cert the
		   caller will get an inappropriate error when we try and verify the
		   signature, but that's yet another CMP flaw which we can't really
		   fix */
		readConstructed( stream, &protocolInfo->authKeyIDlength, 4 );
		protocolInfo->authKeyIDpos = stell( stream );
		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 */
	readUniversal( stream );			/* Recipient */
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_MESSAGETIME ) )
		readUniversal( stream );		/* Message time */
	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 we'd
		   get from the following read */
		status = CRYPT_ERROR_SIGNATURE;
	else
		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 */
		return( status );
	streamPos = ( int ) 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 we can process it later */
		sClearError( stream );
		protocolInfo->macInfoPos = streamPos;
		readUniversal( stream );
		protocolInfo->useMACreceive = TRUE;
		}
	if( isInitialMessage )
		{
		/* Read the keyID which we'll need to figure out how to handle the
		   integrity protection on the message */
		readConstructed( stream, NULL, CTAG_PH_SENDERKID );
		status = readOctetString( stream, protocolInfo->userID,
								  &protocolInfo->userIDsize,
								  CRYPT_MAX_HASHSIZE );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_SENDERKID ) )
			readUniversal( stream );	/* Sender protection keyID */
	if( peekTag( stream ) == MAKE_CTAG( CTAG_PH_RECIPKID ) )
		readUniversal( stream );		/* Recipient protection keyID */

	/* Record the transaction ID / make sure it matches the one we sent.
	   There's no 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 */
	readConstructed( stream, NULL, CTAG_PH_TRANSACTIONID );
	if( isInitialMessage )
		/* This is the first message, record the transaction ID for later */
		status = readOctetString( stream, protocolInfo->transID,
								  &protocolInfo->transIDsize,
								  CRYPT_MAX_HASHSIZE );
	else
		{
		/* Make sure the transaction ID for this message matches the recorded
		   value (the bad recipient nonce error code is the best we can
		   provide here) */
		status = readOctetString( stream, buffer, &length,
								  CRYPT_MAX_HASHSIZE );
		if( cryptStatusOK( status ) && \
			( protocolInfo->transIDsize != length || \
			  memcmp( protocolInfo->transID, buffer, length ) ) )
			{
			protocolInfo->pkiFailInfo = CMPFAILINFO_BADRECIPIENTNONCE;
			status = CRYPT_ERROR_BADDATA;
			}
#ifdef SKIP_IO
		puts( "CMP: Bypassing nonce check." );
		status = CRYPT_OK;
#endif /* SKIP_IO */
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Read the sender nonce, which becomes the new recipient nonce, and skip
	   the recipient nonce if there's one present.  We don't bother checking
	   the nonces since the transaction ID serves the same purpose */
	readConstructed( stream, NULL, CTAG_PH_SENDERNONCE );
	status = readOctetString( stream, protocolInfo->recipNonce,
							  &protocolInfo->recipNonceSize,
							  CRYPT_MAX_HASHSIZE );
	if( cryptStatusError( status ) )
		protocolInfo->pkiFailInfo = CMPFAILINFO_BADSENDERNONCE;
	else
		if( !isInitialMessage )
			{
			readConstructed( stream, NULL, CTAG_PH_RECIPNONCE );
			status = readUniversal( stream );	/* Recipient nonce */
			if( cryptStatusError( status ) )
				protocolInfo->pkiFailInfo = CMPFAILINFO_BADRECIPIENTNONCE;
			}
	if( cryptStatusError( status ) )
		return( status );

	/* Generate a new sender nonce and see if there's anything useful present
	   in the general info.  Note that since cryptlib nonces are based on a
	   hash of the time they're guessable, but since they're entirely
	   redundant anyway this isn't a problem, all we need is a nonrepeating
	   value to keep the other side happy */
	getNonce( protocolInfo->senderNonce, protocolInfo->senderNonceSize );
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_FREETEXT ) )
		readUniversal( stream );		/* Junk */
	if( stell( stream ) < endPos && \
		peekTag( stream ) == MAKE_CTAG( CTAG_PH_GENERALINFO ) )
		{
		int generalInfoEndPos = ( int ) stell( stream );

		/* There's general info present, some of this may contain cryptlib-
		   provided data so we go through the various attributes looking for
		   anything we can use */
		readConstructed( stream, NULL, CTAG_PH_GENERALINFO );
		readSequence( stream, &length );
		generalInfoEndPos += length;
		while( stell( stream ) < generalInfoEndPos )
			{
			BYTE oid[ MAX_OID_SIZE ];

			/* Read the attribute.  Since there are only two attribute types
			   which we use, we hardcode the read in here rather than
			   performing a general-purpose attribute read */
			readSequence( stream, NULL );
			status = readRawObject( stream, oid, &length, MAX_OID_SIZE,
									BER_OBJECT_IDENTIFIER );
			if( cryptStatusError( status ) )
				return( status );
			if( length == sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) && \
				!memcmp( oid, OID_CRYPTLIB_PRESENCECHECK, length ) )
				/* The other side is running cryptlib, we can make some
				   common-sense assumptions about its behaviour */
				protocolInfo->isCryptlib = TRUE;
			else
				if( length == sizeofOID( OID_ESS_CERTID ) && \
					!memcmp( oid, OID_ESS_CERTID, length ) )
					{
					/* Extract the issuerAndSerialNumber from the cert ID.
					   This also provides an optional cert hash, but we
					   don't use this at the moment */
					readSet( stream, NULL );
					readSequence( stream, NULL );
					readSequence( stream, NULL );
					if( peekTag( stream ) == BER_OCTETSTRING )
						readUniversal( stream );
					protocolInfo->authKeyIDpos = ( int ) stell( stream );
					readSequence( stream, &length );
					protocolInfo->authKeyIDlength = \
							( int ) sizeofObject( length );
					sSkip( stream, length );
					continue;
					}
			readUniversal( stream );
			}
		}
	if( stell( stream ) < endPos )
		sseek( stream, endPos );

	return( sGetStatus( stream ) );
	}

/* Write a PKI request into a session's send buffer */

static int writePkiMessage( SESSION_INFO *sessionInfoPtr,
							CMP_PROTOCOL_INFO *protocolInfo,
							const CMPBODY_TYPE bodyType )
	{
	BYTE protInfo[ CRYPT_MAX_PKCSIZE * 2 ], headerBuffer[ 8 ];
	STREAM stream;
	int headerSize, protInfoSize, status;

	/* Write the header and payload so we can MAC/sign it */
	sMemOpen( &stream, sessionInfoPtr->receiveBuffer,
			  sessionInfoPtr->receiveBufSize );
	status = writePkiHeader( &stream, sessionInfoPtr, protocolInfo );
	if( cryptStatusOK( status ) )
		{
		switch( bodyType )
			{
			case CMPBODY_NORMAL:
				if( sessionInfoPtr->flags & SESSION_ISSERVER )
					status = writeResponseBody( &stream, sessionInfoPtr,
												protocolInfo );
				else
					status = writeRequestBody( &stream, sessionInfoPtr,
											   protocolInfo );
				break;

			case CMPBODY_CONFIRMATION:
				status = writeConfBody( &stream, sessionInfoPtr,
										protocolInfo );
				break;

			case CMPBODY_ACK:
				writeConstructed( &stream, objSize( sizeofNull() ),
								  CTAG_PB_PKICONF );
				writeSequence( &stream, sizeofNull() );
				writeNull( &stream, DEFAULT_TAG );
				break;


			case CMPBODY_ERROR:
				status = writeErrorBody( &stream, sessionInfoPtr,
										 protocolInfo );
				break;

			default:
				assert( NOTREACHED );
			}
		}
	if( cryptStatusError( status ) )
		{
		sMemClose( &stream );
		return( status );
		}

	/* Generate the MAC or signature as appropriate */
	if( protocolInfo->useMACsend )
		{
		BYTE macValue[ CRYPT_MAX_HASHSIZE ];

		status = hashMessageContents( protocolInfo->iMacContext,
						sessionInfoPtr->receiveBuffer, stell( &stream ) );
		if( cryptStatusOK( status ) )
			{
			RESOURCE_DATA msgData;

			setResourceData( &msgData, macValue, CRYPT_MAX_HASHSIZE );
			status = krnlSendMessage( protocolInfo->iMacContext,
									  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
									  &msgData, CRYPT_CTXINFO_HASHVALUE );
			protInfoSize = msgData.length;
			}
		if( cryptStatusOK( status ) )
			{
			STREAM macStream;

			/* Write the MAC value with BIT STRING encapsulation */
			sMemOpen( &macStream, protInfo, CRYPT_MAX_PKCSIZE * 2 );
			writeTag( &macStream, BER_BITSTRING );
			writeLength( &macStream, protInfoSize + 1 );/* +1 for bitstring */
			sputc( &macStream, 0 );
			swrite( &macStream, macValue, protInfoSize );
			protInfoSize = stell( &macStream );
			sMemDisconnect( &macStream );
			}
		}
	else
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;

		/* Hash the data and create the signature */
		setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_SHA );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
								  &createInfo, OBJECT_TYPE_CONTEXT );
		if( cryptStatusOK( status ) )
			{
			status = hashMessageContents( createInfo.cryptHandle,
						sessionInfoPtr->receiveBuffer, stell( &stream ) );
			if( cryptStatusOK( status ) )
				status = createRawSignature( protInfo, &protInfoSize,
											 sessionInfoPtr->privateKey,
											 createInfo.cryptHandle );
			krnlSendNotifier( createInfo.cryptHandle, RESOURCE_IMESSAGE_DECREFCOUNT );
			}
		}
	if( cryptStatusError( status ) )
		{
		sMemClose( &stream );
		return( status );
		}

	/* Attach the MAC/signature to the payload */
	writeConstructed( &stream, protInfoSize, CTAG_PM_PROTECTION );
	swrite( &stream, protInfo, protInfoSize );
	sessionInfoPtr->receiveBufEnd = stell( &stream );
	status = sGetStatus( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

⌨️ 快捷键说明

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