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

📄 certexrw.c

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

		/* Read the tag for the field and make sure it matches what we're 
		   expecting, unless it's a (non-explicitly-tagged) blob field which 
		   we don't try and interpret in any way */
		if( ( attributeInfoPtr->fieldType != FIELDTYPE_BLOB || \
			  ( attributeInfoPtr->flags & FL_EXPLICIT ) ) && \
			readTag( stream ) != tag )
			return( fieldErrorReturn( errorLocus, errorType, CRYPT_ERROR_BADDATA,
									  attributeInfoPtr->fieldID ) );

		/* Explicitly tagged field: Read the length for the previous field
		   and the inner field type and make sure it matches what we're
		   expecting, unless the inner field is a blob in which case it'll
		   be processed as an atomic unit by readAttributeField() */
		if( attributeInfoPtr->flags & FL_EXPLICIT )
			{
			assert( isTagged );
			status = readShortLength( stream );
			if( !cryptStatusError( status ) && \
				attributeInfoPtr->fieldType != FIELDTYPE_BLOB && \
				readTag( stream ) != attributeInfoPtr->fieldType )
				status = CRYPT_ERROR_BADDATA;
			if( cryptStatusError( status ) )
				return( fieldErrorReturn( errorLocus, errorType, status,
										  attributeInfoPtr->fieldID ) );
			}

		/* Read the field data */
		status = readAttributeField( stream, attributeListPtrPtr,
									 attributeInfoPtr, subtypeParent,
									 flags | inheritedFlags, errorLocus, errorType );
		if( cryptStatusError( status ) )
			/* Adding invalid attribute data can return detailed error codes 
			   which report the exact parameter which was wrong, we don't
			   need this much detail so we convert a parameter error into a
			   more general bad data status */
			return( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status );

		/* Move on to the next field.  If we've reached the end of a subtyped
		   field, switch back to the main table */
continueDecoding:
		attributeContinues = ( attributeInfoPtr->flags & FL_MORE ) ? TRUE : FALSE;
		if( !attributeContinues && savedAttributeInfoPtr != NULL )
			{
			/* Pop the previous parse state and clear the stack entry */
			attributeInfoPtr = savedAttributeInfoPtr;
			savedAttributeInfoPtr = NULL;
			setEndPos = savedSetEndPos;
			savedSetEndPos = 0;
			subtypeParent = CRYPT_ATTRIBUTE_NONE;
			inheritedFlags = ATTR_FLAG_NONE;
			attributeContinues = ( attributeInfoPtr->flags & FL_MORE ) ? TRUE : FALSE;
			}
		attributeInfoPtr++;

		/* If this is the end of a collection of items but there are more 
		   entries present, go back to the restart point and try again.  At
		   the moment these items always occur at the end of an attribute,
		   this may need to be changed later */
		if( !attributeContinues && setEndPos && isVariableSet && \
			stell( stream ) < setEndPos - setEndEOC )
			{
			attributeInfoPtr = setofItemStartPtr;
			attributeContinues = TRUE;
			}
		}
	while( attributeContinues && sStatusOK( stream ) && \
		   stell( stream ) < endPos );

	/* 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;
			int status;

			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 (eg
		   Microsoft's extensive crlDistributionPoints lists providing
		   redundant pointers to the same inaccessible MS-internal servers),
		   if there's any extraneous data left we just skip it */
		while( stell( stream ) < endPos && peekTag( stream ) )
			readUniversal( stream );

	/* 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 which always follows attributes in certs, cert
	   requests, and CMS attributes.  Per varios casus... */
	while( !peekTag( stream ) )
		checkEOC( stream );

	return( sGetStatus( stream ) );
	}

/* 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 ) ? \
										 ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE;
	const int wrapperTag = ( attributeType == ATTRIBUTE_CMS ) ? \
						   BER_SET : BER_OCTETSTRING;
	int decodeCritical, tag, length, endPos, 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, per-entry extensions and entire-CRL/request 
	   extensions which have different tagging.  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_CR_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 which 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 1930's, 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 
			   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;
			while( sStatusOK( stream ) )
				{
				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 );
					if( cryptStatusError( status ) )
						return( status );
					}
				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 ) )
						break;
					else
						/* It's unknown MS garbage, skip it */
						readUniversal( stream );
				}
			readSet( stream, &length );
			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_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 = ( int ) stell( stream ) + length;

	/* Read config settings which affect the way we process attributes */
	krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
					 RESOURCE_IMESSAGE_GETATTRIBUTE, &decodeCritical,
					 CRYPT_OPTION_CERT_DECODE_CRITICAL );

	/* Read the collection of attributes.  We allow for a bit of slop for
	   software which 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;
		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 );

		/* Read the optional critical flag if it's a certificate.  If the
		   extension is marked as being critical and we don't recognise it,
		   we can't process the certificate or CRL.  Because there are
		   logical problems in the use of the critical flag, we allow this to
		   be overridden if necessary with the CRYPT_OPTION_CERT_DECODE_-
		   CRITICAL option */
		if( attributeType != ATTRIBUTE_CMS )
			{
			if( peekTag( stream ) == BER_BOOLEAN )
				status = readBoolean( stream, &criticalFlag );
			if( cryptStatusOK( status ) && criticalFlag && \
				attributeInfoPtr == NULL && decodeCritical )
				status = CRYPT_ERROR_PERMISSION;
			if( cryptStatusError( status ) )
				{
				if( attributeInfoPtr != NULL )
					*errorLocus = attributeInfoPtr->fieldID;
				*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
				return( status );
				}
			}

		/* Read the wrapper around the attribute payload */
		tag = readTag( stream );
		attributeLength = readShortLength( stream );
		if( cryptStatusError( attributeLength ) )
			return( attributeLength );
		if( tag != wrapperTag )
			{
			*errorLocus = attributeInfoPtr->fieldID;
			*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
			return( CRYPT_ERROR_BADDATA );
			}

		/* Thawte certs for a period of about 6 months incorrectly encoded
		   the authorityKeyIdentifier with an EXPLICIT SEQUENCE so we check
		   for this here */
		if( attributeInfoPtr != NULL && \
			attributeInfoPtr->fieldID == CRYPT_CERTINFO_AUTHORITYKEYIDENTIFIER && \
			attributeLength <= 128 )
			{
			BYTE buffer[ 128 ];
			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 which still uses an explicit tag but which
			   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, 128 );
			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 );

⌨️ 快捷键说明

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