📄 certexrw.c
字号:
/* 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_IA5 || \
attributeInfoPtr->fieldType == BER_STRING_ISO646 || \
attributeInfoPtr->fieldType == BER_STRING_NUMERIC || \
attributeInfoPtr->fieldType == BER_STRING_PRINTABLE || \
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 */
return( addAttributeField( attributeListPtrPtr, fieldID, subFieldID,
buffer, length, flags, 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 ];
status = readRawObjectData( stream, oid + 1, &length,
MAX_OID_SIZE - 1 );
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
oid[ 0 ] = BER_OBJECT_IDENTIFIER; /* Add skipped tag */
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 = readDNTag( stream, &dnPtr,
( attributeInfoPtr->fieldEncodedType ) ? \
NO_TAG : DEFAULT_TAG );
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 );
}
return( CRYPT_OK );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* 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 )
{
const ATTRIBUTE_INFO *savedAttributeInfoPtr = NULL;
const ATTRIBUTE_INFO *setofItemStartPtr = NULL;
const int endPos = ( int ) stell( stream ) + attributeLength;
CRYPT_ATTRIBUTE_TYPE subtypeParent = CRYPT_ATTRIBUTE_NONE;
BOOLEAN attributeContinues = TRUE, isVariableSet;
int flags = criticalFlag ? ATTR_FLAG_CRITICAL : ATTR_FLAG_NONE;
int inheritedFlags = ATTR_FLAG_NONE;
int setEndPos = 0, setEndEOC = 0, savedSetEndPos = 0;
assert( isWritePtr( attributeListPtrPtr, ATTRIBUTE_LIST * ) );
assert( isReadPtr( attributeInfoPtr, ATTRIBUTE_INFO ) );
assert( criticalFlag == TRUE || criticalFlag == FALSE );
assert( attributeLength >= 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, status;
/* Subtyped field: Switch to the new encoding table */
if( attributeInfoPtr->fieldType == FIELDTYPE_SUBTYPED )
{
subtypeParent = attributeInfoPtr->fieldID;
inheritedFlags = ( attributeInfoPtr->flags & FL_MULTIVALUED ) ? \
ATTR_FLAG_MULTIVALUED : ATTR_FLAG_NONE;
/* Push the current parse state and switch to the new state */
savedAttributeInfoPtr = attributeInfoPtr;
attributeInfoPtr = ( ATTRIBUTE_INFO * ) attributeInfoPtr->extraData;
savedSetEndPos = setEndPos;
setEndPos = 0;
}
/* CHOICE (of object identifiers): Read a single OID */
if( attributeInfoPtr->fieldType == FIELDTYPE_CHOICE )
{
const ATTRIBUTE_INFO *extraDataPtr = attributeInfoPtr->extraData;
/* Needed because ->extraData is read-only */
status = readIdentifierFields( stream, attributeListPtrPtr,
&extraDataPtr, flags, attributeInfoPtr->fieldID,
errorLocus, errorType );
if( cryptStatusError( status ) )
return( status );
goto continueDecoding;
}
/* SET OF/SEQUENCE OF: Record its length and end position and
continue. If we're processing a SET OF/SEQUENCE OF, check for the
end of an item or the end of the collection of items */
if( attributeInfoPtr->flags & ( FL_SETOF_FIXED | FL_SETOF_VARIABLE ) )
{
void *objectPtr = sMemBufPtr( stream );
int setofLength;
assert( !attributeInfoPtr->fieldEncodedType && \
!( attributeInfoPtr->flags & FL_EXPLICIT ) );
/* Determine the length and start position of the set of items.
Some broken Verisign certs suddenly break into BER inside the
cert policy extension so if the length evaluates to zero we
have to determine it by burrowing into the ASN.1 */
if( attributeInfoPtr->fieldType == BER_SET )
status = readSet( stream, &setofLength );
else
status = readSequence( stream, &setofLength );
if( cryptStatusOK( status ) && !setofLength )
{
/* Get the overall length without the tag + indef.length */
status = setofLength = \
getObjectLength( objectPtr, sMemDataLeft( stream ) ) - 2;
setEndEOC = 2; /* Two bytes of EOC at end of object */
}
setEndPos = ( int ) stell( stream ) + setofLength;
if( cryptStatusError( status ) )
return( fieldErrorReturn( errorLocus, errorType, status,
attributeInfoPtr->fieldID ) );
/* Remember where the first item in the SET/SEQUENCE starts. We
use this as a restart point when we're parsing the next item
in the SET/SEQUENCE OF items using findIdentifiedItem() for a
choice of fixed items) or a general read (for a collection of
variable items) */
isVariableSet = ( attributeInfoPtr->flags & FL_SETOF_VARIABLE ) ? \
TRUE : FALSE;
setofItemStartPtr = ++attributeInfoPtr;
continue;
}
if( setEndPos )
{
/* If we've reached the end of the collection of items, exit (at
the moment these items always occur at the end of an attribute,
this may need to be changed later) */
if( stell( stream ) >= setEndPos - setEndEOC )
{
/* If the extension drops into BER, make sure the EOC is
present */
if( setEndEOC && !checkEOC( stream ) )
return( CRYPT_ERROR_BADDATA );
break;
}
/* If we're looking for a new item, find the table entry which 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 (ie on the next item
flagged as an identifier) or at the end of the attribute (ie on
the start of the next attribute) */
if( setEndPos && ( !( attributeInfoPtr[ -1 ].flags & FL_MORE ) ||
attributeInfoPtr->flags & FL_IDENTIFIER ) )
{
attributeInfoPtr = findIdentifiedItem( stream, setofItemStartPtr );
if( attributeInfoPtr == NULL )
return( fieldErrorReturn( errorLocus, errorType,
CRYPT_ERROR_BADDATA,
attributeInfoPtr->fieldID ) );
/* 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. 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 */
status = addAttributeField( attributeListPtrPtr,
attributeInfoPtr->fieldID, CRYPT_ATTRIBUTE_NONE,
&dummy, CRYPT_UNUSED, flags, errorLocus,
errorType );
if( status == CRYPT_ERROR_INITED )
status = CRYPT_OK;
if( cryptStatusError( status ) )
return( status );
}
/* Reset the attribute info position in preparation for
the next value and continue */
attributeInfoPtr = setofItemStartPtr;
continue;
}
}
}
/* Identifier field: We've reached the first of a sequence of
possible alternatives, read the sequence of one or more fields and
continue */
if( attributeInfoPtr->fieldType == FIELDTYPE_IDENTIFIER )
{
status = readIdentifierFields( stream, attributeListPtrPtr,
&attributeInfoPtr, flags,
CRYPT_ATTRIBUTE_NONE, errorLocus, errorType );
if( cryptStatusError( status ) )
return( status );
goto continueDecoding;
}
/* Non-encoding field: Check that it matches the required value and
continue */
if( attributeInfoPtr->flags & FL_NONENCODING )
{
BYTE data[ 64 ];
int dataLength;
/* Read the data and continue. We don't check its value or set
specific error information for reasons given under the SET-OF
handling code above (value check) and optional field code below
(error locus set) */
status = readRawObject( stream, data, &dataLength, 64, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
goto continueDecoding;
}
/* Extract various pieces of information from the attribute field
definition */
isTagged = ( attributeInfoPtr->fieldEncodedType ) ? TRUE : FALSE;
tag = ( isTagged ) ? attributeInfoPtr->fieldEncodedType : \
attributeInfoPtr->fieldType;
if( isTagged && ( attributeInfoPtr->fieldType == BER_SEQUENCE ||
attributeInfoPtr->fieldType == BER_SET ||
attributeInfoPtr->fieldType == FIELDTYPE_DN ||
( attributeInfoPtr->flags & FL_EXPLICIT ) ) )
/* If it's an implictly tagged sequence/set then it's constructed */
tag |= BER_CONSTRUCTED;
/* Optional field: Check whether it's present and if it isn't, move
on to the next field */
if( ( attributeInfoPtr->flags & FL_OPTIONAL ) && \
peekTag( stream ) != tag )
{
/* If it's a field with a default value, add that value. This
isn't needed for cryptlib's own use since it knows the default
values for fields, but can cause confusion for the caller if
all fields in an attribute have default values because the
attribute will appear to disappear when it's read in as no
fields are ever added. Since this is a field contributed from
internal data, we don't try and get an error locus or value
for it since this would only confuse the caller */
if( attributeInfoPtr->flags & FL_DEFAULT )
{
const int value = ( int ) attributeInfoPtr->defaultValue;
status = addAttributeField( attributeListPtrPtr,
attributeInfoPtr->fieldID, CRYPT_ATTRIBUTE_NONE,
&value, CRYPT_UNUSED, flags, NULL, NULL );
if( cryptStatusError( status ) )
return( status );
}
/* Skip to the end of the item and continue */
attributeInfoPtr = findItemEnd( attributeInfoPtr, 0 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -