📄 ext_rd.c
字号:
info in the decoding table */
if( !( flags & SETOF_FLAG_RESTARTPOINT ) && \
currentPos >= setofInfoPtr->endPos )
{
int status;
status = findItemEnd( &attributeInfoPtr, 0 );
if( cryptStatusError( status ) )
return( status );
}
}
ENSURES( iterationCount < SETOF_STATE_STACKSIZE );
*attributeInfoPtrPtr = attributeInfoPtr;
return( ( attributeInfoPtr != oldAttributeInfoPtr ) ? \
OK_SPECIAL : CRYPT_OK );
}
/****************************************************************************
* *
* Identified Item Management Routines *
* *
****************************************************************************/
/* Given a pointer to a set of SEQUENCE { type, value } entries, return a
pointer to the { value } entry appropriate for the data in the stream.
If the entry contains user data in the { value } portion then the
returned pointer points to this, if it contains a fixed value or isn't
present at all then the returned pointer points to the { type } portion */
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 2 ) ) \
static const ATTRIBUTE_INFO *findIdentifiedItem( INOUT STREAM *stream,
const ATTRIBUTE_INFO *attributeInfoPtr )
{
BYTE oid[ MAX_OID_SIZE + 8 ];
int oidLength, sequenceLength, iterationCount, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
REQUIRES_N( attributeInfoPtr->flags & FL_IDENTIFIER );
/* Skip the header and read the OID. We only check for a sane total
length in the debug version since this isn't a fatal error */
readSequence( stream, &sequenceLength );
status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( NULL );
sequenceLength -= oidLength;
assert( sequenceLength >= 0 );
/* Walk down the list of entries trying to match it to an allowed value.
Unfortunately we can't use the attributeInfoSize bounds check limit
here because we don't know how far through the attribute table we
already are, so we have to use a generic large value */
for( iterationCount = 0;
( attributeInfoPtr->flags & FL_IDENTIFIER ) && \
iterationCount < FAILSAFE_ITERATIONS_LARGE;
iterationCount++ )
{
const BYTE *oidPtr;
/* Skip the SEQUENCE and OID */
attributeInfoPtr++;
oidPtr = attributeInfoPtr->oid;
if( !( attributeInfoPtr->flags & FL_NONENCODING ) )
attributeInfoPtr++;
else
{
/* If this is a blob field we've hit a don't-care value (usually
the last in a series of type-and-value pairs) which ensures
that { type }s added after the encoding table was defined
don't get processed as errors, skip the field and continue */
if( attributeInfoPtr->fieldType == FIELDTYPE_BLOB )
{
/* If there's a { value } attached to the type, skip it */
if( sequenceLength > 0 )
sSkip( stream, sequenceLength );
return( attributeInfoPtr );
}
}
/* In case there's an error in the encoding table, make sure that we
don't die during parsing */
ENSURES_N( oidPtr != NULL );
/* If the OID matches, return a pointer to the value entry */
if( oidLength == sizeofOID( oidPtr ) && \
!memcmp( oidPtr, oid, sizeofOID( oidPtr ) ) )
{
/* If this is a fixed field and there's a value attached, skip
it */
if( ( attributeInfoPtr->flags & FL_NONENCODING ) && \
sequenceLength > 0 )
sSkip( stream, sequenceLength );
return( attributeInfoPtr );
}
/* The OID doesn't match, skip the { value } entry and continue. We
set the current nesting depth parameter to 1 since we've already
entered the SEQUENCE above */
status = findItemEnd( &attributeInfoPtr, 1 );
if( cryptStatusError( status ) )
return( NULL );
attributeInfoPtr++; /* Move to start of next item */
}
ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );
/* We reached the end of the set of entries without matching the OID */
return( NULL );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5, 6, 7 ) ) \
static int processIdentifiedItem( INOUT STREAM *stream,
/*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
IN_FLAGS( ATTR ) const int flags,
const SETOF_STACK *setofStack,
const ATTRIBUTE_INFO **attributeInfoPtrPtr,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
static const int dummy = CRYPT_UNUSED;
const SETOF_STATE_INFO *setofInfoPtr = setofTOS( setofStack );
const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( setofStack, sizeof( SETOF_STACK ) ) );
assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
assert( ( flags & ~( ATTR_FLAG_CRITICAL ) ) == 0 );
REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
REQUIRES( !( flags & ATTR_FLAG_INVALID ) );
/* Search for the identified item from the start of the set of items.
The 0-th value is the SET OF/SEQUENCE OF so we start the search at
the next entry which is the first FL_IDENTIFIER */
ENSURES( setofInfoPtr->infoStart->flags & FL_SETOF );
attributeInfoPtr = findIdentifiedItem( stream,
setofInfoPtr->infoStart + 1 );
if( attributeInfoPtr == NULL )
return( CRYPT_ERROR_BADDATA );
*attributeInfoPtrPtr = attributeInfoPtr;
/* If it's a subtyped field, continue from a new encoding table */
if( attributeInfoPtr->fieldType == FIELDTYPE_SUBTYPED )
return( OK_SPECIAL );
/* If it's not a special-case, non-encoding field, we're done */
if( !( attributeInfoPtr->flags & FL_NONENCODING ) )
return( CRYPT_OK );
/* If the { type, value } pair has a fixed value then the information
being conveyed is its presence, not its contents, so we add an
attribute corresponding to its ID and continue. The addition of the
attribute is a bit tricky, some of the fixed type-and-value pairs can
have multiple entries denoting things like { algorithm, weak key },
{ algorithm, average key }, { algorithm, strong key }, however all
that we're interested in is the strong key so we ignore the value and
only use the type (in his ordo est ordinem non servare). Since the
same type can be present multiple times (with different { value }s)
we ignore data duplicate errors and continue. If we're processing a
blob field type, we've ended up at a generic catch-any value and
can't do much with it */
if( attributeInfoPtr->fieldType != FIELDTYPE_BLOB )
{
int status;
/* Add the field type, discarding warnings about dups */
TRACE_FIELDTYPE( attributeInfoPtr, 0 );
status = addAttributeField( attributeListPtrPtr,
attributeInfoPtr->fieldID, CRYPT_ATTRIBUTE_NONE,
&dummy, CRYPT_UNUSED, flags, errorLocus,
errorType );
if( status == CRYPT_ERROR_INITED )
status = CRYPT_OK;
else
{
if( cryptStatusError( status ) )
return( CRYPT_ERROR_BADDATA );
}
}
/* Reset the attribute info position in preparation for the next value
and continue */
attributeInfoPtr = setofInfoPtr->infoStart + 1;
return( OK_SPECIAL );
}
/* Read a sequence of identifier fields of the form { oid, value OPTIONAL }.
This is used to read both SEQUENCE OF and CHOICE, with SEQUENCE OF
allowing multiple entries and CHOICE allowing only a single entry */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 6, 7 ) ) \
static int readIdentifierFields( INOUT STREAM *stream,
/*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
const ATTRIBUTE_INFO **attributeInfoPtrPtr,
IN_FLAGS( ATTR ) const int flags,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
const BOOLEAN isChoice = ( fieldID != CRYPT_ATTRIBUTE_NONE );
int count = 0, iterationCount;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
assert( flags == ATTR_FLAG_NONE );
REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
REQUIRES( !( flags & ATTR_FLAG_INVALID ) );
for( iterationCount = 0;
peekTag( stream ) == BER_OBJECT_IDENTIFIER && \
iterationCount < FAILSAFE_ITERATIONS_LARGE;
iterationCount++ )
{
const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
BYTE oid[ MAX_OID_SIZE + 8 ];
BOOLEAN addField = TRUE;
static const int dummy = CRYPT_UNUSED;
int oidLength, innerIterationCount, status;
/* Make sure that we don't die during parsing if there's an error in
the encoding table */
ENSURES( attributeInfoPtr->oid != NULL );
/* Read the OID and walk down the list of possible OIDs up to the end
of the group of alternatives trying to match it to an allowed
value */
status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
for( innerIterationCount = 0;
( oidLength != sizeofOID( attributeInfoPtr->oid ) || \
memcmp( attributeInfoPtr->oid, oid, oidLength ) ) && \
innerIterationCount < FAILSAFE_ITERATIONS_MED;
innerIterationCount++ )
{
/* If we've reached the end of the list and the OID wasn't
matched, exit */
if( ( attributeInfoPtr->flags & FL_SEQEND_MASK ) || \
!( attributeInfoPtr->flags & FL_MORE ) )
return( CRYPT_ERROR_BADDATA );
attributeInfoPtr++;
/* If this is a blob field we've hit a don't-care value which
ensures that { type }s added after the encoding table was
defined don't get processed as errors, skip the field and
continue */
if( attributeInfoPtr->fieldType == FIELDTYPE_BLOB )
{
addField = FALSE;
break;
}
/* Make sure that we don't die during parsing if there's an error
in the encoding table */
ENSURES( attributeInfoPtr->oid != NULL );
}
ENSURES( innerIterationCount < FAILSAFE_ITERATIONS_MED );
TRACE_FIELDTYPE( attributeInfoPtr, 0 );
if( addField )
{
/* The OID matches, add this field as an identifier field. This
will catch duplicate OIDs, since we can't add the same
identifier field twice */
if( isChoice )
{
/* If there's a field value present then this is a CHOICE of
attributes whose value is the field value so we add it with
this value */
status = addAttributeField( attributeListPtrPtr,
fieldID, CRYPT_ATTRIBUTE_NONE,
&attributeInfoPtr->fieldID, CRYPT_UNUSED,
flags, errorLocus, errorType );
}
else
{
/* It's a standard field */
status = addAttributeField( attributeListPtrPtr,
attributeInfoPtr->fieldID, CRYPT_ATTRIBUTE_NONE,
&dummy, CRYPT_UNUSED,
flags, errorLocus, errorType );
}
if( cryptStatusError( status ) )
return( status );
}
count++;
/* If there's more than one OID present in a CHOICE, it's an error */
if( isChoice && count > 1 )
{
*errorLocus = attributeInfoPtr->fieldID,
*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
return( CRYPT_ERROR_BADDATA );
}
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
/* We've processed the non-data field(s), move on to the next field.
We move to the last valid non-data field rather than the start of the
field following it since the caller needs to be able to check whether
there are more fields to follow using the current field's flags.
Unfortunately we can't use the attributeInfoSize bounds check limit
here because we don't know how far through the attribute table we
already are, so we have to use a generic large value */
iterationCount = 0;
while( !( ( *attributeInfoPtrPtr )->flags & FL_SEQEND_MASK ) && \
( ( *attributeInfoPtrPtr )->flags & FL_MORE ) && \
iterationCount++ < FAILSAFE_ITERATIONS_LARGE )
( *attributeInfoPtrPtr )++;
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Attribute/Attribute Field Read Routines *
* *
****************************************************************************/
/* Generic error-handler that sets extended error codes */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int fieldErrorReturn( OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType,
IN_ERROR const int status,
IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -