📄 dumpasn1.c
字号:
{
const int lineLength = ( dumpText ) ? 8 : 16;
char printable[ 9 ];
long noBytes = length;
int zeroPadded = FALSE, warnPadding = FALSE, warnNegative = isInteger;
int maxLevel = ( doPure ) ? 15 : 8, i;
if( noBytes > 128 && !printAllData )
noBytes = 128; /* Only output a maximum of 128 bytes */
if( level > maxLevel )
level = maxLevel; /* Make sure we don't go off edge of screen */
printable[ 8 ] = printable[ 0 ] = '\0';
for( i = 0; i < noBytes; i++ )
{
int ch;
if( !( i % lineLength ) )
{
if( dumpText )
{
/* If we're dumping text alongside the hex data, print the
accumulated text string */
fputs( " ", output );
fputs( printable, output );
}
fputc( '\n', output );
if( !doPure )
fprintf( output, " : " );
doIndent( level + 1 );
}
ch = getc( inFile );
fprintf( output, "%s%02X", i % lineLength ? " " : "", ch );
printable[ i % 8 ] = ( ch >= ' ' && ch < 127 ) ? ch : '.';
fPos++;
/* If we need to check for negative values and zero padding, check
this now */
if( !i )
{
if( !ch )
zeroPadded = TRUE;
if( !( ch & 0x80 ) )
warnNegative = FALSE;
}
if( i == 1 && zeroPadded && ch < 0x80 )
warnPadding = TRUE;
}
if( dumpText )
{
/* Print any remaining text */
i %= lineLength;
printable[ i ] = '\0';
while( i < lineLength )
{
fprintf( output, " " );
i++;
}
fputs( " ", output );
fputs( printable, output );
}
if( length > 128 && !printAllData )
{
length -= 128;
fputc( '\n', output );
if( !doPure )
fprintf( output, " : " );
doIndent( level + 5 );
fprintf( output, "[ Another %ld bytes skipped ]", length );
fPos += length;
if( useStdin )
{
while( length-- )
getc( inFile );
}
else
fseek( inFile, length, SEEK_CUR );
}
fputs( "\n", output );
if( isInteger )
{
if( warnPadding )
complain( "Integer has non-DER encoding", level );
if( warnNegative )
complain( "Integer has a negative value", level );
}
}
/* Dump a bitstring, reversing the bits into the standard order in the
process */
static void dumpBitString( FILE *inFile, const int length, const int unused,
const int level )
{
unsigned int bitString = 0, currentBitMask = 0x80, remainderMask = 0xFF;
int bitFlag, value = 0, noBits, bitNo = -1, i;
char *errorStr = NULL;
if( unused < 0 || unused > 7 )
complain( "Invalid number of unused bits", level );
noBits = ( length * 8 ) - unused;
/* ASN.1 bitstrings start at bit 0, so we need to reverse the order of
the bits */
if( length )
{
bitString = fgetc( inFile );
fPos++;
}
for( i = noBits - 8; i > 0; i -= 8 )
{
bitString = ( bitString << 8 ) | fgetc( inFile );
currentBitMask <<= 8;
remainderMask = ( remainderMask << 8 ) | 0xFF;
fPos++;
}
if( reverseBitString )
{
for( i = 0, bitFlag = 1; i < noBits; i++ )
{
if( bitString & currentBitMask )
value |= bitFlag;
if( !( bitString & remainderMask ) )
/* The last valid bit should be a one bit */
errorStr = "Spurious zero bits in bitstring";
bitFlag <<= 1;
bitString <<= 1;
}
if( noBits < sizeof( int ) && \
( ( remainderMask << noBits ) & value ) )
/* There shouldn't be any bits set after the last valid one. We
have to do the noBits check to avoid a fencepost error when
there's exactly 32 bits */
errorStr = "Spurious one bits in bitstring";
}
/* Now that it's in the right order, dump it. If there's only one bit
set (which is often the case for bit flags) we also print the bit
number to save users having to count the zeroes to figure out which
flag is set */
fputc( '\n', output );
if( !doPure )
fprintf( output, " : " );
doIndent( level + 1 );
fputc( '\'', output );
currentBitMask = 1 << ( noBits - 1 );
for( i = 0; i < noBits; i++ )
{
if( value & currentBitMask )
{
bitNo = ( bitNo == -1 ) ? ( noBits - 1 ) - i : -2;
fputc( '1', output );
}
else
fputc( '0', output );
currentBitMask >>= 1;
}
if( bitNo >= 0 )
fprintf( output, "'B (bit %d)\n", bitNo );
else
fputs( "'B\n", output );
if( errorStr != NULL )
complain( errorStr, level );
}
/* Display data as a text string up to a maximum of 240 characters (8 lines
of 48 chars to match the hex limit of 8 lines of 16 bytes) with special
treatement for control characters and other odd things which can turn up
in BMPString and UniversalString types.
If the string is less than 40 chars in length, we try to print it on the
same line as the rest of the text (even if it wraps), otherwise we break
it up into 48-char chunks in a somewhat less nice text-dump format */
static void displayString( FILE *inFile, long length, int level,
STR_OPTION strOption )
{
long noBytes = ( length > 384 ) ? 384 : length;
int lineLength = 48;
int maxLevel = ( doPure ) ? 15 : 8, firstTime = TRUE, i;
int warnIA5 = FALSE, warnPrintable = FALSE, warnTime = FALSE;
int warnBMP = FALSE;
if( ( strOption == STR_UTCTIME && length != 13 ) || \
( strOption == STR_GENERALIZED && length != 15 ) )
warnTime = TRUE;
if( length <= 40 )
fprintf( output, " '" ); /* Print string on same line */
if( level > maxLevel )
level = maxLevel; /* Make sure we don't go off edge of screen */
for( i = 0; i < noBytes; i++ )
{
int ch;
/* If the string is longer than 40 chars, break it up into multiple
sections */
if( length > 40 && !( i % lineLength ) )
{
if( !firstTime )
fputc( '\'', output );
fputc( '\n', output );
if( !doPure )
fprintf( output, " : " );
doIndent( level + 1 );
fputc( '\'', output );
firstTime = FALSE;
}
ch = getc( inFile );
#ifdef __WIN32__
if( strOption == STR_BMP )
{
if( i == noBytes - 1 && ( noBytes & 1 ) )
/* Odd-length BMP string, complain */
warnBMP = TRUE;
else
{
const wchar_t wCh = ( ch << 8 ) | getc( inFile );
unsigned char outBuf[ 8 ];
int outLen;
/* Attempting to display Unicode characters is pretty hit and
miss, and if it fails nothing is displayed. To try and
detect this we use wcstombs() to see if anything can be
displayed, if it can't we drop back to trying to display
the data as non-Unicode. There's one exception to this
case, which is for a wrong-endianness Unicode string, for
which the first character looks like a single ASCII char */
outLen = wcstombs( outBuf, &wCh, 1 );
if( outLen < 1 )
/* Can't be displayed as Unicode, fall back to
displaying it as normal text */
ungetc( wCh & 0xFF, inFile );
else
{
lineLength++;
i++; /* We've read two characters for a wchar_t */
wprintf( L"%c", wCh );
fPos += 2;
continue;
}
}
}
#endif /* __WIN32__ */
switch( strOption )
{
case STR_PRINTABLE:
case STR_IA5:
if( strOption == STR_PRINTABLE && !isPrintable( ch ) )
warnPrintable = TRUE;
if( strOption == STR_IA5 && !isIA5( ch ) )
warnIA5 = TRUE;
if( ch < ' ' || ch >= 0x7F )
ch = '.'; /* Convert non-ASCII to placeholders */
break;
case STR_UTCTIME:
case STR_GENERALIZED:
if( !isdigit( ch ) && ch != 'Z' )
{
warnTime = TRUE;
if( ch < ' ' || ch >= 0x7F )
ch = '.'; /* Convert non-ASCII to placeholders */
}
break;
case STR_BMP_REVERSED:
if( i == noBytes - 1 && ( noBytes & 1 ) )
/* Odd-length BMP string, complain */
warnBMP = TRUE;
/* Wrong-endianness BMPStrings (Microsoft Unicode) can't be
handled through the usual widechar-handling mechanism
above since the first widechar looks like an ASCII char
followed by a null terminator, so we just treat them as
ASCII chars, skipping the following zero byte. This is
safe since the code which detects reversed BMPStrings
has already checked that every second byte is zero */
getc( inFile );
i++;
fPos++;
/* Drop through */
default:
if( ( ch & 0x7F ) < ' ' || ch == 0xFF )
ch = '.'; /* Convert control chars to placeholders */
}
fputc( ch, output );
fPos++;
}
if( length > 384 )
{
length -= 384;
fprintf( output, "'\n" );
if( !doPure )
fprintf( output, " : " );
doIndent( level + 5 );
fprintf( output, "[ Another %ld characters skipped ]", length );
fPos += length;
while( length-- )
{
int ch = getc( inFile );
if( strOption == STR_PRINTABLE && !isPrintable( ch ) )
warnPrintable = TRUE;
if( strOption == STR_IA5 && !isIA5( ch ) )
warnIA5 = TRUE;
}
}
else
fputc( '\'', output );
fputc( '\n', output );
/* Display any problems we encountered */
if( warnPrintable )
complain( "PrintableString contains illegal character(s)", level );
if( warnIA5 )
complain( "IA5String contains illegal character(s)", level );
if( warnTime )
complain( "Time is encoded incorrectly", level );
if( warnBMP )
complain( "BMPString has missing final byte/half character", level );
}
/****************************************************************************
* *
* ASN.1 Parsing Routines *
* *
****************************************************************************/
/* Get an integer value */
static long getValue( FILE *inFile, const long length )
{
long value;
char ch;
int i;
ch = getc( inFile );
value = ch;
for( i = 0; i < length - 1; i++ )
value = ( value << 8 ) | getc( inFile );
fPos += length;
return( value );
}
/* Get an ASN.1 objects tag and length */
int getItem( FILE *inFile, ASN1_ITEM *item )
{
int tag, length, index = 0;
memset( item, 0, sizeof( ASN1_ITEM ) );
item->indefinite = FALSE;
tag = item->header[ index++ ] = fgetc( inFile );
item->id = tag & ~TAG_MASK;
tag &= TAG_MASK;
if( tag == TAG_MASK )
{
int value;
/* Long tag encoded as sequence of 7-bit values. This doesn't try to
handle tags > INT_MAX, it'd be pretty peculiar ASN.1 if it had to
use tags this large */
tag = 0;
do
{
value = fgetc( inFile );
tag = ( tag << 7 ) | ( value & 0x7F );
item->header[ index++ ] = value;
fPos++;
}
while( value & LEN_XTND && index < 5 && !feof( inFile ) );
if( index == 5 )
{
fPos++; /* Tag */
return( FALSE );
}
}
item->tag = tag;
if( feof( inFile ) )
{
fPos++;
return( FALSE );
}
fPos += 2; /* Tag + length */
length = item->header[ index++ ] = fgetc( inFile );
item->headerSize = index;
if( length & LEN_XTND )
{
int i;
length &= LEN_MASK;
if( length > 4 )
/* Impossible length value, probably because we've run into
the weeds */
return( -1 );
item->headerSize += length;
item->length = 0;
if( !length )
item->indefinite = TRUE;
for( i = 0; i < length; i++ )
{
int ch = fgetc( inFile );
item->length = ( item->length << 8 ) | ch;
item->header[ i + index ] = ch;
}
fPos += length;
}
else
item->length = length;
return( TRUE );
}
/* Check whether a BIT STRING or OCTET STRING encapsulates another object */
static int checkEncapsulate( FILE *inFile, const int tag, const int length )
{
ASN1_ITEM nestedItem;
const int currentPos = fPos;
int diffPos;
/* If we're not looking for encapsulated objects, return */
if( !checkEncaps )
return( FALSE );
#if 1
/* Read the details of the next item in the input stream */
getItem( inFile, &nestedItem );
diffPos = fPos - currentPos;
fPos = currentPos;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -