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

📄 dumpasn1.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 );
#else
	/* Older code which used heuristics but was actually less accurate than
	   the above code */
	int ch;

	/* Get the first character and see if it's an INTEGER or SEQUENCE */
	ch = getc( inFile );
	ungetc( ch, inFile );
	if( ch == INTEGER || ch == ( SEQUENCE | CONSTRUCTED ) )
		return( TRUE );

	/* All sorts of weird things get bundled up in octet strings in
	   certificate extensions */
	if( tag == OCTETSTRING && ch == BITSTRING )
		return( TRUE );

	/* If we're looking for all sorts of things which might be encapsulated,
	   check for these as well.  At the moment we only check for a small
	   number of possibilities, this list will probably change as more
	   oddities are discovered, the idea is to keep the amount of burrowing
	   we do to a minimum in order to reduce problems with false positives */
	if( level > 1 && tag == OCTETSTRING )
		{
		int length;

		if( ch == IA5STRING )
			/* Verisign extensions */
			return( TRUE );

		/* For the following possibilities we have to look ahead a bit
		   further and check the length as well */
		getc( inFile );
		length = getc( inFile );
		fseek( inFile, -2, SEEK_CUR );
		if( ( ch == OID && length < 9 ) || \
			( ch == ENUMERATED && length == 1 ) || \
			( ch == GENERALIZEDTIME && length == 15 ) )
			/* CRL per-entry extensions */
			return( TRUE );
		}
#endif /* 0 */

	return( FALSE );
	}

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

int zeroLengthOK( const ASN1_ITEM *item )
	{
	/* 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 int checkForText( FILE *inFile, const int length )
	{
	STR_OPTION stringType;
	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 ] ) ) )
				return( STR_NONE );
		return( STR_IA5 );
		}

	/* Check for ASCII-looking text */
	sampleLength = fread( buffer, 1, sampleLength, inFile );
	fseek( inFile, -sampleLength, SEEK_CUR );
	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 ] )
				{
				/* 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) */
				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 ] )
				{
				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 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 */

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, "            : " );
	fprintf( output, ( printDots ) ? ". " : "  " );
	doIndent( level );
	fputs( "}\n", output );
	}

/* Print a single ASN.1 object */

void printASN1object( FILE *inFile, ASN1_ITEM *item, int level )
	{
	OIDINFO *oidInfo;
	STR_OPTION stringType;
	char buffer[ MAX_OID_SIZE ];
	long value;
	int x, y;

	if( ( item->id & CLASS_MASK ) != UNIVERSAL )
		{
		static const char *const classtext[] =
			{ "UNIVERSAL ", "APPLICATION ", "", "PRIVATE " };

		/* Print the object type */
		fprintf( output, "[%s%d]",
				 classtext[ ( item->id & CLASS_MASK ) >> 6 ], item->tag );

		/* Perform a sanity check */
		if( ( item->tag != NULLTAG ) && ( item->length < 0 ) )
			{
			int i;

			fprintf( stderr, "\nError: Object has bad length field, tag = %02X, "
					 "length = %lX, value =", item->tag, item->length );
			fprintf( stderr, "<%02X", *item->header );
			for( i = 1; i < item->headerSize; i++ )
				fprintf( stderr, " %02X", item->header[ i ] );
			fputs( ">.\n", stderr );
			exit( EXIT_FAILURE );
			}

		if( !item->length && !item->indefinite )
			{
			fputc( '\n', output );
			complain( "Object has zero length", level );
			return;
			}

		/* If it's constructed, print the various fields in it */
		if( ( item->id & FORM_MASK ) == CONSTRUCTED )
			{
			printConstructed( inFile, level, item );
			return;
			}

		/* It's primitive, if it's a seekable stream try and determine
		   whether it's text so we can display it as such */
		if( !useStdin && \
			( stringType = checkForText( inFile, item->length ) ) != STR_NONE )
			{
			/* It looks like a text string, dump it as text */
			displayString( inFile, item->length, level, stringType );
			return;
			}

		/* This could be anything, dump it as hex data */
		dumpHex( inFile, item->length, level, FALSE );

		return;
		}

	/* Print the object type */
	fprintf( output, "%s", idstr( item->tag ) );

	/* Perform a sanity check */
	if( ( item->tag != NULLTAG ) && ( item->length < 0 ) )
		{
		int i;

		fprintf( stderr, "\nError: Object has bad length field, tag = %02X, "
				 "length = %lX, value =", item->tag, item->length );
		fprintf( stderr, "<%02X", *item->header );
		for( i = 1; i < item->headerSize; i++ )
			fprintf( stderr, " %02X", item->header[ i ] );
		fputs( ">.\n", stderr );
		exit( EXIT_FAILURE );
		}

	/* If it's constructed, print the various fields in it */
	if( ( item->id & FORM_MASK ) == CONSTRUCTED )
		{
		printConstructed( inFile, level, item );
		return;
		}

	/* It's primitive */
	if( !item->length && !zeroLengthOK( item ) )
		{
		fputc( '\n', output );
		complain( "Object has zero length", level );
		return;
		}
	switch( item->tag )
		{
		case BOOLEAN:
			x = getc( inFile );
			fprintf( output, " %s\n", x ? "TRUE" : "FALSE" );
			if( x != 0 && x != 0xFF )
				complain( "BOOLEAN has non-DER encoding", level );
			fPos++;
			break;

		case INTEGER:
		case ENUMERATED:
			if( item->length > 4 )
				dumpHex( inFile, item->length, level, TRUE );
			else
				{
				value = getValue( inFile, item->length );
				fprintf( output, " %ld\n", value );
				if( value < 0 )
					complain( "Integer has a negative value", level );
				}
			break;

		case BITSTRING:
			fprintf( output, " %d unused bits", x = getc( inFile ) );
			fPos++;
			if( !--item->length && !x )
				{
				fputc( '\n', output );
				complain( "Object has zero length", level );
				return;
				}
			if( item->length <= sizeof( int ) )
				{
				/* It's short enough to be a bit flag, dump it as a sequence
				   of bits */
				dumpBitString( inFile, ( int ) item->length, x, level );
				break;
				}
		case OCTETSTRING:
			if( checkEncapsulate( inFile, item->tag, item->length ) )
				{
				/* It's something encapsulated inside the string, print it as
				   a constructed item */
				fprintf( output, ", encapsulates" );
				printConstructed( inFile, level + 1, item );
				break;
				}
			if( !useStdin && !dumpText && \
				( stringType = checkForText( inFile, item->length ) ) != STR_NONE )
				{
				/* If we'd be doing a straight hex dump and it looks like
				   encapsulated text, display it as such */
				displayString( inFile, item->length, level, stringType );
				return;
				}
			dumpHex( inFile, item->length, level, FALSE );
			break;

		case OID:
			/* Hierarchical Object Identifier: The first two levels are
			   encoded into one byte, since the root level has only 3 nodes
			   (40*x + y).  However if x = joint-iso-itu-t(2) then y may be
			   > 39, so we have to add special-case handling for this */
			if( item->length > MAX_OID_SIZE )
				{
				fprintf( stderr, "\nError: Object identifier length %ld too "
						 "large.\n", item->length );
				exit( EXIT_FAILURE );
				}
			fread( buffer, 1, ( size_t ) item->length, inFile );
			fPos += item->length;
			if( ( oidInfo = getOIDinfo( buffer, ( int ) item->length ) ) != NULL )
				{
				int lhsSize = ( doPure ) ? 0 : 14;

				/* Check if LHS status info + indent + "OID " string + oid
				   name will wrap */
				if( lhsSize + ( level * 2 ) + 18 + strlen( oidInfo->description ) >= 80 )
					{
					fputc( '\n', output );
					if( !doPure )
						fprintf( output, "            : " );
					doIndent( level + 1 );
					}
				else
					fputc( ' ', output );
				fprintf( output, "%s\n", oidInfo->description );

				/* Display extra comments about the OID if required */
				if( extraOIDinfo && oidInfo->comment != NULL )
					{
					if( !doPure )
						fprintf( output, "            : " );
					doIndent( level + 1 );
					fprintf( output, "(%s)\n", oidInfo->comment );
					}

⌨️ 快捷键说明

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