📄 dumpasn1.c
字号:
STR_OPTION stringType;
char buffer[ MAX_OID_SIZE ];
long value;
int x, y;
if( ( item->id & CLASS_MASK ) != UNIVERSAL )
{
static const char *const classtext[] =
{ "UNIVERSAL ", "APPLICATION ", "", "PRIVATE " };
/* Print the object type */
fprintf( output, "[%s%d]",
classtext[ ( item->id & CLASS_MASK ) >> 6 ], item->tag );
/* Perform a sanity check */
if( ( item->tag != NULLTAG ) && ( item->length < 0 ) )
{
int i;
fprintf( stderr, "\nError: Object has bad length field, tag = %02X, "
"length = %lX, value =", item->tag, item->length );
fprintf( stderr, "<%02X", *item->header );
for( i = 1; i < item->headerSize; i++ )
fprintf( stderr, " %02X", item->header[ i ] );
fputs( ">.\n", stderr );
exit( EXIT_FAILURE );
}
if( !item->length && !item->indefinite && !zeroLengthOK( item ) )
{
fputc( '\n', output );
complain( "Object has zero length", level );
return;
}
/* If it's constructed, print the various fields in it */
if( ( item->id & FORM_MASK ) == CONSTRUCTED )
{
printConstructed( inFile, level, item );
return;
}
/* It's primitive, if it's a seekable stream try and determine
whether it's text so we can display it as such */
if( !useStdin && \
( stringType = checkForText( inFile, item->length ) ) != STR_NONE )
{
/* It looks like a text string, dump it as text */
displayString( inFile, item->length, level, stringType );
return;
}
/* This could be anything, dump it as hex data */
dumpHex( inFile, item->length, level, FALSE );
return;
}
/* Print the object type */
fprintf( output, "%s", idstr( item->tag ) );
/* Perform a sanity check */
if( ( item->tag != NULLTAG ) && ( item->length < 0 ) )
{
int i;
fprintf( stderr, "\nError: Object has bad length field, tag = %02X, "
"length = %lX, value =", item->tag, item->length );
fprintf( stderr, "<%02X", *item->header );
for( i = 1; i < item->headerSize; i++ )
fprintf( stderr, " %02X", item->header[ i ] );
fputs( ">.\n", stderr );
exit( EXIT_FAILURE );
}
/* If it's constructed, print the various fields in it */
if( ( item->id & FORM_MASK ) == CONSTRUCTED )
{
printConstructed( inFile, level, item );
return;
}
/* It's primitive */
if( !item->length && !zeroLengthOK( item ) )
{
fputc( '\n', output );
complain( "Object has zero length", level );
return;
}
switch( item->tag )
{
case BOOLEAN:
x = getc( inFile );
fprintf( output, " %s\n", x ? "TRUE" : "FALSE" );
if( x != 0 && x != 0xFF )
complain( "BOOLEAN has non-DER encoding", level );
fPos++;
break;
case INTEGER:
case ENUMERATED:
if( item->length > 4 )
dumpHex( inFile, item->length, level, TRUE );
else
{
value = getValue( inFile, item->length );
fprintf( output, " %ld\n", value );
if( value < 0 )
complain( "Integer has a negative value", level );
}
break;
case BITSTRING:
if( ( x = getc( inFile ) ) != 0 )
fprintf( output, " %d unused bit%s",
x, ( x != 1 ) ? "s" : "" );
fPos++;
if( !--item->length && !x )
{
fputc( '\n', output );
complain( "Object has zero length", level );
return;
}
if( item->length <= sizeof( int ) )
{
/* It's short enough to be a bit flag, dump it as a sequence
of bits */
dumpBitString( inFile, ( int ) item->length, x, level );
break;
}
/* Drop through to dump it as an octet string */
case OCTETSTRING:
if( checkEncapsulate( inFile, item->length ) )
{
/* It's something encapsulated inside the string, print it as
a constructed item */
fprintf( output, ", encapsulates" );
printConstructed( inFile, level, item );
break;
}
if( !useStdin && !dumpText && \
( stringType = checkForText( inFile, item->length ) ) != STR_NONE )
{
/* If we'd be doing a straight hex dump and it looks like
encapsulated text, display it as such. If the user has
overridden character set type checking and it's a string
type for which we normally perform type checking, we reset
its type to none */
displayString( inFile, item->length, level, \
( !checkCharset && ( stringType == STR_IA5 || \
stringType == STR_PRINTABLE ) ) ? \
STR_NONE : stringType );
return;
}
dumpHex( inFile, item->length, level, FALSE );
break;
case OID:
/* Hierarchical Object Identifier: The first two levels are
encoded into one byte, since the root level has only 3 nodes
(40*x + y). However if x = joint-iso-itu-t(2) then y may be
> 39, so we have to add special-case handling for this */
if( item->length > MAX_OID_SIZE )
{
fprintf( stderr, "\nError: Object identifier length %ld too "
"large.\n", item->length );
exit( EXIT_FAILURE );
}
fread( buffer, 1, ( size_t ) item->length, inFile );
fPos += item->length;
if( ( oidInfo = getOIDinfo( buffer, ( int ) item->length ) ) != NULL )
{
/* Check if LHS status info + indent + "OID " string + oid
name will wrap */
if( ( ( doPure ) ? 0 : INDENT_SIZE ) + ( level * 2 ) + 18 + \
strlen( oidInfo->description ) >= outputWidth )
{
fputc( '\n', output );
if( !doPure )
fprintf( output, INDENT_STRING );
doIndent( level + 1 );
}
else
fputc( ' ', output );
fprintf( output, "%s\n", oidInfo->description );
/* Display extra comments about the OID if required */
if( extraOIDinfo && oidInfo->comment != NULL )
{
if( !doPure )
fprintf( output, INDENT_STRING );
doIndent( level + 1 );
fprintf( output, "(%s)\n", oidInfo->comment );
}
/* If there's a warning associated with this OID, remember
that there was a problem */
if( oidInfo->warn )
noWarnings++;
break;
}
/* Pick apart the OID */
x = ( unsigned char ) buffer[ 0 ] / 40;
y = ( unsigned char ) buffer[ 0 ] % 40;
if( x > 2 )
{
/* Handle special case for large y if x = 2 */
y += ( x - 2 ) * 40;
x = 2;
}
fprintf( output, " '%d %d", x, y );
value = 0;
for( x = 1; x < item->length; x++ )
{
value = ( value << 7 ) | ( buffer[ x ] & 0x7F );
if( !( buffer[ x ] & 0x80 ) )
{
fprintf( output, " %ld", value );
value = 0;
}
}
fprintf( output, "'\n" );
break;
case EOC:
case NULLTAG:
fputc( '\n', output );
break;
case OBJDESCRIPTOR:
case GRAPHICSTRING:
case VISIBLESTRING:
case GENERALSTRING:
case UNIVERSALSTRING:
case NUMERICSTRING:
case VIDEOTEXSTRING:
case UTF8STRING:
displayString( inFile, item->length, level, STR_NONE );
break;
case PRINTABLESTRING:
displayString( inFile, item->length, level, STR_PRINTABLE );
break;
case BMPSTRING:
displayString( inFile, item->length, level, STR_BMP );
break;
case UTCTIME:
displayString( inFile, item->length, level, STR_UTCTIME );
break;
case GENERALIZEDTIME:
displayString( inFile, item->length, level, STR_GENERALIZED );
break;
case IA5STRING:
displayString( inFile, item->length, level, STR_IA5 );
break;
case T61STRING:
displayString( inFile, item->length, level, STR_LATIN1 );
break;
default:
fputc( '\n', output );
if( !doPure )
fprintf( output, INDENT_STRING );
doIndent( level + 1 );
fprintf( output, "Unrecognised primitive, hex value is:");
dumpHex( inFile, item->length, level, FALSE );
noErrors++; /* Treat it as an error */
}
}
/* Print a complex ASN.1 object */
static int printAsn1( FILE *inFile, const int level, long length,
const int isIndefinite )
{
ASN1_ITEM item;
long lastPos = fPos;
int seenEOC = FALSE, status;
/* Special-case for zero-length objects */
if( !length && !isIndefinite )
return( 0 );
while( ( status = getItem( inFile, &item ) ) > 0 )
{
/* Perform various special checks the first time we're called */
if( length == LENGTH_MAGIC )
{
/* If the length isn't known and the item has a definite length,
set the length to the item's length */
if( !item.indefinite )
length = item.headerSize + item.length;
/* If the input isn't seekable, turn off some options that
require the use of fseek(). This check isn't perfect (some
streams are slightly seekable due to buffering) but it's
better than nothing */
if( fseek( inFile, -item.headerSize, SEEK_CUR ) )
{
useStdin = TRUE;
checkEncaps = FALSE;
puts( "Warning: Input is non-seekable, some functionality "
"has been disabled." );
}
else
fseek( inFile, item.headerSize, SEEK_CUR );
}
/* Dump the header as hex data if requested */
if( doDumpHeader )
dumpHeader( inFile, &item );
/* Print offset into buffer, tag, and length */
if( item.header[ 0 ] == EOC )
{
seenEOC = TRUE;
if( !isIndefinite)
complain( "Spurious EOC in definite-length item", level );
}
if( !doPure )
{
#if 0
/* Don't print hex tags any more to save display space */
if( item.indefinite )
fprintf( output, ( doHexValues ) ? "%04lX %02X NDEF: " :
"%4ld %02X NDEF: ", lastPos, item.id | item.tag );
else
if( !seenEOC )
fprintf( output, ( doHexValues ) ? "%04lX %02X %4lX: " :
"%4ld %02X %4ld: ", lastPos, item.id | item.tag,
item.length );
#else
if( item.indefinite )
fprintf( output, ( doHexValues ) ? "%04lX NDEF: " :
"%4ld NDEF: ", lastPos );
else
if( !seenEOC )
fprintf( output, ( doHexValues ) ? "%04lX %4lX: " :
"%4ld %4ld: ", lastPos, item.length );
#endif
}
/* Print details on the item */
if( !seenEOC )
{
doIndent( level );
printASN1object( inFile, &item, level );
}
/* If it was an indefinite-length object (no length was ever set) and
we've come back to the top level, exit */
if( length == LENGTH_MAGIC )
return( 0 );
length -= fPos - lastPos;
lastPos = fPos;
if( isIndefinite )
{
if( seenEOC )
return( 0 );
}
else
{
if( length <= 0 )
{
if( length < 0 )
return( ( int ) -length );
return( 0 );
}
else
{
if( length == 1 )
{
const int ch = fgetc( inFile );
/* No object can be one byte long, try and recover. This
only works sometimes because it can be caused by
spurious data in an OCTET STRING hole or an incorrect
length encoding. The following workaround tries to
recover from spurious data by skipping the byte if
it's zero or a non-basic-ASN.1 tag, but keeping it if
it could be valid ASN.1 */
if( ch && ch <= 0x31 )
ungetc( ch, inFile );
else
{
fPos++;
return( 1 );
}
}
}
}
}
if( status == -1 )
{
int i;
fprintf( stderr, "\nError: Invalid data encountered at position "
"%d:", fPos );
for( i = 0; i < item.headerSize; i++ )
fprintf( stderr, " %02X", item.header[ i ] );
fprintf( stderr, ".\n" );
exit( EXIT_FAILURE );
}
/* If we see an EOF and there's supposed to be more data present,
complain */
if( length && length != LENGTH_MAGIC )
{
fprintf( output, "Error: Inconsistent object length, %ld byte%s "
"difference.\n", length, ( length > 1 ) ? "s" : "" );
noErrors++;
}
return( 0 );
}
/* Show usage and exit */
static void usageExit( void )
{
puts( "DumpASN1 - ASN.1 object dump/syntax check program." );
puts( "Copyright Peter Gutmann 1997 - 2008. Last updated " UPDATE_STRING "." );
puts( "" );
puts( "Usage: dumpasn1 [-acdefhlprstuxz] <file>" );
puts( " Input options:" );
puts( " - = Take input from stdin (some options may not work properly)" );
puts( " -<number> = Start <number> bytes into the file" );
puts( " -- = End of arg list" );
puts( " -c<file> = Read Object Identifier info from alternate config file" );
puts( " (values will override equivalents in global config file)" );
puts( "" );
puts( " Output options:" );
puts( "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -