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

📄 dumpasn1.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
					}

				/* 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 that detects reversed BMPStrings
				   has already checked that every second byte is zero */
				getc( inFile );
				i++;
				fPos++;
				/* Drop through */

			default:
				if( !isprint( ch ) )
					ch = '.';	/* Convert control chars to placeholders */
#ifdef __OS390__
				ch = asciiToEbcdic( ch );
#endif /* __OS390__ */
			}
		if( doTimeStr )
			timeStr[ i ] = ch;
		else
			fputc( ch, output );
		fPos++;
		}
	if( length > 384 && !printAllData )
		{
		length -= 384;
		fprintf( output, "'\n" );
		if( !doPure )
			fprintf( output, INDENT_STRING );
		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
		if( doTimeStr )
			{
			const char *timeStrPtr = ( strOption == STR_UTCTIME ) ? \
									 timeStr : timeStr + 2;

			fprintf( output, " %c%c/%c%c/", timeStrPtr[ 4 ], timeStrPtr[ 5 ],
					 timeStrPtr[ 2 ], timeStrPtr[ 3 ] );
			if( strOption == STR_UTCTIME )
				fprintf( output, ( timeStr[ 0 ] < '5' ) ? "20" : "19" );
			else
				fprintf( output, "%c%c", timeStr[ 0 ], timeStr[ 1 ] );
			fprintf( output, "%c%c %c%c:%c%c:%c%c GMT", timeStrPtr[ 0 ],
					 timeStrPtr[ 1 ], timeStrPtr[ 6 ], timeStrPtr[ 7 ],
					 timeStrPtr[ 8 ], timeStrPtr[ 9 ], timeStrPtr[ 10 ],
					 timeStrPtr[ 11 ] );
			}
		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 */

static 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 length )
	{
	ASN1_ITEM nestedItem;
	const int currentPos = fPos;
	int diffPos;

	/* If we're not looking for encapsulated objects, return */
	if( !checkEncaps )
		return( FALSE );

	/* Read the details of the next item in the input stream */
	getItem( inFile, &nestedItem );
	diffPos = fPos - currentPos;
	fPos = currentPos;
	fseek( inFile, -diffPos, SEEK_CUR );

	/* If it fits exactly within the current item and has a valid-looking
	   tag, treat it as nested data */
	if( ( ( nestedItem.id & CLASS_MASK ) == UNIVERSAL || \
		  ( nestedItem.id & CLASS_MASK ) == CONTEXT ) && \
		( nestedItem.tag > 0 && nestedItem.tag <= 0x31 ) && \
		nestedItem.length == length - diffPos )
		return( TRUE );

	return( FALSE );
	}

/* Check whether a zero-length item is OK */

static int zeroLengthOK( const ASN1_ITEM *item )
	{
	/* An implicitly-tagged NULL can have a zero length.  An occurrence of this
	   type of item is almost always an error, however OCSP uses a weird status
	   encoding that encodes result values in tags and then has to use a NULL
	   value to indicate that there's nothing there except the tag that encodes
	   the status, so we allow this as well if zero-length content is explicitly
	   enabled */
	if( zeroLengthAllowed && ( item->id & CLASS_MASK ) == CONTEXT )
		return( TRUE );

	/* If we can't recognise the type from the tag, reject it */
	if( ( item->id & CLASS_MASK ) != UNIVERSAL )
		return( FALSE );

	/* The following types are zero-length by definition */
	if( item->tag == EOC || item->tag == NULLTAG )
		return( TRUE );

	/* A real with a value of zero has zero length */
	if( item->tag == REAL )
		return( TRUE );

	/* Everything after this point requires input from the user to say that
	   zero-length data is OK (usually it's not, so we flag it as a
	   problem) */
	if( !zeroLengthAllowed )
		return( FALSE );

	/* String types can have zero length except for the Unrestricted
	   Character String type ([UNIVERSAL 29]) which has to have at least one
	   octet for the CH-A/CH-B index */
	if( item->tag == OCTETSTRING || item->tag == NUMERICSTRING || \
		item->tag == PRINTABLESTRING || item->tag == T61STRING || \
		item->tag == VIDEOTEXSTRING || item->tag == VISIBLESTRING || \
		item->tag == IA5STRING || item->tag == GRAPHICSTRING || \
		item->tag == GENERALSTRING || item->tag == UNIVERSALSTRING || \
		item->tag == BMPSTRING || item->tag == UTF8STRING || \
		item->tag == OBJDESCRIPTOR )
		return( TRUE );

	/* SEQUENCE and SET can be zero if there are absent optional/default
	   components */
	if( item->tag == SEQUENCE || item->tag == SET )
		return( TRUE );

	return( FALSE );
	}

/* Check whether the next item looks like text */

static STR_OPTION checkForText( FILE *inFile, const int length )
	{
	char buffer[ 16 ];
	int isBMP = FALSE, isUnicode = FALSE;
	int sampleLength = min( length, 16 ), i;

	/* If the sample is very short, we're more careful about what we
	   accept */
	if( sampleLength < 4 )
		{
		/* If the sample size is too small, don't try anything */
		if( sampleLength <= 2 )
			return( STR_NONE );

		/* For samples of 3-4 characters we only allow ASCII text.  These
		   short strings are used in some places (eg PKCS #12 files) as
		   IDs */
		sampleLength = fread( buffer, 1, sampleLength, inFile );
		fseek( inFile, -sampleLength, SEEK_CUR );
		for( i = 0; i < sampleLength; i++ )
			{
			if( !( isalpha( buffer[ i ] ) || isdigit( buffer[ i ] ) || \
				   isspace( buffer[ i ] ) ) )
				return( STR_NONE );
			}
		return( STR_IA5 );
		}

	/* Check for ASCII-looking text */
	sampleLength = fread( buffer, 1, sampleLength, inFile );
	fseek( inFile, -sampleLength, SEEK_CUR );
	if( isdigit( buffer[ 0 ] ) && ( length == 13 || length == 15 ) && \
		buffer[ length - 1 ] == 'Z' )
		{
		/* It looks like a time string, make sure that it really is one */
		for( i = 0; i < length - 1; i++ )
			{
			if( !isdigit( buffer[ i ] ) )
				break;
			}
		if( i == length - 1 )
			return( ( length == 13 ) ? STR_UTCTIME : STR_GENERALIZED );
		}
	for( i = 0; i < sampleLength; i++ )
		{
		/* If even bytes are zero, it could be a BMPString.  Initially
		   we set isBMP to FALSE, if it looks like a BMPString we set it to
		   TRUE, if we then encounter a nonzero byte it's neither an ASCII
		   nor a BMPString */
		if( !( i & 1 ) )
			{
			if( !buffer[ i ] )
				{
				/* If we thought we were in a Unicode string but we've found a
				   zero byte where it'd occur in a BMP string, it's neither a
				   Unicode nor BMP string */
				if( isUnicode )
					return( STR_NONE );

				/* We've collapsed the eigenstate (in an earlier incarnation
				   isBMP could take values of -1, 0, or 1, with 0 being
				   undecided, in which case this comment made a bit more
				   sense) */
				if( i < sampleLength - 2 )
					{
					/* If the last char(s) are zero but preceding ones
					   weren't, don't treat it as a BMP string.  This can
					   happen when storing a null-terminated string if the
					   implementation gets the length wrong and stores the
					   null as well */
					isBMP = TRUE;
					}
				continue;
				}
			else
				{
				/* If we thought we were in a BMPString but we've found a
				   nonzero byte where there should be a zero, it's neither
				   an ASCII nor BMP string */
				if( isBMP )
					return( STR_NONE );
				}
			}
		else
			{
			/* Just to make it tricky, Microsoft stuff Unicode strings into
			   some places (to avoid having to convert them to BMPStrings,
			   presumably) so we have to check for these as well */
			if( !buffer[ i ] )
				{
				if( isBMP )
					return( STR_NONE );
				isUnicode = TRUE;
				continue;
				}
			else
				if( isUnicode )
					return( STR_NONE );
			}
		if( buffer[ i ] < 0x20 || buffer[ i ] > 0x7E )
			return( STR_NONE );
		}

	/* It looks like a text string */
	return( isUnicode ? STR_BMP_REVERSED : isBMP ? STR_BMP : STR_IA5 );
	}

/* Dump the header bytes for an object, useful for vgrepping the original
   object from a hex dump */

static void dumpHeader( FILE *inFile, const ASN1_ITEM *item )
	{
	int extraLen = 24 - item->headerSize, i;

	/* Dump the tag and length bytes */
	if( !doPure )
		fprintf( output, "    " );
	fprintf( output, "<%02X", *item->header );
	for( i = 1; i < item->headerSize; i++ )
		fprintf( output, " %02X", item->header[ i ] );

	/* If we're asked for more, dump enough extra data to make up 24 bytes.
	   This is somewhat ugly since it assumes we can seek backwards over the
	   data, which means it won't always work on streams */
	if( extraLen > 0 && doDumpHeader > 1 )
		{
		/* Make sure that we don't print too much data.  This doesn't work
		   for indefinite-length data, we don't try and guess the length with
		   this since it involves picking apart what we're printing */
		if( extraLen > item->length && !item->indefinite )
			extraLen = ( int ) item->length;

		for( i = 0; i < extraLen; i++ )
			{
			int ch = fgetc( inFile );

			if( feof( inFile ) )
				extraLen = i;	/* Exit loop and get fseek() correct */
			else
				fprintf( output, " %02X", ch );
			}
		fseek( inFile, -extraLen, SEEK_CUR );
		}

	fputs( ">\n", output );
	}

/* Print a constructed ASN.1 object */

static int printAsn1( FILE *inFile, const int level, long length,
					  const int isIndefinite );

static void printConstructed( FILE *inFile, int level, const ASN1_ITEM *item )
	{
	int result;

	/* Special case for zero-length objects */
	if( !item->length && !item->indefinite )
		{
		fputs( " {}\n", output );
		return;
		}

	fputs( " {\n", output );
	result = printAsn1( inFile, level + 1, item->length, item->indefinite );
	if( result )
		{
		fprintf( output, "Error: Inconsistent object length, %d byte%s "
				 "difference.\n", result, ( result > 1 ) ? "s" : "" );
		noErrors++;
		}
	if( !doPure )
		fprintf( output, INDENT_STRING );
	fprintf( output, ( printDots ) ? ". " : "  " );
	doIndent( level );
	fputs( "}\n", output );
	}

/* Print a single ASN.1 object */

static void printASN1object( FILE *inFile, ASN1_ITEM *item, int level )
	{
	OIDINFO *oidInfo;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -