📄 dumpasn1.c
字号:
#endif /* __UNIX__ */
if( strlen( path ) < FILENAME_MAX - 13 && namePos != NULL )
{
strcpy( buffer, path );
strcpy( buffer + ( int ) ( namePos - ( char * ) path ), CONFIG_NAME );
if( testConfigPath( buffer ) )
return( readConfig( buffer, TRUE ) );
}
/* Now try each of the possible absolute locations for the config file */
for( i = 0; configPaths[ i ] != NULL; i++ )
{
buildConfigPath( buffer, configPaths[ i ] );
if( testConfigPath( buffer ) )
return( readConfig( buffer, TRUE ) );
}
#ifdef __UNIX__
/* On Unix systems we can also search for the config file on $PATH */
if( ( envPath = getenv( "PATH" ) ) != NULL )
{
char *pathPtr = strtok( envPath, ":" );
do
{
sprintf( buffer, "%s/%s", pathPtr, CONFIG_NAME );
if( testConfigPath( buffer ) )
return( readConfig( buffer, TRUE ) );
pathPtr = strtok( NULL, ":" );
}
while( pathPtr != NULL );
}
#endif /* __UNIX__ */
/* Default to just the config name (which should fail as it was the
first entry in configPaths[]). readConfig() will display the
appropriate warning */
return( readConfig( CONFIG_NAME, TRUE ) );
}
/****************************************************************************
* *
* Output/Formatting Routines *
* *
****************************************************************************/
#ifdef __OS390__
static int asciiToEbcdic( const int ch )
{
char convBuffer[ 2 ];
convBuffer[ 0 ] = ch;
convBuffer[ 1 ] = '\0';
__atoe( convBuffer ); /* Convert ASCII to EBCDIC for 390 */
return( convBuffer[ 0 ] );
}
#endif /* __OS390__ */
/* Indent a string by the appropriate amount */
static void doIndent( const int level )
{
int i;
for( i = 0; i < level; i++ )
fprintf( output, printDots ? ". " : \
shallowIndent ? " " : " " );
}
/* Complain about an error in the ASN.1 object */
static void complain( const char *message, const int level )
{
if( !doPure )
fprintf( output, INDENT_STRING );
doIndent( level + 1 );
fprintf( output, "Error: %s.\n", message );
noErrors++;
}
/* Dump data as a string of hex digits up to a maximum of 128 bytes */
static void dumpHex( FILE *inFile, long length, int level, int isInteger )
{
const int lineLength = ( dumpText ) ? 8 : 16;
char printable[ 9 ];
long noBytes = length;
int zeroPadded = FALSE, warnPadding = FALSE, warnNegative = isInteger;
int singleLine = FALSE;
int maxLevel = ( doPure ) ? 15 : 8, prevCh = -1, i;
/* Check if LHS status info + indent + "OCTET STRING" string + data will
wrap */
if( ( ( doPure ) ? 0 : INDENT_SIZE ) + ( level * 2 ) + 12 + \
( length * 3 ) < outputWidth )
singleLine = TRUE;
if( noBytes > 128 && !printAllData )
noBytes = 128; /* Only output a maximum of 128 bytes */
if( level > maxLevel )
level = maxLevel; /* Make sure that 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( singleLine )
fputc( ' ', output );
else
{
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, INDENT_STRING );
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 == 0 )
{
prevCh = ch;
if( !ch )
zeroPadded = TRUE;
if( !( ch & 0x80 ) )
warnNegative = FALSE;
}
if( i == 1 )
{
/* Check for the first 9 bits being identical */
if( ( prevCh == 0x00 ) && ( ( ch & 0x80 ) == 0x00 ) )
warnPadding = TRUE;
if( ( prevCh == 0xFF ) && ( ( ch & 0x80 ) == 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, INDENT_STRING );
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 necessary */
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";
}
}
else
value = 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, INDENT_STRING );
doIndent( level + 1 );
fputc( '\'', output );
if( reverseBitString )
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 that 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 )
{
char timeStr[ 64 ];
#ifdef __OS390__
char convBuffer[ 2 ];
#endif /* __OS390__ */
long noBytes = length;
int lineLength = 48, maxLevel = ( doPure ) ? 15 : 8, i;
int firstTime = TRUE, doTimeStr = FALSE, warnIA5 = FALSE;
int warnPrintable = FALSE, warnTime = FALSE, warnBMP = FALSE;
if( noBytes > 384 && !printAllData )
noBytes = 384; /* Only output a maximum of 384 bytes */
if( strOption == STR_UTCTIME || strOption == STR_GENERALIZED )
{
if( ( strOption == STR_UTCTIME && length != 13 ) || \
( strOption == STR_GENERALIZED && length != 15 ) )
warnTime = TRUE;
else
doTimeStr = rawTimeString ? FALSE : TRUE;
}
if( !doTimeStr && length <= 40 )
fprintf( output, " '" ); /* Print string on same line */
if( level > maxLevel )
level = maxLevel; /* Make sure that 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, INDENT_STRING );
doIndent( level + 1 );
fputc( '\'', output );
firstTime = FALSE;
}
ch = getc( inFile );
#if defined( __WIN32__ ) || defined( __UNIX__ ) || defined( __OS390__ )
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 );
char outBuf[ 8 ];
#ifdef __OS390__
char *p;
#endif /* OS-specific charset handling */
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 */
#if defined( __WIN32__ )
fputwc( wCh, output );
#elif defined( __UNIX__ ) && !( defined( __MACH__ ) || defined( __OpenBSD__ ) )
/* Some Unix environments differentiate between char
and wide-oriented stdout (!!!), so it's necessary to
manually switch the orientation of stdout to make it
wide-oriented before calling a widechar output
function or nothing will be output (exactly what
level of braindamage it takes to have an
implementation function like this is a mystery). In
order to safely display widechars, we therefore have
to use the fwide() kludge function to change stdout
modes around the display of the widechar */
if( fwide( output, 1 ) > 0 )
{
fputwc( wCh, output );
fwide( output, -1 );
}
else
fputc( wCh, output );
#else
#ifdef __OS390__
/* This could use some improvement */
for( p = outBuf; *p != '\0'; p++ )
*p = asciiToEbcdic( *p );
#endif /* IBM ASCII -> EBCDIC conversion */
fprintf( output, "%s", outBuf );
#endif /* OS-specific charset handling */
fPos += 2;
continue;
}
}
}
#endif /* __WIN32__ || __UNIX__ || __OS390__ */
switch( strOption )
{
case STR_PRINTABLE:
case STR_IA5:
case STR_LATIN1:
if( strOption == STR_PRINTABLE && !isPrintable( ch ) )
warnPrintable = TRUE;
if( strOption == STR_IA5 && !isIA5( ch ) )
warnIA5 = TRUE;
if( strOption == STR_LATIN1 )
{
if( !isprint( ch & 0x7F ) )
ch = '.'; /* Convert non-ASCII to placeholders */
}
else
{
if( !isprint( ch ) )
ch = '.'; /* Convert non-ASCII to placeholders */
}
#ifdef __OS390__
ch = asciiToEbcdic( ch );
#endif /* __OS390__ */
break;
case STR_UTCTIME:
case STR_GENERALIZED:
if( !isdigit( ch ) && ch != 'Z' )
{
warnTime = TRUE;
if( !isprint( ch ) )
ch = '.'; /* Convert non-ASCII to placeholders */
}
#ifdef __OS390__
ch = asciiToEbcdic( ch );
#endif /* __OS390__ */
break;
case STR_BMP_REVERSED:
if( i == noBytes - 1 && ( noBytes & 1 ) )
{
/* Odd-length BMP string, complain */
warnBMP = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -