📄 ext_rd.c
字号:
/****************************************************************************
* *
* Certificate Attribute Read Routines *
* Copyright Peter Gutmann 1996-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "cert.h"
#include "certattr.h"
#include "asn1.h"
#include "asn1_ext.h"
#else
#include "cert/cert.h"
#include "cert/certattr.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
/* Define the following to print a trace of the certificate fields being
parsed, useful for debugging broken certificates */
#if !defined( NDEBUG ) && 0
#define TRACE_FIELDTYPE( attributeInfoPtr, stackPos ) \
{ \
int i; \
\
for( i = 0; i < stackPos; i++ ) \
printf( " " ); \
if( ( attributeInfoPtr ) != NULL && \
( attributeInfoPtr )->description != NULL ) \
puts( ( attributeInfoPtr )->description ); \
}
#define TRACE_DEBUG( message, status ) \
printf( message, status );
#else
#define TRACE_FIELDTYPE( attributeInfoPtr, stackPos )
#define TRACE_DEBUG( message, status )
#endif /* NDEBUG */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Get the tag for a field from the attribute field definition */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int getFieldTag( INOUT STREAM *stream,
const ATTRIBUTE_INFO *attributeInfoPtr,
int *tag )
{
int status, value;
assert( isReadPtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
assert( isWritePtr( tag, sizeof( int ) ) );
/* Clear return value. This is actually a bit difficult to do because
the output can have both positive values (tags) and negative values
(field codes), setting the output to -1000 is invalid for both
types */
*tag = -1000;
/* Check whether the field is tagged */
status = value = getFieldEncodedTag( attributeInfoPtr );
if( cryptStatusError( status ) )
{
/* If there's no tagging (i.e. the tag is the same as the field
type) we'll get an OK_SPECIAL return value, this isn't an
error */
if( status != OK_SPECIAL )
return( status );
}
else
{
/* It's a tagged field, return the encoded form */
*tag = value;
return( CRYPT_OK );
}
ENSURES( status == OK_SPECIAL );
/* It's a non-tagged field, the tag is the same as the field type */
value = attributeInfoPtr->fieldType;
if( value == FIELDTYPE_DISPLAYSTRING )
{
/* This is a variable-tag field that can have one of a number of
tags. To handle this we peek ahead into the stream to see if an
acceptable tag is present and if not set the value to a non-
matching tag value */
status = value = peekTag( stream );
if( cryptStatusError( status ) )
return( status );
if( ( value != BER_STRING_IA5 ) && \
( value != BER_STRING_ISO646 ) && \
( value != BER_STRING_BMP ) && ( value != BER_STRING_UTF8 ) )
value++; /* Make sure that it doesn't match */
}
ENSURES( ( ( value == FIELDTYPE_BLOB || value == FIELDTYPE_DN ) && \
!( attributeInfoPtr->flags & FL_OPTIONAL ) ) || \
( value > 0 && value < 0xF0 ) );
*tag = value;
return( CRYPT_OK );
}
/* Find the end of an item (either primitive or constructed) in the attribute
table. Sometimes we may have already entered a constructed object (for
example when an attribute has a version number so we don't know until we've
started processing it that we can't do anything with it), if this is the
case then the depth parameter indicates how many nesting levels we have to
undo */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int findItemEnd( const ATTRIBUTE_INFO **attributeInfoPtrPtr,
IN_RANGE( 0, 3 ) const int depth )
{
const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
BOOLEAN attributeContinues;
int currentDepth = depth, iterationCount = 0;
assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
REQUIRES( depth >= 0 && depth < 3 );
/* Skip to the end of the (potentially) constructed item by recording the
nesting level and continuing until either it reaches zero or we reach
the end of the item */
do
{
/* If it's a sequence/set, increment the depth; if it's an end-of-
constructed-item marker, decrement it by the appropriate amount */
if( attributeInfoPtr->fieldType == BER_SEQUENCE || \
attributeInfoPtr->fieldType == BER_SET )
currentDepth++;
currentDepth -= decodeNestingLevel( attributeInfoPtr->flags );
/* Move to the next entry */
attributeContinues = ( attributeInfoPtr->flags & FL_MORE ) ? TRUE : FALSE;
attributeInfoPtr++;
}
while( currentDepth > 0 && attributeContinues && \
iterationCount++ < FAILSAFE_ITERATIONS_MED );
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
/* We return the previous entry, since we're going to move on to the
next entry once we return */
*attributeInfoPtrPtr = attributeInfoPtr - 1;
return( CRYPT_OK );
}
/****************************************************************************
* *
* SET/SEQUENCE Management Routines *
* *
****************************************************************************/
/* When we're processing SETs/SEQUENCEs (generically referred to as a SET
OF) we need to maintain a stack of state information to handle a nested
SET OF. The following code implements the state stack */
#define SETOF_STATE_STACKSIZE 16
#define SETOF_FLAG_NONE 0x00 /* No flag value */
#define SETOF_FLAG_SUBTYPED 0x01 /* SET ends on a subtyped value */
#define SETOF_FLAG_RESTARTPOINT 0x02 /* SET OF rather than SET */
#define SETOF_FLAG_ISEMPTY 0x04 /* Cleared if SET OF contains at least one entry */
typedef struct {
/* SET OF state information */
const ATTRIBUTE_INFO *infoStart; /* Start of SET OF attribute info */
int startPos, endPos; /* Start and end position of SET OF */
int flags; /* SET OF flags */
/* Subtype information */
CRYPT_ATTRIBUTE_TYPE subtypeParent; /* Parent type if this is subtyped */
int inheritedFlags; /* Flags inherited from parent if subtyped */
} SETOF_STATE_INFO;
typedef struct {
ARRAY( SETOF_STATE_STACKSIZE, stackPos ) \
SETOF_STATE_INFO stateInfo[ SETOF_STATE_STACKSIZE + 8 ];
int stackPos; /* Current position in stack */
} SETOF_STACK;
STDC_NONNULL_ARG( ( 1 ) ) \
static void setofStackInit( OUT SETOF_STACK *setofStack )
{
assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );
memset( setofStack, 0, sizeof( SETOF_STACK ) );
}
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN setofStackPush( INOUT SETOF_STACK *setofStack )
{
const int newPos = setofStack->stackPos + 1;
assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );
/* Increment the stack pointer and make sure that we don't overflow */
ENSURES_B( newPos >= 1 && newPos < SETOF_STATE_STACKSIZE );
setofStack->stackPos = newPos;
/* Initialise the new entry */
memset( &setofStack->stateInfo[ newPos ], 0, \
sizeof( SETOF_STATE_INFO ) );
return( TRUE );
}
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN setofStackPop( INOUT SETOF_STACK *setofStack )
{
const int newPos = setofStack->stackPos - 1;
assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );
/* Decrement the stack pointer and make sure that we don't underflow */
ENSURES_B( newPos >= 0 && newPos < SETOF_STATE_STACKSIZE - 1 );
setofStack->stackPos = newPos;
return( TRUE );
}
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
static SETOF_STATE_INFO *setofTOS( const SETOF_STACK *setofStack )
{
assert( isReadPtr( setofStack, sizeof( SETOF_STACK ) ) );
return( ( SETOF_STATE_INFO * ) \
&setofStack->stateInfo[ setofStack->stackPos ] );
}
/* Process the start of a SET/SET OF/SEQUENCE/SEQUENCE OF */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int beginSetof( INOUT STREAM *stream,
INOUT SETOF_STACK *setofStack,
const ATTRIBUTE_INFO *attributeInfoPtr )
{
SETOF_STATE_INFO *setofInfoPtr = setofTOS( setofStack );
CRYPT_ATTRIBUTE_TYPE oldSubtypeParent;
int oldInheritedFlags, setofLength, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );
assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
REQUIRES( !( attributeInfoPtr->flags & FL_EXPLICIT ) );
/* Determine the length and start position of the SET OF items */
if( attributeInfoPtr->fieldEncodedType >= 0 )
{
status = readConstructed( stream, &setofLength,
attributeInfoPtr->fieldEncodedType );
}
else
{
if( attributeInfoPtr->fieldType == BER_SET )
status = readSet( stream, &setofLength );
else
status = readSequence( stream, &setofLength );
}
if( cryptStatusError( status ) )
return( status );
/* When processing a SET/SEQUENCE with default values for the elements
the result may be a zero-length object, in which case we don't take
any action */
if( setofLength <= 0 )
return( CRYPT_OK );
/* Remember assorted info such as where the SET/SEQUENCE ends. In
addition if this is a SET OF/SEQUENCE OF, remember this as a restart
point for when we're parsing the next item in the SET/SEQUENCE OF */
oldSubtypeParent = setofInfoPtr->subtypeParent;
oldInheritedFlags = setofInfoPtr->inheritedFlags;
if( !setofStackPush( setofStack ) )
{
/* Stack overflow, there's a problem with the certificate */
return( CRYPT_ERROR_OVERFLOW );
}
setofInfoPtr = setofTOS( setofStack );
setofInfoPtr->infoStart = attributeInfoPtr;
if( attributeInfoPtr->flags & FL_SETOF )
setofInfoPtr->flags |= SETOF_FLAG_RESTARTPOINT;
if( attributeInfoPtr->flags & FL_NONEMPTY )
setofInfoPtr->flags |= SETOF_FLAG_ISEMPTY;
setofInfoPtr->subtypeParent = oldSubtypeParent;
setofInfoPtr->inheritedFlags = oldInheritedFlags;
setofInfoPtr->startPos = stell( stream );
setofInfoPtr->endPos = setofInfoPtr->startPos + setofLength;
return( CRYPT_OK );
}
/* Check whether we've reached the end of a SET/SEQUENCE. Returns OK_SPECIAL
if the end has been reached */
CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int checkSetofEnd( const STREAM *stream,
INOUT SETOF_STACK *setofStack,
const ATTRIBUTE_INFO **attributeInfoPtrPtr )
{
const SETOF_STATE_INFO *setofInfoPtr = setofTOS( setofStack );
const ATTRIBUTE_INFO *oldAttributeInfoPtr = *attributeInfoPtrPtr;
const ATTRIBUTE_INFO *attributeInfoPtr = *attributeInfoPtrPtr;
const int currentPos = stell( stream );
int iterationCount;
assert( isReadPtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( setofStack, sizeof( SETOF_STACK ) ) );
assert( isReadPtr( attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO * ) ) );
assert( isReadPtr( *attributeInfoPtrPtr, sizeof( ATTRIBUTE_INFO ) ) );
/* If we're still within the SET/SEQUENCE, we're done */
if( setofStack->stackPos <= 0 || currentPos < setofInfoPtr->endPos )
return( CRYPT_OK );
/* We've reached the end of or or more layers of SET/SEQUENCE, keep
popping SET/SEQUENCE state info until we can continue */
for( iterationCount = 0;
setofStack->stackPos > 0 && \
currentPos >= setofInfoPtr->endPos && \
iterationCount < SETOF_STATE_STACKSIZE;
iterationCount++ )
{
const int flags = setofInfoPtr->flags;
/* Pop one level of parse state */
if( !setofStackPop( setofStack ) )
{
/* Stack underflow, there's a problem with the certificate */
return( CRYPT_ERROR_UNDERFLOW );
}
setofInfoPtr = setofTOS( setofStack );
attributeInfoPtr = setofInfoPtr->infoStart;
ENSURES( setofInfoPtr->endPos > 0 && \
setofInfoPtr->endPos < MAX_INTLENGTH_SHORT );
/* If it's a pure SET/SEQUENCE (not a SET OF/SEQUENCE OF) and there
are no more elements present, go to the end of the SET/SEQUENCE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -