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

📄 ext_rd.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
	REQUIRES( type >= CRYPT_CERTTYPE_NONE && type < CRYPT_CERTTYPE_LAST );
			  /* Single CRL entries have the special-case type 
			     CRYPT_CERTTYPE_NONE */
	REQUIRES( attributeLength >= 0 && attributeLength < MAX_INTLENGTH );

	/* Clear return value */
	*lengthPtr = 0;

	/* Read the appropriate extensions tag for the certificate object and
	   determine how far we can read.  CRLs and OCSP requests/responses have
	   two extension types that have different tagging, per-entry extensions
	   and entire-CRL/request extensions.  To differentiate between the two
	   we read per-entry extensions with a type of CRYPT_CERTTYPE_NONE */
	switch( type )
		{
		case CRYPT_CERTTYPE_CERTIFICATE:
			readConstructed( stream, NULL, CTAG_CE_EXTENSIONS );
			return( readSequence( stream, lengthPtr ) );

		case CRYPT_CERTTYPE_CRL:
			readConstructed( stream, NULL, CTAG_CL_EXTENSIONS );
			return( readSequence( stream, lengthPtr ) );

		case CRYPT_CERTTYPE_ATTRIBUTE_CERT:
		case CRYPT_CERTTYPE_PKIUSER:
		case CRYPT_CERTTYPE_NONE:
			/* Any outer wrapper for per-entry CRL/OCSP extensions has
			   already been read by the caller so there's only the inner
			   SEQUENCE left to read */
			return( readSequence( stream, lengthPtr ) );

		case CRYPT_CERTTYPE_CMS_ATTRIBUTES:
			return( readConstructed( stream, lengthPtr,
									 CTAG_SI_AUTHENTICATEDATTRIBUTES ) );

		case CRYPT_CERTTYPE_REQUEST_CERT:
		case CRYPT_CERTTYPE_REQUEST_REVOCATION:
			/* CRMF/CMP attributes don't contain any wrapper so there's
			   nothing to read */
			*lengthPtr = attributeLength;
			return( CRYPT_OK );

		case CRYPT_CERTTYPE_RTCS_REQUEST:
			return( readSet( stream, lengthPtr ) );

		case CRYPT_CERTTYPE_RTCS_RESPONSE:
			return( readConstructed( stream, lengthPtr, CTAG_RP_EXTENSIONS ) );

		case CRYPT_CERTTYPE_OCSP_REQUEST:
			readConstructed( stream, NULL, CTAG_OR_EXTENSIONS );
			return( readSequence( stream, lengthPtr ) );

		case CRYPT_CERTTYPE_OCSP_RESPONSE:
			readConstructed( stream, NULL, CTAG_OP_EXTENSIONS );
			return( readSequence( stream, lengthPtr ) );
		}

	retIntError();
	}

/* Read a certificate-request wrapper for a set of attributes.  This isn't 
   as simple as it should be because alongside their incompatible request 
   extension OID Microsoft also invented other values containing God knows 
   what sort of data (long Unicode strings describing the Windows module 
   that created it (as if you'd need that to know where it came from), the 
   scripts from "Gilligan's Island", every "Brady Bunch" episode ever made,
   dust from under somebody's bed from the 1930s, etc).  Because of this, 
   the following code skips over unknown garbage until it finds a valid 
   extension.

   Unfortunately this simple solution is complicated by the fact that SET 
   also defines non-CMMF-style attributes, however unlike MS's stuff these 
   are documented and stable so if we find SET-style attributes (or more 
   generally any attributes that we know about) we process them normally.  
   Finally, since all attributes may be either skipped or processed at this
   stage we include provisions for bailing out if we exhaust the available 
   attributes */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5, 6 ) ) \
static int readCertReqWrapper( INOUT STREAM *stream, 
							   /*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
							   OUT_LENGTH_Z int *lengthPtr, 
							   IN_LENGTH const int attributeLength,
							   OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
									CRYPT_ATTRIBUTE_TYPE *errorLocus,
							   OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
									CRYPT_ERRTYPE_TYPE *errorType )
	{
	const int endPos = stell( stream ) + attributeLength;
	int status, attributesProcessed = 0;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
	assert( isWritePtr( lengthPtr, sizeof( int ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	REQUIRES( attributeLength >= 0 && attributeLength < MAX_INTLENGTH );

	/* Clear return value */
	*lengthPtr = 0;
			
	do
		{
		const ATTRIBUTE_INFO *attributeInfoPtr;
		BYTE oid[ MAX_OID_SIZE + 8 ];
		int oidLength;

		/* If we've run out of attributes without finding anything useful, 
		   exit */
		if( stell( stream ) > endPos - MIN_ATTRIBUTE_SIZE )
			return( CRYPT_OK );

		/* Read the wrapper SEQUENCE and OID */
		readSequence( stream, NULL );
		status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
								 BER_OBJECT_IDENTIFIER );
		if( cryptStatusError( status ) )
			return( status );

		/* Check for a known attribute, which can happen with SET 
		   certificate requests.  If it's a known attribute, process it */
		attributeInfoPtr = oidToAttribute( ATTRIBUTE_CERTIFICATE, 
										   oid, oidLength );
		if( attributeInfoPtr != NULL )
			{
			status = readSet( stream, lengthPtr );
			if( cryptStatusOK( status ) )
				{
				status = readAttribute( stream, attributeListPtrPtr,
										attributeInfoPtr, *lengthPtr, FALSE, 
										errorLocus, errorType );
				}
			}
		else
			{
			/* It's not a known attribute, check whether it's a CMMF or MS 
			   wrapper attribute */
			if( !memcmp( oid, OID_PKCS9_EXTREQ, oidLength ) || \
				!memcmp( oid, OID_MS_EXTREQ, oidLength ) )
				{
				/* Skip the wrapper to reveal the encapsulated attributes */
				readSet( stream, NULL );
				return( readSequence( stream, lengthPtr ) );
				}
			else
				{
				/* It's unknown MS garbage, skip it */
				status = readUniversal( stream );
				}
			}
		}
	while( cryptStatusOK( status ) && attributesProcessed++ < 16 );
	if( attributesProcessed >= 16 )
		{
		/* As with the check in readAttribute() above this could be either a 
		   certificate-parsing error or a CRYPT_ERROR_INTERNAL internal 
		   error, since we can't tell without human intervention we treat it 
		   as a certificate error rather than throwing a retIntError() 
		   exception */
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_BADDATA );
		}

	return( status );
	}

/* Read a set of attributes */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5, 6 ) ) \
int readAttributes( INOUT STREAM *stream, 
					/*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
					IN_ENUM_OPT( CRYPT_CERTTYPE ) const CRYPT_CERTTYPE_TYPE type, 
					IN_LENGTH_Z const int attributeLength,
					OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
						CRYPT_ATTRIBUTE_TYPE *errorLocus,
					OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
						CRYPT_ERRTYPE_TYPE *errorType )
	{
	const ATTRIBUTE_TYPE attributeType = ( type == CRYPT_CERTTYPE_CMS_ATTRIBUTES || \
										   type == CRYPT_CERTTYPE_RTCS_REQUEST || \
										   type == CRYPT_CERTTYPE_RTCS_RESPONSE ) ? \
										 ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE;
	const BOOLEAN wrapperTagSet = ( attributeType == ATTRIBUTE_CMS ) ? \
								  TRUE : FALSE;
	int length, endPos, complianceLevel, iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );

	REQUIRES( type >= CRYPT_CERTTYPE_NONE && type < CRYPT_CERTTYPE_LAST );
			  /* Single CRL entries have the special-case type 
			     CRYPT_CERTTYPE_NONE */
	REQUIRES( ( type == CRYPT_CERTTYPE_CMS_ATTRIBUTES && \
				attributeLength == 0 ) || \
			  ( type != CRYPT_CERTTYPE_CMS_ATTRIBUTES && \
				attributeLength >= 0 && attributeLength < MAX_INTLENGTH ) );
			  /* CMS attributes are pure attribute data with no 
			     encapsulation to indicate the length so the length is 
				 implicitly "everything that's present" */

	status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
							  IMESSAGE_GETATTRIBUTE, &complianceLevel,
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the wrapper for the certificate object's attributes and 
	   determine how far we can read */
	if( type == CRYPT_CERTTYPE_CERTREQUEST )
		{
		status = readCertReqWrapper( stream, attributeListPtrPtr, &length, 
									 attributeLength, errorLocus, errorType );
		}
	else
		status = readAttributeWrapper( stream, &length, type, attributeLength );
	if( cryptStatusError( status ) )
		return( status );
	endPos = stell( stream ) + length;

	/* Read the collection of attributes.  We allow for a bit of slop for
	   software that gets the length encoding wrong by a few bytes */
	for( iterationCount = 0;
		 stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE && \
			iterationCount < FAILSAFE_ITERATIONS_LARGE;
		 iterationCount++ )
		{
		const ATTRIBUTE_INFO *attributeInfoPtr;
		BYTE oid[ MAX_OID_SIZE + 8 ];
		BOOLEAN criticalFlag = FALSE, ignoreAttribute = FALSE;
		void *attributeDataPtr;
		int oidLength, attributeDataLength;

		/* Read the outer wrapper and determine the attribute type based on
		   the OID */
		readSequence( stream, NULL );
		status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, 
								 BER_OBJECT_IDENTIFIER );
		if( cryptStatusError( status ) )
			{
			TRACE_DEBUG( "Couldn't read attribute OID, status %d.\n", 
						 status );
			return( status );
			}
		attributeInfoPtr = oidToAttribute( attributeType, oid, oidLength );
		if( attributeInfoPtr != NULL && \
			complianceLevel < decodeComplianceLevel( attributeInfoPtr->flags ) )
			{
			/* If we're running at a lower compliance level than that
			   required for the attribute, ignore it by treating it as a
			   blob-type attribute */
			attributeInfoPtr = NULL;
			ignoreAttribute = TRUE;
			}

		/* Read the optional critical flag if it's a certificate.  If the
		   extension is marked critical and we don't recognise it we don't 
		   reject it at this point because that'd make it impossible to 
		   examine the contents of the certificate or display it to the 
		   user.  Instead we reject the certificate when we try and check 
		   it */
		if( attributeType != ATTRIBUTE_CMS && \
			peekTag( stream ) == BER_BOOLEAN )
			{
			status = readBoolean( stream, &criticalFlag );
			if( cryptStatusError( status ) )
				{
				*errorLocus = ( attributeInfoPtr != NULL ) ? \
							  attributeInfoPtr->fieldID : CRYPT_ATTRIBUTE_NONE;
				*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
				return( status );
				}
			}

		/* Read the wrapper around the attribute payload */
		if( wrapperTagSet )
			status = readSet( stream, &attributeDataLength );
		else
			status = readOctetStringHole( stream, &attributeDataLength, 2,
										  DEFAULT_TAG );
		if( cryptStatusError( status ) )
			{
			*errorLocus = ( attributeInfoPtr != NULL ) ? \
						  attributeInfoPtr->fieldID : CRYPT_ATTRIBUTE_NONE;
			*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
			TRACE_DEBUG( "Couldn't read attribute wrapper, status %d.\n", 
						 status );
			return( status );
			}

		/* If it's a known attribute, parse the payload */
		if( attributeInfoPtr != NULL )
			{
			status = readAttribute( stream, attributeListPtrPtr,
									attributeInfoPtr, attributeDataLength,
									criticalFlag, errorLocus, errorType );
			if( cryptStatusError( status ) )
				{
				TRACE_DEBUG( "Error %d reading attribute.\n", status );
				return( status );
				}
			continue;
			}

		/* If it's a zero-length unrecognised attribute, don't add anything.
		   A zero length indicates that the attribute contains all default
		   values, however since we don't recognise the attribute we can't
		   fill these in so the attribute is in effect not present */
		if( attributeDataLength <= 0 )
			continue;

		/* It's an unrecognised or ignored attribute type, add the raw data
		   to the list of attributes */
		status = sMemGetDataBlock( stream, &attributeDataPtr, 
								   attributeDataLength );
		if( cryptStatusOK( status ) )
			{
			status = addAttribute( attributeType, attributeListPtrPtr, 
								   oid, oidLength, criticalFlag, 
								   attributeDataPtr, attributeDataLength, 
								   ignoreAttribute ? \
										ATTR_FLAG_BLOB | ATTR_FLAG_IGNORED : \
										ATTR_FLAG_NONE );
			}
		if( cryptStatusError( status ) )
			{
			if( status == CRYPT_ERROR_INITED )
				{
				/* If there's a duplicate attribute present, set error
				   information for it and flag it as a bad data error.  We
				   can't set an error locus since it's an unknown blob */
				*errorLocus = CRYPT_ATTRIBUTE_NONE;
				*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
				status = CRYPT_ERROR_BADDATA;
				}
			TRACE_DEBUG( "Error %d adding attribute data.\n", status );
			return( status );
			}
		sSkip( stream, attributeDataLength );	/* Skip the attribute data */
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );

	return( CRYPT_OK );
	}

⌨️ 快捷键说明

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