📄 ext_rd.c
字号:
{
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
REQUIRES( cryptStatusError( status ) );
REQUIRES( fieldID > CRYPT_ATTRIBUTE_NONE && \
fieldID < CRYPT_IATTRIBUTE_LAST );
/* 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 */
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 2 ) ) \
static ATTRIBUTE_INFO *switchToSubtype( const ATTRIBUTE_INFO *attributeInfoPtr,
INOUT SETOF_STATE_INFO *setofInfoPtr )
{
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( isReadPtr( attributeInfoPtr->extraData,
sizeof( ATTRIBUTE_INFO ) ) );
assert( isWritePtr( setofInfoPtr, sizeof( SETOF_STATE_INFO ) ) );
REQUIRES_N( attributeInfoPtr->extraData != NULL );
/* Record the subtype parent information */
setofInfoPtr->subtypeParent = attributeInfoPtr->fieldID;
setofInfoPtr->inheritedFlags = \
( attributeInfoPtr->flags & FL_MULTIVALUED ) ? \
ATTR_FLAG_MULTIVALUED : ATTR_FLAG_NONE;
/* If the subtype is being used to process a list of { ... OPTIONAL,
... OPTIONAL } and at least one entry must be present, remember
that we haven't seen any entries yet */
if( attributeInfoPtr->flags & FL_NONEMPTY )
setofInfoPtr->flags |= SETOF_FLAG_ISEMPTY;
/* 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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 6, 7 ) ) \
static int readAttributeField( INOUT STREAM *stream,
/*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
const ATTRIBUTE_INFO *attributeInfoPtr,
IN_ATTRIBUTE_OPT \
const CRYPT_ATTRIBUTE_TYPE subtypeParent,
IN_FLAGS( ATTR ) const int flags,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
CRYPT_ATTRIBUTE_TYPE fieldID, subFieldID;
const int fieldType = attributeInfoPtr->fieldType;
int length, status = CRYPT_OK;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
REQUIRES( subtypeParent >= CRYPT_ATTRIBUTE_NONE && \
subtypeParent < CRYPT_ATTRIBUTE_LAST );
assert( ( flags & ~( ATTR_FLAG_NONE | ATTR_FLAG_CRITICAL | ATTR_FLAG_MULTIVALUED ) ) == 0 );
REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
REQUIRES( !( flags & ATTR_FLAG_INVALID ) );
/* 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:
retIntError();
}
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 );
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 ) );
}
case BER_STRING_BMP:
case BER_STRING_IA5:
case BER_STRING_ISO646:
case BER_STRING_NUMERIC:
case BER_STRING_PRINTABLE:
case BER_STRING_T61:
case BER_STRING_UTF8:
case BER_OCTETSTRING:
case FIELDTYPE_BLOB:
case FIELDTYPE_DISPLAYSTRING:
{
/* 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) */
BYTE buffer[ 256 + 8 ];
/* Read in the string to a maximum length of 256 bytes */
if( fieldType == FIELDTYPE_BLOB )
{
const int tag = peekTag( stream );
if( cryptStatusError( tag ) )
{
return( fieldErrorReturn( errorLocus, errorType, tag,
attributeInfoPtr->fieldID ) );
}
/* Reading in blob fields is somewhat difficult since these
are typically used to read SET/SEQUENCE OF kitchensink
values and so won't have a consistent tag that we can pass
to readRawObject(). To get around this we peek ahead into
the stream to get the tag and then pass that down to
readRawObject(). Note that this requires that the blob
have an internal structure (with its own { tag, length }
data) since the caller has already stripped off the tag
and length */
status = readRawObject( stream, buffer, 256, &length, tag );
}
else
{
status = readOctetStringData( stream, buffer, &length, \
1, 256 );
}
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
/* There are enough broken certificates out there with
enormously long disclaimers in the certificate 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 ) );
}
case BER_OBJECT_IDENTIFIER:
{
BYTE oid[ MAX_OID_SIZE + 8 ];
/* If it's an OID, we need to reassemble the entire OID since
this is the form expected by addAttributeField() */
oid[ 0 ] = BER_OBJECT_IDENTIFIER; /* Add skipped tag */
status = readEncodedOID( stream, oid + 1, MAX_OID_SIZE - 1,
&length, NO_TAG );
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
return( addAttributeField( attributeListPtrPtr, fieldID,
subFieldID, oid, length + 1, flags,
errorLocus, errorType ) );
}
case FIELDTYPE_DN:
{
void *dnPtr = NULL;
/* Read the DN */
status = readDN( stream, &dnPtr );
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
/* Some buggy certificates 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 );
}
}
retIntError();
}
/* Read an attribute */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 6, 7 ) ) \
static int readAttribute( INOUT STREAM *stream,
/*?*/ ATTRIBUTE_LIST **attributeListPtrPtr,
const ATTRIBUTE_INFO *attributeInfoPtr,
IN_LENGTH_Z const int attributeLength,
const BOOLEAN criticalFlag,
OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
CRYPT_ATTRIBUTE_TYPE *errorLocus,
OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
CRYPT_ERRTYPE_TYPE *errorType )
{
SETOF_STACK setofStack;
SETOF_STATE_INFO *setofInfoPtr;
const int endPos = stell( stream ) + attributeLength;
BOOLEAN attributeContinues = TRUE;
int flags = criticalFlag ? ATTR_FLAG_CRITICAL : ATTR_FLAG_NONE;
int attributeFieldsProcessed = 0, status = CRYPT_OK;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( attributeListPtrPtr, sizeof( ATTRIBUTE_LIST * ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
REQUIRES( attributeLength >= 0 && attributeLength < MAX_INTLENGTH );
/* Initialise the SET OF state stack */
setofStackInit( &setofStack );
setofInfoPtr = setofTOS( &setofStack );
/* Process each field in the attribute. This is a simple FSM driven by
the encoding table and the data that we encounter. The various
states and associated actions are indicated by the comment tags */
do
{
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 )
{
/* If we've reached the end of the collection of items, exit */
status = checkSetofEnd( stream, &setofStack, &attributeInfoPtr );
if( cryptStatusError( status ) && status != OK_SPECIAL )
return( status );
setofInfoPtr = setofTOS( &setofStack );
if( status == OK_SPECIAL )
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 ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -