📄 dumpasn1.c
字号:
/* 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 T61STRING:
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;
default:
fputc( '\n', output );
if( !doPure )
fprintf( output, " : " );
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 */
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 which
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( !doPure )
if( item.indefinite )
fprintf( output, ( doHexValues ) ? "%04lX %02X NDEF: " :
"%4ld %02X NDEF: ", lastPos, item.id | item.tag );
else
if( ( item.id | item.tag ) == EOC )
seenEOC = TRUE;
else
fprintf( output, ( doHexValues ) ? "%04lX %02X %4lX: " :
"%4ld %02X %4ld: ", lastPos, item.id | item.tag,
item.length );
/* 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 )
{
fprintf( stderr, "\nError: Invalid data encountered at position "
"%d.\n", fPos );
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 */
void usageExit( void )
{
puts( "DumpASN1 - ASN.1 object dump/syntax check program." );
puts( "Copyright Peter Gutmann 1997 - 2001. Last updated " UPDATE_STRING "." );
puts( "" );
puts( "Usage: dumpasn1 [-acdefhlprstxz] <file>" );
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( " -a = Print all data in long data blocks, not just the first 128 bytes" );
puts( " -c<file> = Read Object Identifier info from alternate config file" );
puts( " (values will override equivalents in global config file)" );
puts( " -d = Print dots to show column alignment" );
puts( " -e = Don't print encapsulated data inside OCTET/BIT STRINGs" );
puts( " -f<file> = Dump object at offset -<number> to file (allows data to be" );
puts( " extracted from encapsulating objects)" );
puts( " -h = Hex dump object header (tag+length) before the decoded output" );
puts( " -hh = Same as -h but display more of the object as hex data" );
puts( " -l = Long format, display extra info about Object Identifiers" );
puts( " -p = Pure ASN.1 output without encoding information" );
puts( " -r = Print bits in BIT STRING as encoded in reverse order" );
puts( " -s = Syntax check only, don't dump ASN.1 structures" );
puts( " -t = Display text values next to hex dump of data" );
puts( " -x = Display size and offset in hex not decimal" );
puts( " -z = Allow zero-length items" );
puts( "" );
puts( "Warnings generated by deprecated OIDs require the use of '-l' to be displayed." );
puts( "Program return code is the number of errors found or EXIT_SUCCESS." );
exit( EXIT_FAILURE );
}
int main( int argc, char *argv[] )
{
FILE *inFile, *outFile = NULL;
char *pathPtr = argv[ 0 ];
long offset = 0;
int moreArgs = TRUE, doCheckOnly = FALSE;
/* Skip the program name */
argv++; argc--;
/* Display usage if no args given */
if( argc < 1 )
usageExit();
output = stdout; /* Needs to be assigned at runtime */
/* Check for arguments */
while( argc && *argv[ 0 ] == '-' && moreArgs )
{
char *argPtr = argv[ 0 ] + 1;
if( !*argPtr )
useStdin = TRUE;
while( *argPtr )
{
if( isdigit( *argPtr ) )
{
offset = atol( argPtr );
break;
}
switch( toupper( *argPtr ) )
{
case '-':
moreArgs = FALSE; /* GNU-style end-of-args flag */
break;
case 'A':
printAllData = TRUE;
break;
case 'C':
if( !readConfig( argPtr + 1, FALSE ) )
exit( EXIT_FAILURE );
while( argPtr[ 1 ] )
argPtr++; /* Skip rest of arg */
break;
case 'D':
printDots = TRUE;
break;
case 'E':
checkEncaps = FALSE;
break;
case 'F':
if( ( outFile = fopen( argPtr + 1, "wb" ) ) == NULL )
{
perror( argPtr + 1 );
exit( EXIT_FAILURE );
}
while( argPtr[ 1 ] )
argPtr++; /* Skip rest of arg */
break;
case 'L':
extraOIDinfo = TRUE;
break;
case 'H':
doDumpHeader++;
break;
case 'P':
doPure = TRUE;
break;
case 'R':
reverseBitString = FALSE;
break;
case 'S':
doCheckOnly = TRUE;
#if defined( __WIN32__ )
/* Under Windows we can't fclose( stdout ) because the
VC++ runtime reassigns the stdout handle to the next
open file (which is valid) but then scribbles stdout
garbage all over it for files larger than about 16K
(which isn't), so we have to make sure that the
stdout handle is pointed to something somewhere */
freopen( "nul", "w", stdout );
#elif defined( __UNIX__ )
/* Safety feature in case any Unix libc is as broken
as the Win32 version */
freopen( "/dev/null", "w", stdout );
#else
fclose( stdout );
#endif /* OS-specific bypassing of stdout */
break;
case 'T':
dumpText = TRUE;
break;
case 'X':
doHexValues = TRUE;
break;
case 'Z':
zeroLengthAllowed = TRUE;
break;
default:
printf( "Unknown argument '%c'.\n", *argPtr );
return( EXIT_SUCCESS );
}
argPtr++;
}
argv++;
argc--;
}
/* We can't use options which perform an fseek() if reading from stdin */
if( useStdin && ( doDumpHeader || outFile != NULL ) )
{
puts( "Can't use -f or -h when taking input from stdin" );
exit( EXIT_FAILURE );
}
/* Check args and read the config file. We don't bother weeding out
dups during the read because (a) the linear search would make the
process n^2, (b) during the dump process the search will terminate on
the first match so dups aren't that serious, and (c) there should be
very few dups present */
if( argc != 1 && !useStdin )
usageExit();
if( !readGlobalConfig( pathPtr ) )
exit( EXIT_FAILURE );
/* Dump the given file */
if( useStdin )
inFile = stdin;
else
if( ( inFile = fopen( argv[ 0 ], "rb" ) ) == NULL )
{
perror( argv[ 0 ] );
exit( EXIT_FAILURE );
}
if( useStdin )
{
while( offset-- )
getc( inFile );
}
else
fseek( inFile, offset, SEEK_SET );
if( outFile != NULL )
{
ASN1_ITEM item;
long length;
int i, status;
/* Make sure there's something there, and that it has a definite
length */
status = getItem( inFile, &item );
if( status == -1 )
{
puts( "Non-ASN.1 data encountered." );
exit( EXIT_FAILURE );
}
if( status == 0 )
{
puts( "Nothing to read." );
exit( EXIT_FAILURE );
}
if( item.indefinite )
{
puts( "Cannot process indefinite-length item." );
exit( EXIT_FAILURE );
}
/* Copy the item across, first the header and then the data */
for( i = 0; i < item.headerSize; i++ )
putc( item.header[ i ], outFile );
for( length = 0; length < item.length && !feof( inFile ); length++ )
putc( getc( inFile ), outFile );
fclose( outFile );
fseek( inFile, offset, SEEK_SET );
}
printAsn1( inFile, 0, LENGTH_MAGIC, 0 );
fclose( inFile );
/* Print a summary of warnings/errors if it's required or appropriate */
if( !doPure )
{
if( !doCheckOnly )
fputc( '\n', stderr );
fprintf( stderr, "%d warning%s, %d error%s.\n", noWarnings,
( noWarnings != 1 ) ? "s" : "", noErrors,
( noErrors != 1 ) ? "s" : "" );
}
return( ( noErrors ) ? noErrors : EXIT_SUCCESS );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -