📄 certexrd.c
字号:
/* Read the data as appropriate */
switch( attributeInfoPtr->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 ) );
}
if( attributeInfoPtr->fieldType == BER_TIME_GENERALIZED || \
attributeInfoPtr->fieldType == BER_TIME_UTC )
{
time_t timeVal;
if( attributeInfoPtr->fieldType == BER_TIME_GENERALIZED )
status = readGeneralizedTimeData( stream, &timeVal );
else
status = readUTCTimeData( stream, &timeVal );
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
/* Add the data for this attribute field */
return( addAttributeField( attributeListPtrPtr, fieldID, subFieldID,
&timeVal, sizeof( time_t ), flags,
errorLocus, errorType ) );
}
/* If it's a string type or a blob, read it in as a blob (the only
difference being that for a true blob we read the tag + length as
well) */
if( attributeInfoPtr->fieldType == BER_STRING_BMP || \
attributeInfoPtr->fieldType == BER_STRING_IA5 || \
attributeInfoPtr->fieldType == BER_STRING_ISO646 || \
attributeInfoPtr->fieldType == BER_STRING_NUMERIC || \
attributeInfoPtr->fieldType == BER_STRING_PRINTABLE || \
attributeInfoPtr->fieldType == BER_STRING_T61 || \
attributeInfoPtr->fieldType == BER_STRING_UTF8 || \
attributeInfoPtr->fieldType == BER_OCTETSTRING || \
attributeInfoPtr->fieldType == FIELDTYPE_BLOB )
{
BYTE buffer[ 256 ];
/* Read in the string to a maximum length of 256 bytes. Anything
longer is quietly truncated, strings in certs shouldn't be this
long anyway */
if( attributeInfoPtr->fieldType == FIELDTYPE_BLOB )
status = readRawObjectTag( stream, buffer, &length, 256, CRYPT_UNUSED );
else
status = readOctetStringData( stream, buffer, &length, 256 );
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
/* There are enough broken certs out there with enormously long
disclaimers in the cert policy explicit text field that we
have to specifically check for them here and truncate the text
at a valid length in order to get it past the extension
validity checking code */
if( fieldID == CRYPT_CERTINFO_CERTPOLICY_EXPLICITTEXT && \
length > 200 )
length = 200;
/* Add the data for this attribute field, setting the payload-blob
flag to disable type-checking of the payload data so users can
cram any old rubbish into the strings */
return( addAttributeField( attributeListPtrPtr, fieldID, subFieldID,
buffer, length, flags | ATTR_FLAG_BLOB_PAYLOAD,
errorLocus, errorType ) );
}
/* If it's an OID, we need to reassemble the entire OID since this is the
form expected by addAttributeField() */
if( attributeInfoPtr->fieldType == BER_OBJECT_IDENTIFIER )
{
BYTE oid[ MAX_OID_SIZE ];
oid[ 0 ] = BER_OBJECT_IDENTIFIER; /* Add skipped tag */
status = readRawObjectData( stream, oid + 1, &length,
MAX_OID_SIZE - 1 );
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
return( addAttributeField( attributeListPtrPtr, fieldID, subFieldID,
oid, length + 1, flags, errorLocus,
errorType ) );
}
/* If it's a special-case field, read it */
if( attributeInfoPtr->fieldType == FIELDTYPE_DN )
{
void *dnPtr = NULL;
/* Read the DN */
status = readDN( stream, &dnPtr );
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
/* Some buggy certs can include zero-length DNs, which we skip */
if( dnPtr == NULL )
return( CRYPT_OK );
/* We're being asked to instantiate the field containing the DN,
create the attribute field and fill in the DN value */
status = addAttributeField( attributeListPtrPtr, fieldID, subFieldID,
dnPtr, CRYPT_UNUSED, flags, errorLocus,
errorType );
if( cryptStatusError( status ) )
deleteDN( &dnPtr );
return( status );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* When we're processing SETs/SEQUENCEs (generically referred to as a SET
OF), we need to maintain a stack of state information in case we
encounter a nested SET OF. The following code implements the state
stack */
#define SETOF_STATE_STACKSIZE 16
typedef struct {
const ATTRIBUTE_INFO *infoStart; /* Start of SET OF attribute info */
int endPos, endEOC; /* End position of SET OF and optional EOC */
CRYPT_ATTRIBUTE_TYPE subtypeParent; /* Parent type if this is subtyped */
int inheritedFlags; /* Flags inherited from parent if subtyped */
BOOLEAN restartPoint; /* Info is a SET OF (rather than SET) */
BOOLEAN subTyped; /* SET ends on a subtyped value */
} SETOF_STATE_INFO;
static SETOF_STATE_INFO *stackSetofState( SETOF_STATE_INFO *setofStack,
int *stackPos )
{
const int newPos = *stackPos + 1;
/* Increment the stack pointer and make sure we don't overflow */
if( newPos >= SETOF_STATE_STACKSIZE )
{
assert( NOTREACHED );
return( &setofStack[ 0 ] );
}
*stackPos = newPos;
/* Initialise the new entry */
memset( &setofStack[ newPos ], 0, sizeof( SETOF_STATE_INFO ) );
return( &setofStack[ newPos ] );
}
static SETOF_STATE_INFO *unstackSetofState( SETOF_STATE_INFO *setofStack,
int *stackPos )
{
const int newPos = *stackPos - 1;
if( newPos < 0 )
{
assert( NOTREACHED );
return( &setofStack[ 0 ] );
}
*stackPos = newPos;
return( &setofStack[ newPos ] );
}
/* Read an attribute */
static int readAttribute( STREAM *stream, ATTRIBUTE_LIST **attributeListPtrPtr,
const ATTRIBUTE_INFO *attributeInfoPtr, const int attributeLength,
const BOOLEAN criticalFlag, CRYPT_ATTRIBUTE_TYPE *errorLocus,
CRYPT_ERRTYPE_TYPE *errorType )
{
SETOF_STATE_INFO setofStack[ SETOF_STATE_STACKSIZE ];
SETOF_STATE_INFO *setofInfoPtr;
const int endPos = stell( stream ) + attributeLength;
BOOLEAN attributeContinues = TRUE;
int flags = criticalFlag ? ATTR_FLAG_CRITICAL : ATTR_FLAG_NONE;
int setofStackPos = 0, status = CRYPT_OK;
assert( isWritePtr( attributeListPtrPtr, ATTRIBUTE_LIST * ) );
assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );
assert( criticalFlag == TRUE || criticalFlag == FALSE );
assert( attributeLength >= 0 );
/* Clear the top of the SET OF state stack. This entry is always all-
zero to represent an empty stack */
memset( &setofStack[ 0 ], 0, sizeof( SETOF_STATE_INFO ) );
setofInfoPtr = &setofStack[ 0 ];
/* Process each field in the attribute. This is a simple FSM driven by
the encoding table and the data we encounter. The various states and
associated actions are indicated by the comment tags */
do
{
BOOLEAN isTagged;
int tag;
/* Inside a SET/SET OF/SEQUENCE/SEQUENCE OF: Check for the end of the
item/collection of items. This must be the first action taken
since reaching the end of a SET/SEQUENCE pre-empts all other
parsing actions */
if( setofInfoPtr->endPos > 0 )
{
const ATTRIBUTE_INFO *oldAttributeInfoPtr = attributeInfoPtr;
/* If we've reached the end of the collection of items, exit */
while( setofStackPos > 0 && \
stell( stream ) >= setofInfoPtr->endPos )
{
#if 0 /* 22/11/03 Removed since these Verisign certs have now expired */
/* If the extension drops into BER, make sure that the EOC
is present */
if( setofInfoPtr->endEOC > 0 && checkEOC( stream ) != TRUE )
return( CRYPT_ERROR_BADDATA );
#endif /* 0 */
/* Pop one level of parse state. If it's a restart point
(SET OF/SEQUENCE OF), restart from here */
if( !setofInfoPtr->restartPoint || \
stell( stream ) >= setofInfoPtr->endPos )
/* It's a straight SET/SEQUENCE, find what follows it */
attributeInfoPtr = findItemEnd( setofInfoPtr->infoStart, 0 );
else
/* It's a SET OF/SEQUENCE OF and there are more entries
present, restart from the start of the SET OF */
attributeInfoPtr = setofInfoPtr->infoStart;
setofInfoPtr = unstackSetofState( setofStack,
&setofStackPos );
assert( setofInfoPtr->endPos > 0 && \
setofInfoPtr->endPos < 65536L );
}
if( attributeInfoPtr != oldAttributeInfoPtr )
goto continueDecoding;
/* If we're looking for a new item, find the table entry that it
corresponds to. This takes a pointer to the start of a set of
SEQUENCE { type, value } entries and returns a pointer to the
appropriate value entry.
The test for the start of a new item is a bit complex since we
could be at the end of the previous item (i.e. on the next item
flagged as an identifier) or at the end of the attribute (i.e.
on the start of the next attribute) */
if( !( attributeInfoPtr[ -1 ].flags & FL_MORE ) || \
attributeInfoPtr->flags & FL_IDENTIFIER )
{
const CRYPT_ATTRIBUTE_TYPE oldFieldID = \
attributeInfoPtr->fieldID;
/* 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( fieldErrorReturn( errorLocus, errorType,
CRYPT_ERROR_BADDATA,
oldFieldID ) );
/* If it's a subtyped field, continue from a new encoding
table */
if( attributeInfoPtr->fieldType == FIELDTYPE_SUBTYPED )
continue;
/* 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 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( attributeInfoPtr->flags & FL_NONENCODING )
{
const int dummy = CRYPT_UNUSED;
/* If it's 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 )
{
/* Add the field type, discarding warnings about dups */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -