📄 dumpasn1.c
字号:
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: if( ( x = getc( inFile ) ) != 0 ) fprintf( output, " %d unused bit%s", x, ( x != 1 ) ? "s" : "" ); 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; } /* Drop through to dump it as an octet string */ case OCTETSTRING: if( checkEncapsulate( inFile, item->length ) ) { /* It's something encapsulated inside the string, print it as a constructed item */ fprintf( output, ", encapsulates" ); printConstructed( inFile, level, 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. If the user has overridden character set type checking and it's a string type for which we normally perform type checking, we reset its type to none */ displayString( inFile, item->length, level, \ ( !checkCharset && ( stringType == STR_IA5 || \ stringType == STR_PRINTABLE ) ) ? \ STR_NONE : 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 ) { /* Check if LHS status info + indent + "OID " string + oid name will wrap */ if( ( ( doPure ) ? 0 : INDENT_SIZE ) + ( level * 2 ) + 18 + \ strlen( oidInfo->description ) >= outputWidth ) { fputc( '\n', output ); if( !doPure ) fprintf( output, INDENT_STRING ); 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, INDENT_STRING ); doIndent( level + 1 ); fprintf( output, "(%s)\n", oidInfo->comment ); } /* If there's a warning associated with this OID, remember that there was a problem */ if( oidInfo->warn ) noWarnings++; break; } /* Pick apart the OID */ x = ( unsigned char ) buffer[ 0 ] / 40; y = ( unsigned char ) buffer[ 0 ] % 40; if( x > 2 ) { /* Handle special case for large y if x = 2 */ y += ( x - 2 ) * 40; x = 2; } fprintf( output, " '%d %d", x, y ); value = 0; for( x = 1; x < item->length; x++ ) { value = ( value << 7 ) | ( buffer[ x ] & 0x7F ); if( !( buffer[ x ] & 0x80 ) ) { fprintf( output, " %ld", value ); value = 0; } } fprintf( output, "'\n" ); break; case EOC: case NULLTAG: fputc( '\n', output ); break; case OBJDESCRIPTOR: case GRAPHICSTRING: case VISIBLESTRING: case GENERALSTRING: case UNIVERSALSTRING: case NUMERICSTRING: case VIDEOTEXSTRING: case UTF8STRING: displayString( inFile, item->length, level, STR_NONE ); break; case PRINTABLESTRING: displayString( inFile, item->length, level, STR_PRINTABLE ); break; case BMPSTRING: displayString( inFile, item->length, level, STR_BMP ); break; case UTCTIME: displayString( inFile, item->length, level, STR_UTCTIME ); break; case GENERALIZEDTIME: displayString( inFile, item->length, level, STR_GENERALIZED ); break; case IA5STRING: displayString( inFile, item->length, level, STR_IA5 ); break; case T61STRING: displayString( inFile, item->length, level, STR_LATIN1 ); break; default: fputc( '\n', output ); if( !doPure ) fprintf( output, INDENT_STRING ); doIndent( level + 1 ); fprintf( output, "Unrecognised primitive, hex value is:"); dumpHex( inFile, item->length, level, FALSE ); noErrors++; /* Treat it as an error */ } }/* Print a complex ASN.1 object */static int printAsn1( FILE *inFile, const int level, long length, const int isIndefinite ) { ASN1_ITEM item; long lastPos = fPos; int seenEOC = FALSE, status; /* Special-case for zero-length objects */ if( !length && !isIndefinite ) return( 0 ); while( ( status = getItem( inFile, &item ) ) > 0 ) { /* Perform various special checks the first time we're called */ if( length == LENGTH_MAGIC ) { /* If the length isn't known and the item has a definite length, set the length to the item's length */ if( !item.indefinite ) length = item.headerSize + item.length; /* If the input isn't seekable, turn off some options that require the use of fseek(). This check isn't perfect (some streams are slightly seekable due to buffering) but it's better than nothing */ if( fseek( inFile, -item.headerSize, SEEK_CUR ) ) { useStdin = TRUE; checkEncaps = FALSE; puts( "Warning: Input is non-seekable, some functionality " "has been disabled." ); } else fseek( inFile, item.headerSize, SEEK_CUR ); } /* Dump the header as hex data if requested */ if( doDumpHeader ) dumpHeader( inFile, &item ); /* Print offset into buffer, tag, and length */ if( item.header[ 0 ] == EOC ) { seenEOC = TRUE; if( !isIndefinite) complain( "Spurious EOC in definite-length item", level ); } if( !doPure ) {#if 0 /* Don't print hex tags any more to save display space */ if( item.indefinite ) fprintf( output, ( doHexValues ) ? "%04lX %02X NDEF: " : "%4ld %02X NDEF: ", lastPos, item.id | item.tag ); else if( !seenEOC ) fprintf( output, ( doHexValues ) ? "%04lX %02X %4lX: " : "%4ld %02X %4ld: ", lastPos, item.id | item.tag, item.length );#else if( item.indefinite ) fprintf( output, ( doHexValues ) ? "%04lX NDEF: " : "%4ld NDEF: ", lastPos ); else if( !seenEOC ) fprintf( output, ( doHexValues ) ? "%04lX %4lX: " : "%4ld %4ld: ", lastPos, item.length );#endif } /* Print details on the item */ if( !seenEOC ) { doIndent( level ); printASN1object( inFile, &item, level ); } /* If it was an indefinite-length object (no length was ever set) and we've come back to the top level, exit */ if( length == LENGTH_MAGIC ) return( 0 ); length -= fPos - lastPos; lastPos = fPos; if( isIndefinite ) { if( seenEOC ) return( 0 ); } else { if( length <= 0 ) { if( length < 0 ) return( ( int ) -length ); return( 0 ); } else { if( length == 1 ) { const int ch = fgetc( inFile ); /* No object can be one byte long, try and recover. This only works sometimes because it can be caused by spurious data in an OCTET STRING hole or an incorrect length encoding. The following workaround tries to recover from spurious data by skipping the byte if it's zero or a non-basic-ASN.1 tag, but keeping it if it could be valid ASN.1 */ if( ch && ch <= 0x31 ) ungetc( ch, inFile ); else { fPos++; return( 1 ); } } } } } if( status == -1 ) { int i; fprintf( stderr, "\nError: Invalid data encountered at position " "%d:", fPos ); for( i = 0; i < item.headerSize; i++ ) fprintf( stderr, " %02X", item.header[ i ] ); fprintf( stderr, ".\n" ); exit( EXIT_FAILURE ); } /* If we see an EOF and there's supposed to be more data present, complain */ if( length && length != LENGTH_MAGIC ) { fprintf( output, "Error: Inconsistent object length, %ld byte%s " "difference.\n", length, ( length > 1 ) ? "s" : "" ); noErrors++; } return( 0 ); }/* Show usage and exit */static void usageExit( void ) { puts( "DumpASN1 - ASN.1 object dump/syntax check program." ); puts( "Copyright Peter Gutmann 1997 - 2006. Last updated " UPDATE_STRING "." ); puts( "" ); puts( "Usage: dumpasn1 [-acdefhlprstuxz] <file>" ); puts( " Input options:" ); puts( " - = Take input from stdin (some options may not work properly)" ); puts( " -<number> = Start <number> bytes into the file" ); puts( " -- = End of arg list" ); puts( " -c<file> = Read Object Identifier info from alternate config file" ); puts( " (values will override equivalents in global config file)" ); puts( "" ); puts( " Output options:" ); puts( " -f<file> = Dump object at offset -<number> to file (allows data to be" ); puts( " extracted from encapsulating objects)" ); puts( " -w<number> = Set width of output, default = 80 columns" ); puts( "" ); puts( " Display options:" ); puts( " -a = Print all data in long data blocks, not just the first 128 bytes" ); puts( " -d = Print dots to show column alignment" ); puts( " -h = Hex dump object header (tag+length) before the decoded output" ); puts( " -hh = Same as -h but display more of the object as hex data" ); puts( " -i = Use shallow indenting, for deeply-nested objects" ); puts( " -l = Long format, display extra info about Object Identifiers" ); puts( " -p = Pure ASN.1 output without encoding information" ); puts( " -t = Display text values next to hex dump of data" ); puts( "" ); puts( " Format options:" ); puts( " -e = Don't print encapsulated data inside OCTET/BIT STRINGs" ); puts( " -r = Print bits in BIT STRING as encoded in reverse order" ); puts( " -u = Don't format UTCTime/GeneralizedTime string data" ); puts( " -x = Display size and offset in hex not decimal" ); puts( "" ); puts( " Checking options:" ); puts( " -o = Don't check validity of character strings hidden in octet strings" ); puts( " -s = Syntax check only, don't dump ASN.1 structures" ); puts( " -z = Allow zero-length items" ); puts( "" ); puts( "Warnings generated by deprecated OIDs require the use of '-l' to be displayed." ); puts( "Program return code is the number of errors found or EXIT_SUCCESS." ); exit( EXIT_FAILURE ); }int main( int argc, char *argv[] ) { FILE *inFile, *outFile = NULL;#ifdef __OS390__ char pathPtr[ FILENAME_MAX ];#else char *pathPtr = argv[ 0 ];#endif /* __OS390__ */ long offset = 0; int moreArgs = TRUE, doCheckOnly = FALSE;#ifdef __OS390__ memset( pathPtr, '\0', sizeof( pathPtr ) ); getcwd( pathPtr, sizeof( pathPtr ) ); strcat( pathPtr, "/" );#endif /* __OS390__ */ /* Skip the program name */ argv++; argc--; /* Display usage if no args given */ if( argc < 1 ) usageExit(); output = stdout; /* Needs to be assigned at runtime */ /* Check for arguments */ while( argc && *argv[ 0 ] == '-' && moreArgs ) { char *argPtr = argv[ 0 ] + 1; if( !*argPtr ) useStdin = TRUE; whi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -