📄 ext_chk.c
字号:
/* If the field is present in this attributeTypeAndValue, return */
if( attributeInfoPtr->fieldID == fieldID )
return( CRYPT_OK );
/* If we're at the end of the attribute or the attributeTypeAndValue,
exit the loop before adjusting the attributeInfoPtr so that we're
still pointing at the end-of-attribute field */
if( nestLevel <= 0 || !( attributeInfoPtr->flags & FL_MORE ) )
break;
attributeInfoPtr++;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
/* The field isn't present, update the pointer to the next
attributeTypeAndValue or the end of the attribute */
*attributeInfoPtrPtr = ( ATTRIBUTE_INFO * ) attributeInfoPtr;
return( CRYPT_ERROR_NOTFOUND );
}
/* State machine for checking a CHOICE. When we get to the start of a
CHOICE we move from CHOICE_NONE to CHOICE_START. Once we've checked one
of the CHOICE options we move to CHOICE_DONE. If a further option is
found in the CHOICE_DONE state we record an error. This is a somewhat
crude mechanism that works because the only CHOICE fields that can't be
handled by rewriting them as alternative representations are complete
attributes so that the CHOICE applies over the entire attribute. If a
CHOICE is ever present as an attribute subfield then the checking would
be handled by recursively checking it as a subtyped field */
typedef enum { CHOICE_NONE, CHOICE_START, CHOICE_DONE } CHOICE_STATE;
/* Check an entry in the attribute table. While we're performing the check
we need to pass a lot of state information around, this is contained in
the following structure */
typedef struct {
/* State information. When we're encoding a subtyped field (using an
alternative encoding table) we need to remember the field ID of the
parent to both tell the encoding routines that we're using an
alternative encoding table and to remember the overall field ID so we
don't treat two adjacent field subfields as though they were part of
the same parent field. If we're not currently encoding a subtyped
field, this field is set to CRYPT_ATTRIBUTE_NONE */
ATTRIBUTE_LIST *attributeListPtr; /* Position in attribute list */
ATTRIBUTE_INFO *attributeInfoPtr; /* Position in attribute table */
CRYPT_ATTRIBUTE_TYPE subtypeParent; /* Parent of subtype being processed */
CHOICE_STATE choiceState; /* State of CHOICE processing */
/* Encoding stack. When we're encoding subfields the stack contains
items from both the subfield and the encapsulating field so we also
record the current stack top to make sure that we don't go past this
level when popping items after we've finished encoding a subfield */
ATTRIBUTE_STACK stack[ ATTRIBUTE_STACKSIZE + 8 ];
int stackPos; /* Encoding stack position */
int stackTop;
/* Error information */
CRYPT_ATTRIBUTE_TYPE errorLocus;/* Error locus */
int errorType; /* Error type */
} ATTRIBUTE_CHECK_INFO;
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
static int stackInfo( INOUT_ARRAY( ATTRIBUTE_CHECK_INFO ) \
ATTRIBUTE_CHECK_INFO *attributeCheckInfo,
IN_OPT ATTRIBUTE_LIST *attributeListPtr,
IN ATTRIBUTE_INFO *attributeInfoPtr )
{
ATTRIBUTE_STACK *stack = attributeCheckInfo->stack;
assert( isWritePtr( attributeCheckInfo, \
sizeof( ATTRIBUTE_CHECK_INFO ) ) );
assert( attributeListPtr == NULL || \
isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
REQUIRES( attributeCheckInfo->stackPos >= 0 && \
attributeCheckInfo->stackPos < ATTRIBUTE_STACKSIZE - 1 );
stack[ attributeCheckInfo->stackPos ].size = 0;
stack[ attributeCheckInfo->stackPos ].attributeListPtr = attributeListPtr;
stack[ attributeCheckInfo->stackPos++ ].attributeInfoPtr = attributeInfoPtr;
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkAttribute( INOUT_ARRAY( ATTRIBUTE_CHECK_INFO ) \
ATTRIBUTE_CHECK_INFO *attributeCheckInfo );
/* Forward declaration for function */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int checkAttributeEntry( INOUT_ARRAY( ATTRIBUTE_CHECK_INFO ) \
ATTRIBUTE_CHECK_INFO *attributeCheckInfo )
{
ATTRIBUTE_LIST *attributeListPtr = attributeCheckInfo->attributeListPtr;
ATTRIBUTE_INFO *attributeInfoPtr = attributeCheckInfo->attributeInfoPtr;
ATTRIBUTE_STACK *stack = attributeCheckInfo->stack;
CRYPT_ATTRIBUTE_TYPE fieldID;
assert( isWritePtr( attributeCheckInfo, \
sizeof( ATTRIBUTE_CHECK_INFO ) ) );
/* Determine the fieldID for the current attribute field. Once we get
to the end of an attribute list entry we may still run through this
function multiple times with attributeListPtr set to NULL but
attributeInfoPtr advancing on each step, see the comment in
updateStackedInfo() for details */
if( attributeListPtr == NULL || \
attributeListPtr->fieldID == CRYPT_ATTRIBUTE_NONE )
{
/* If we've reached the end of the list of recognised attributes,
use a non-ID that doesn't match any table entry */
fieldID = CRYPT_IATTRIBUTE_LAST;
}
else
{
/* If we're encoding a subtyped field the fieldID is the field ID
within the parent field, or the subFieldID */
if( attributeCheckInfo->subtypeParent == attributeListPtr->fieldID )
fieldID = attributeListPtr->subFieldID;
else
{
/* It's a standard attribute field */
fieldID = attributeListPtr->fieldID;
}
}
/* If the field in the attribute list matches the one in the table,
process it and move on to the next one */
if( attributeListPtr != NULL && attributeInfoPtr->fieldID == fieldID )
{
/* 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, 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 for which each CHOICE field is
optional but at least one component of the CHOICE must be
present */
retIntError();
}
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_ERRTYPE_NONE )
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,
CRYPT_COMPLIANCELEVEL_STANDARD );
if( attributeCheckInfo->stackPos > 0 )
{
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 that we want */
if( attributeInfoPtr->flags & FL_IDENTIFIER )
{
BOOLEAN endOfAttributeField = FALSE;
int status;
status = checkComponentPresent( fieldID, &attributeInfoPtr );
if( status == CRYPT_ERROR_NOTFOUND )
{
/* 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 );
}
if( cryptStatusError( status ) )
return( status );
/* 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 ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -