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

📄 ext_rd.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 4 页
字号:
			attributeContinues = TRUE;
			}
		}
	while( ( attributeContinues || setofStack.stackPos > 1 ) && \
		   stell( stream ) < endPos && \
		   iterationCount++ < CERT_MAX_ITERATIONS );

	/* If we got stuck in a loop trying to decode an attribute, complain and 
	   exit.  This can happen in cases where there's a series of nested 
	   sequences of optional attributes, where we have to keep backtracking 
	   and trying again to try and find a match.  In this case it's possible
	   to construct cert data that matches the first part of the optional
	   data, but since the rest doesn't match we keep having to restart 
	   (imagine an LL(1) parser trying to handle a non-LL(1) grammar) */
	if( iterationCount >= CERT_MAX_ITERATIONS )
		{
		assert( NOTREACHED );
		return( CRYPT_ERROR_BADDATA );
		}

	/* Handle the special case of (a) the encoded data ending but fields with
	   default values being present, or (b) the encoded data continuing but
	   no more decoding information being present */
	if( attributeContinues )
		{
		/* If there are default fields to follow, add the default value - see
		   the comment on the handling of default fields above.  For now we
		   only add the first field since the only attributes where this
		   case can occur have a single default value as the next possible
		   entry, burrowing down further causes complications due to default
		   values present in optional sequences.  As usual, we don't set any
		   specific error information for the default fields */
		if( attributeInfoPtr->flags & FL_DEFAULT )
			{
			const int value = ( int ) attributeInfoPtr->defaultValue;

			status = addAttributeField( attributeListPtrPtr,
						attributeInfoPtr->fieldID, CRYPT_ATTRIBUTE_NONE,
						&value, CRYPT_UNUSED, flags, NULL, NULL );
			if( cryptStatusError( status ) )
				return( status );
			}
		}
	else
		/* Some attributes have a SEQUENCE OF fields of no great use (e.g.
		   Microsoft's extensive crlDistributionPoints lists providing
		   redundant pointers to the same inaccessible site-internal
		   servers, although these are already handled above), if there's
		   any extraneous data left we just skip it */
		while( stell( stream ) < endPos && cryptStatusOK( status ) && \
			   peekTag( stream ) )
			{
			assert( NOTREACHED );
			status = readUniversal( stream );
			}

#if 0	/* 22/11/03 Removed since these Verisign certs have now expired */
	/* More Verisign braindamage: There may be arbitrary levels of EOC's
	   at the end of an attribute, so we sit in a loop skipping them.
	   Eventually we'll run into the SEQUENCE for the signature
	   AlgorithmIdentifier that always follows attributes in certs, cert
	   requests, and CMS attributes.  Per varios casus... */
	while( cryptStatusOK( status ) && peekTag( stream ) == BER_EOC )
		{
		status = checkEOC( stream );
		if( status == TRUE )
			/* checkEOC returns TRUE/FALSE for EOC */
			status = CRYPT_OK;
		}
#endif /* 0 */

	return( status );
	}

/****************************************************************************
*																			*
*						Attribute Collection Read Routines					*
*																			*
****************************************************************************/

/* Read a set of attributes */

int readAttributes( STREAM *stream, ATTRIBUTE_LIST **attributeListPtrPtr,
					const CRYPT_CERTTYPE_TYPE type, const int attributeSize,
					CRYPT_ATTRIBUTE_TYPE *errorLocus,
					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, status;

	/* Many certificates are invalid but are accepted by existing software
	   that does little or no checking.  In order to be able to process
	   these certs, the user can disable various levels of processing in
	   order to be able to handle the cert */
	status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
							  IMESSAGE_GETATTRIBUTE, &complianceLevel,
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		return( status );

	/* 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 );
			status = readSequence( stream, &length );
			break;

		case CRYPT_CERTTYPE_CRL:
			readConstructed( stream, NULL, CTAG_CL_EXTENSIONS );
			status = readSequence( stream, &length );
			break;

		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 */
			status = readSequence( stream, &length );
			break;

		case CRYPT_CERTTYPE_CERTREQUEST:
			/* The read of cert request extensions 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 */
			endPos = stell( stream ) + attributeSize;
			do
				{
				const ATTRIBUTE_INFO *attributeInfoPtr;
				BYTE oid[ MAX_OID_SIZE ];
				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 = readRawObject( stream, oid, &oidLength,
										MAX_OID_SIZE, BER_OBJECT_IDENTIFIER );
				if( cryptStatusError( status ) )
					return( status );

				/* Check for a known attribute, which can happen with SET
				   cert requests.  If it's a known attribute, process it */
				attributeInfoPtr = oidToAttribute( attributeType, oid );
				if( attributeInfoPtr != NULL )
					{
					status = readSet( stream, &length );
					if( cryptStatusOK( status ) )
						status = readAttribute( stream, attributeListPtrPtr,
												attributeInfoPtr, length,
												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 ) )
						status = OK_SPECIAL;
					else
						/* It's unknown MS garbage, skip it */
						status = readUniversal( stream );
				}
			while( cryptStatusOK( status ) );
			if( status == OK_SPECIAL )
				{
				readSet( stream, NULL );
				status = readSequence( stream, &length );
				}
			break;

		case CRYPT_CERTTYPE_CMS_ATTRIBUTES:
			status = readConstructed( stream, &length,
									  CTAG_SI_AUTHENTICATEDATTRIBUTES );
			break;

		case CRYPT_CERTTYPE_REQUEST_CERT:
		case CRYPT_CERTTYPE_REQUEST_REVOCATION:
			/* CRMF/CMP attributes don't contain any wrapper so there's
			   nothing to read */
			length = attributeSize;
			status = CRYPT_OK;
			break;

		case CRYPT_CERTTYPE_RTCS_REQUEST:
			status = readSet( stream, &length );
			break;

		case CRYPT_CERTTYPE_RTCS_RESPONSE:
			status = readConstructed( stream, &length, CTAG_RP_EXTENSIONS );
			break;

		case CRYPT_CERTTYPE_OCSP_REQUEST:
			readConstructed( stream, &length, CTAG_OR_EXTENSIONS );
			status = readSequence( stream, &length );
			break;

		case CRYPT_CERTTYPE_OCSP_RESPONSE:
			readConstructed( stream, &length, CTAG_OP_EXTENSIONS );
			status = readSequence( stream, &length );
			break;

		default:
			assert( NOTREACHED );
			status = CRYPT_ERROR_BADDATA;
		}
	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 */
	while( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
		{
		const ATTRIBUTE_INFO *attributeInfoPtr;
		BYTE oid[ MAX_OID_SIZE ];
		BOOLEAN criticalFlag = FALSE, ignoreAttribute = FALSE;
		int attributeLength;

		/* Read the outer wrapper and determine the attribute type based on
		   the OID */
		readSequence( stream, NULL );
		status = readRawObject( stream, oid, &length, MAX_OID_SIZE,
								BER_OBJECT_IDENTIFIER );
		if( cryptStatusError( status ) )
			return( status );
		attributeInfoPtr = oidToAttribute( attributeType, oid );
		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 cert or display it to the user.  
		   Instead, we reject the cert 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, &attributeLength );
		else
			status = readOctetStringHole( stream, &attributeLength,
										  DEFAULT_TAG );
		if( cryptStatusError( status ) )
			{
			*errorLocus = ( attributeInfoPtr != NULL ) ? \
						  attributeInfoPtr->fieldID : CRYPT_ATTRIBUTE_NONE;
			*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
			return( status );
			}

		/* Thawte certs for a period of about 6 months incorrectly encoded
		   the authorityKeyIdentifier (containing a SHA-1 hash) with an
		   EXPLICIT SEQUENCE so we check for this here.  These were at one
		   time common enough that we provide a special-case workaround
		   rather than using a compliance level reduction as a fix */
		if( attributeInfoPtr != NULL && \
			attributeInfoPtr->fieldID == CRYPT_CERTINFO_AUTHORITYKEYIDENTIFIER && \
			attributeLength == 26 )
			{
			BYTE buffer[ 32 ];
			long offset = stell( stream );
			int length2, length3;

			/* Burrow down into the encoding to see if it's an incorrectly
			   encoded authorityKeyIdentifier.  There's a second type of
			   incorrect encoding that still uses an explicit tag but that
			   makes the contents the octet string data, this is rare and
			   isn't checked for here */
			readSequence( stream, &length );
			readConstructed( stream, &length2, 0 );
			status = readOctetString( stream, buffer, &length3, 32 );
			if( cryptStatusOK( status ) && \
				length == 24 && length2 == 22 && length3 == 20 )
				{
				/* It's a SEQUENCE { [0] EXPLICIT SEQUENCE { ..., add the
				   data as a keyIdentifier */
				status = addAttributeField( attributeListPtrPtr,
							CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER,
							CRYPT_ATTRIBUTE_NONE, buffer, 20,
							criticalFlag ? \
								( ATTR_FLAG_CRITICAL | ATTR_FLAG_BLOB ) : \
								ATTR_FLAG_BLOB, errorLocus, errorType );
				if( cryptStatusError( status ) )
					return( status );
				continue;
				}

			/* It's a correctly-encoded authorityKeyIdentifier, read it
			   normally */
			sClearError( stream );
			sseek( stream, offset );
			}

		/* If it's a known attribute, parse the payload */
		if( attributeInfoPtr != NULL )
			{
			status = readAttribute( stream, attributeListPtrPtr,
									attributeInfoPtr, attributeLength,
									criticalFlag, errorLocus, errorType );
			if( cryptStatusError( 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( attributeLength <= 0 )
			continue;

		/* It's an unrecognised or ignored attribute type, add the raw data
		   to the list of attributes */
		status = addAttribute( attributeType, attributeListPtrPtr, oid,
							   criticalFlag, sMemBufPtr( stream ),
							   attributeLength, 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;
				}
			return( status );
			}
		sSkip( stream, attributeLength );	/* Skip the attribute data */
		}

	return( CRYPT_OK );
	}

⌨️ 快捷键说明

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