📄 certechk.c
字号:
{
/* If it's a subtyped or CHOICE field, check the components using
their own encoding table */
if( attributeInfoPtr->fieldType == FIELDTYPE_SUBTYPED || \
attributeInfoPtr->fieldType == FIELDTYPE_CHOICE )
{
int status;
/* Switch to the new encoding table and record the fact that
we've done this, and set the new stack top to the level at
which we start encoding the subtype */
if( attributeInfoPtr->fieldType == FIELDTYPE_CHOICE )
{
/* Stack the value start position in the attribute list and
record the fact that we're processing a CHOICE */
status = stackInfo( attributeCheckInfo, attributeListPtr,
attributeInfoPtr );
if( cryptStatusError( status ) )
return( status );
attributeCheckInfo->choiceState = CHOICE_START;
}
attributeCheckInfo->attributeInfoPtr = \
( ATTRIBUTE_INFO * ) attributeInfoPtr->extraData;
attributeCheckInfo->subtypeParent = attributeListPtr->fieldID;
attributeCheckInfo->stackTop = attributeCheckInfo->stackPos;
status = checkAttribute( attributeCheckInfo );
attributeCheckInfo->attributeInfoPtr = attributeInfoPtr;
attributeCheckInfo->subtypeParent = CRYPT_ATTRIBUTE_NONE;
attributeCheckInfo->stackTop = 0;
if( !( attributeInfoPtr->flags & FL_OPTIONAL ) && \
attributeCheckInfo->attributeListPtr == attributeListPtr )
{
/* The subtyped field was non-optional but we failed to match
anything in it against the current attribute list entry,
there's a problem with the encoding table. This check is
used to catch situations where a subtyped field is used to
encode a CHOICE, where each CHOICE field is optional but
at least one component of the CHOICE must be present */
assert( NOTREACHED );
return( CRYPT_ERROR_FAILED );
}
return( status );
}
/* If there's an extended validation function attached to this field,
call it */
if( attributeInfoPtr->extraData != NULL )
{
VALIDATION_FUNCTION validationFunction = \
( VALIDATION_FUNCTION ) attributeInfoPtr->extraData;
attributeCheckInfo->errorType = validationFunction( attributeListPtr );
if( attributeCheckInfo->errorType != CRYPT_OK )
return( CRYPT_ERROR_INVALID );
}
/* If this is an optional field and the value is the same as the
default value, remember that it doesn't get encoded */
if( ( attributeInfoPtr->flags & FL_DEFAULT ) && \
( attributeInfoPtr->defaultValue == attributeListPtr->intValue ) )
{
attributeListPtr->flags |= ATTR_FLAG_DEFAULTVALUE;
attributeCheckInfo->attributeListPtr = attributeListPtr->next;
return( CRYPT_OK );
}
/* Remember the encoded size of this field */
attributeListPtr->attributeInfoPtr = attributeInfoPtr;
attributeListPtr->encodedSize = writeAttributeField( NULL, attributeListPtr );
if( attributeCheckInfo->stackPos )
stack[ attributeCheckInfo->stackPos - 1 ].size += attributeListPtr->encodedSize;
/* If this is a CHOICE field, update the choice state */
if( attributeCheckInfo->choiceState != CHOICE_NONE )
{
if( attributeCheckInfo->choiceState == CHOICE_DONE )
{
/* If we've already processed one of the CHOICE options, there
can't be another one present */
attributeCheckInfo->errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
return( CRYPT_ERROR_INVALID );
}
if( attributeCheckInfo->choiceState == CHOICE_START )
/* Remember that we've seen a CHOICE option */
attributeCheckInfo->choiceState = CHOICE_DONE;
}
/* Move on to the next attribute field */
attributeCheckInfo->attributeListPtr = attributeListPtr->next;
return( CRYPT_OK );
}
/* If it's an attributeTypeAndValue sequence, check whether it contains
the field we want */
if( attributeInfoPtr->flags & FL_IDENTIFIER )
{
BOOLEAN endOfAttributeField = FALSE;
int status;
if( !checkComponentPresent( fieldID, &attributeInfoPtr ) )
{
/* Since we've jumped over several items we may be pointing at an
end-of-sequence flag for which no sequence start was stacked,
so we skip the stack update step */
attributeCheckInfo->attributeInfoPtr = attributeInfoPtr;
return( OK_SPECIAL );
}
/* Stack the position of the sequence start and the following OID */
status = stackInfo( attributeCheckInfo, attributeListPtr,
attributeInfoPtr++ );
if( cryptStatusOK( status ) )
status = stackInfo( attributeCheckInfo, attributeListPtr,
attributeInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* If the OID entry is marked as the end-of-sequence, there are no
parameters attached so we move on to the next entry */
if( attributeInfoPtr->flags & FL_SEQEND_MASK )
endOfAttributeField = TRUE;
/* Sometimes the OID is followed by a fixed-value blob field that
constitutes parameters for the OID, if this is present we stack it
as well */
if( attributeInfoPtr[ 1 ].flags & FL_NONENCODING )
{
attributeInfoPtr++;
status = stackInfo( attributeCheckInfo, attributeListPtr,
attributeInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* If the fields are fixed-value, we always move on to the next
entry since there are no user-supplied parameters present */
endOfAttributeField = TRUE;
}
attributeCheckInfo->attributeInfoPtr = attributeInfoPtr;
if( endOfAttributeField )
/* If this is all that needs to be encoded, move on to the next
attribute field */
attributeCheckInfo->attributeListPtr = attributeListPtr->next;
return( CRYPT_OK );
}
/* If it's a sequence/set or a non-encoding value then it's a nop entry
used only for encoding purposes and can be skipped, however we need to
remember it for later encoding */
if( attributeInfoPtr->fieldType == BER_SEQUENCE || \
attributeInfoPtr->fieldType == BER_SET || \
attributeInfoPtr->flags & FL_NONENCODING )
/* Stack the sequence or value start position in the attribute list */
return( stackInfo( attributeCheckInfo, attributeListPtr,
attributeInfoPtr ) );
/* If it's a non-optional field and the attribute field doesn't match,
it's an error - attribute attributeID is missing field
attributeInfoPtr->fieldID (optional subfield
attributeInfoPtr->subFieldID) (set by the error handler in the calling
code) */
if( !( attributeInfoPtr->flags & FL_OPTIONAL ) )
{
attributeCheckInfo->errorType = CRYPT_ERRTYPE_ATTR_ABSENT;
return( CRYPT_ERROR_NOTINITED );
}
return( CRYPT_OK );
}
/* Check an individual attribute */
static int checkAttribute( ATTRIBUTE_CHECK_INFO *attributeCheckInfo )
{
ATTRIBUTE_LIST *restartEntry = NULL;
ATTRIBUTE_INFO *restartPoint;
int restartStackPos, iterationCount = 0;
BOOLEAN attributeContinues;
assert( isWritePtr( attributeCheckInfo, ATTRIBUTE_CHECK_INFO ) );
/* Step through the attribute comparing the fields which are present in
the attribute list with the fields which should be present according
to the table, and set encoding sync points as required */
do
{
int status;
/* Sanity check to make sure we don't fall off the end of the
table */
if( attributeCheckInfo->attributeInfoPtr->fieldID == CRYPT_ERROR )
{
assert( NOTREACHED );
return( CRYPT_ERROR_OVERFLOW );
}
/* Check whether this is a repeated instance of the same attribute
and if it is, remember the encoding restart point. We have to do
this before we check the attribute info because it usually
updates the info after the check */
if( restartEntry == NULL && \
attributeCheckInfo->attributeListPtr != NULL && \
attributeCheckInfo->attributeListPtr->next != NULL && \
( attributeCheckInfo->attributeListPtr->fieldID == \
attributeCheckInfo->attributeListPtr->next->fieldID ) && \
( attributeCheckInfo->attributeListPtr->subFieldID == \
attributeCheckInfo->attributeListPtr->next->subFieldID ) )
{
restartEntry = attributeCheckInfo->attributeListPtr;
restartPoint = attributeCheckInfo->attributeInfoPtr + 1;
restartStackPos = attributeCheckInfo->stackPos + 1;
}
/* Check the current encoding table entry */
status = checkAttributeEntry( attributeCheckInfo );
if( status != OK_SPECIAL )
{
if( cryptStatusError( status ) )
{
attributeCheckInfo->errorLocus = attributeCheckInfo->attributeInfoPtr->fieldID;
return( status );
}
/* If this is the end of a constructed item, unstack it and
update the attribute list entry with the length information.
If it's a sequence with all fields optional (so that nothing
gets encoded), we don't do anything */
updateStackedInfo( attributeCheckInfo->stack,
&attributeCheckInfo->stackPos,
decodeNestingLevel( attributeCheckInfo->attributeInfoPtr->flags ),
TRUE );
}
/* If there's another instance of the same item, don't move on to
the next table entry */
if( restartEntry != NULL && \
restartEntry != attributeCheckInfo->attributeListPtr )
{
#if 0
/* Currently we don't allow the creation of multivalued
instances of fields, although we can read certs which contain
them */
assert( NOTREACHED );
#endif /* 0 */
/* Restart at the table entry for the previous instance of the
item, and adjust the stack to match */
restartEntry = NULL;
attributeCheckInfo->attributeInfoPtr = restartPoint;
attributeContinues = TRUE;
if( attributeCheckInfo->stackPos > restartStackPos )
updateStackedInfo( attributeCheckInfo->stack,
&attributeCheckInfo->stackPos,
attributeCheckInfo->stackPos - restartStackPos,
TRUE );
continue;
}
/* Move on to the next table entry. We have to check the
continuation flag before we move to the next table entry in order
to include processing of the last field in an attribute */
attributeContinues = ( attributeCheckInfo->attributeInfoPtr->flags & FL_MORE ) ? TRUE : FALSE;
attributeCheckInfo->attributeInfoPtr++;
}
while( attributeContinues && iterationCount++ < 1000 );
attributeCheckInfo->choiceState = CHOICE_NONE;
/* Safety check in case of an invalid encoding table */
if( iterationCount >= 1000 )
{
assert( NOTREACHED );
return( CRYPT_ERROR_OVERFLOW );
}
/* We've reached the end of the attribute, if there are still constructed
objects stacked, unstack them and update their length information. If
it's a sequence with all fields optional (so that nothing gets
encoded), we don't do anything */
updateStackedInfo( attributeCheckInfo->stack, &attributeCheckInfo->stackPos,
attributeCheckInfo->stackPos - attributeCheckInfo->stackTop,
FALSE );
return( CRYPT_OK );
}
/* Check the entire list of attributes */
int checkAttributes( const ATTRIBUTE_TYPE attributeType,
const ATTRIBUTE_LIST *listHeadPtr,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
ATTRIBUTE_CHECK_INFO attributeCheckInfo;
const ATTRIBUTE_INFO *attributeInfoStartPtr = \
selectAttributeInfo( attributeType );
ATTRIBUTE_LIST *attributeListPtr;
/* If we've already done a validation pass, some of the fields will
contain values that were previously set, so before we begin we walk
down the list resetting the fields that are updated by this
function */
for( attributeListPtr = ( ATTRIBUTE_LIST * ) listHeadPtr;
attributeListPtr != NULL && attributeListPtr->fieldID != CRYPT_ATTRIBUTE_NONE;
attributeListPtr = attributeListPtr->next )
{
attributeListPtr->attributeInfoPtr = NULL;
attributeListPtr->encodedSize = attributeListPtr->fifoPos = \
attributeListPtr->fifoEnd = 0;
attributeListPtr->flags &= ~ATTR_FLAG_DEFAULTVALUE;
}
/* Set up the attribute-checking state information */
memset( &attributeCheckInfo, 0, sizeof( ATTRIBUTE_CHECK_INFO ) );
attributeCheckInfo.attributeListPtr = ( ATTRIBUTE_LIST * ) listHeadPtr;
attributeCheckInfo.attributeInfoPtr = ( ATTRIBUTE_INFO * ) attributeInfoStartPtr;
/* Walk down the list of known attributes checking each one for
consistency */
while( attributeCheckInfo.attributeListPtr != NULL && \
attributeCheckInfo.attributeListPtr->fieldID != CRYPT_ATTRIBUTE_NONE )
{
int status;
/* Find the start of this attribute in the attribute info table and
remember it as an encoding sync point. Comparing the field ID
with the attribute ID is usually valid because the attribute info
table always begins the series of entries for an attribute with
the attribute ID. The one exception is where the attribute ID is
the same as the field ID but they're separate entries in the
table, in which case the first entries will contain a
FIELDID_FOLLOWS code to indicate that a following field contains
the attribute/fieldID */
while( ( attributeCheckInfo.attributeInfoPtr->fieldID != \
attributeCheckInfo.attributeListPtr->attributeID ) && \
attributeCheckInfo.attributeInfoPtr->fieldID != CRYPT_ERROR )
attributeCheckInfo.attributeInfoPtr++;
if( attributeCheckInfo.attributeInfoPtr->fieldID == CRYPT_ERROR )
{
/* Safety check in case of an invalid encoding table */
assert( NOTREACHED );
return( CRYPT_ERROR_OVERFLOW );
}
while( attributeCheckInfo.attributeInfoPtr != attributeInfoStartPtr && \
attributeCheckInfo.attributeInfoPtr[ -1 ].fieldID == FIELDID_FOLLOWS )
attributeCheckInfo.attributeInfoPtr--;
/* Check this attribute */
status = checkAttribute( &attributeCheckInfo );
if( cryptStatusError( status ) )
{
*errorLocus = attributeCheckInfo.errorLocus;
*errorType = attributeCheckInfo.errorType;
return( status );
}
}
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -