📄 ext_rd.c
字号:
{
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 */
if( oidPtr == NULL )
{
assert( NOTREACHED );
return( 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 */
}
/* We reached the end of the set of entries without matching the OID */
return( NULL );
}
static int processIdentifiedItem( STREAM *stream,
ATTRIBUTE_LIST **attributeListPtrPtr,
const int flags, const SETOF_STACK *setofStack,
const ATTRIBUTE_INFO **attributeInfoPtrPtr,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
static const int dummy = CRYPT_UNUSED;
const SETOF_STATE_INFO *setofInfoPtr = setofTOS( setofStack );
const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( setofStack, sizeof( SETOF_STACK ) ) );
assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
/* 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 */
assert( 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 */
static int readIdentifierFields( STREAM *stream,
ATTRIBUTE_LIST **attributeListPtrPtr,
const ATTRIBUTE_INFO **attributeInfoPtrPtr,
const int flags,
const CRYPT_ATTRIBUTE_TYPE fieldID,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
const BOOLEAN isChoice = ( fieldID != CRYPT_ATTRIBUTE_NONE );
int count = 0;
assert( !( flags & ATTR_FLAG_INVALID ) );
assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
while( peekTag( stream ) == BER_OBJECT_IDENTIFIER )
{
const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
BYTE oid[ MAX_OID_SIZE ];
BOOLEAN addField = TRUE;
static const int dummy = CRYPT_UNUSED;
int oidLength, status;
/* Make sure that we don't die during parsing if there's an error in
the encoding table */
if( attributeInfoPtr->oid == NULL )
{
assert( NOTREACHED );
return( CRYPT_ERROR_FAILED );
}
/* 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 = readRawObject( stream, oid, &oidLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
while( oidLength != sizeofOID( attributeInfoPtr->oid ) || \
memcmp( attributeInfoPtr->oid, oid, oidLength ) )
{
/* 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 */
if( attributeInfoPtr->oid == NULL )
{
assert( NOTREACHED );
return( CRYPT_ERROR_FAILED );
}
}
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 );
}
}
/* 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 */
while( !( ( *attributeInfoPtrPtr )->flags & FL_SEQEND_MASK ) && \
( ( *attributeInfoPtrPtr )->flags & FL_MORE ) )
( *attributeInfoPtrPtr )++;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Attribute/Attribute Field Read Routines *
* *
****************************************************************************/
/* Generic error-handler that sets extended error codes */
static int fieldErrorReturn( CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType, const int status,
const CRYPT_ATTRIBUTE_TYPE fieldID )
{
/* Since some fields are internal-use only (e.g. meaningless blob data,
version numbers, and other paraphernalia) we only set the locus if
it has a meaningful value */
*errorLocus = ( fieldID > CRYPT_CERTINFO_FIRST && \
fieldID < CRYPT_CERTINFO_LAST ) ? \
fieldID : CRYPT_ATTRIBUTE_NONE;
*errorType = CRYPT_ERRTYPE_ATTR_VALUE;
return( status );
}
/* Switch from the main encoding table to a subtype encoding table */
static ATTRIBUTE_INFO *switchToSubtype( const ATTRIBUTE_INFO *attributeInfoPtr,
SETOF_STATE_INFO *setofInfoPtr )
{
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( isReadPtr( attributeInfoPtr->extraData,
sizeof( ATTRIBUTE_INFO ) ) );
assert( isWritePtr( setofInfoPtr, sizeof( SETOF_STATE_INFO ) ) );
/* Record the subtype parent information */
setofInfoPtr->subtypeParent = attributeInfoPtr->fieldID;
setofInfoPtr->inheritedFlags = \
( attributeInfoPtr->flags & FL_MULTIVALUED ) ? \
ATTR_FLAG_MULTIVALUED : ATTR_FLAG_NONE;
/* If the subtype ends once the current SET/SEQUENCE ends, remember this
so that we return to the main type when appropriate */
if( ( attributeInfoPtr->flags & FL_SEQEND_MASK ) || \
!( attributeInfoPtr->flags & FL_MORE ) )
setofInfoPtr->flags |= SETOF_FLAG_SUBTYPED;
/* Switch to the subtype encoding table */
return( ( ATTRIBUTE_INFO * ) attributeInfoPtr->extraData );
}
/* Read the contents of an attribute field. This uses the readXXXData()
variants of the read functions because the field that we're reading may
be tagged, so we process the tag at a higher level and only read the
contents here */
static int readAttributeField( STREAM *stream,
ATTRIBUTE_LIST **attributeListPtrPtr,
const ATTRIBUTE_INFO *attributeInfoPtr,
const CRYPT_ATTRIBUTE_TYPE subtypeParent,
const int flags,
CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
CRYPT_ATTRIBUTE_TYPE fieldID, subFieldID;
const int fieldType = attributeInfoPtr->fieldType;
int length, status;
assert( !( flags & ATTR_FLAG_INVALID ) );
assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
/* Set up the field identifiers depending on whether it's a normal field
or a subfield of a parent field */
if( subtypeParent == CRYPT_ATTRIBUTE_NONE )
{
fieldID = attributeInfoPtr->fieldID;
subFieldID = CRYPT_ATTRIBUTE_NONE;
}
else
{
fieldID = subtypeParent;
subFieldID = attributeInfoPtr->fieldID;
}
/* Read the field as appropriate */
switch( fieldType )
{
case BER_INTEGER:
case BER_ENUMERATED:
case BER_BITSTRING:
case BER_BOOLEAN:
case BER_NULL:
{
BOOLEAN boolean;
long longValue;
int value;
/* Read the data as appropriate */
switch( fieldType )
{
case BER_BITSTRING:
status = readBitStringData( stream, &value );
break;
case BER_BOOLEAN:
status = readBooleanData( stream, &boolean );
value = boolean;
break;
case BER_ENUMERATED:
status = readEnumeratedData( stream, &value );
break;
case BER_INTEGER:
status = readShortIntegerData( stream, &longValue );
value = ( int ) longValue;
break;
case BER_NULL:
/* NULL values have no associated data so we explicitly
set the value to CRYPT_UNUSED to ensure that this is
returned on any attempt to read it */
value = CRYPT_UNUSED;
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR );
}
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
/* Add the data for this attribute field */
return( addAttributeField( attributeListPtrPtr, fieldID,
subFieldID, &value, CRYPT_UNUSED,
flags, errorLocus, errorType ) );
}
case BER_TIME_GENERALIZED:
case BER_TIME_UTC:
{
time_t timeVal;
if( fieldType == BER_TIME_GENERALIZED )
status = readGeneralizedTimeData( stream, &timeVal );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -