⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dumpasn1.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	{
	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 + -