RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  [email protected]
  Module: rpm                              Date:   26-Jun-2010 22:05:57
  Branch: HEAD                             Handle: 2010062620055700

  Modified files:
    rpm/rpmio               dumpasn1.c

  Log:
    - update to latest.

  Summary:
    Revision    Changes     Path
    2.4         +499 -97    rpm/rpmio/dumpasn1.c
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: rpm/rpmio/dumpasn1.c
  ============================================================================
  $ cvs diff -u -r2.3 -r2.4 dumpasn1.c
  --- rpm/rpmio/dumpasn1.c      14 Jul 2007 22:47:29 -0000      2.3
  +++ rpm/rpmio/dumpasn1.c      26 Jun 2010 20:05:57 -0000      2.4
  @@ -6,22 +6,33 @@
      <[email protected]>, Geoff Thorpe <[email protected]>, David Boyce
      <[email protected]>, John Hughes <[email protected]>, Life is 
hard,
      and then you die <[email protected]>, Hans-Olof Hermansson
  -   <[email protected]>, Tor Rustad <[email protected]>,
  -   Kjetil Barvik <[email protected]>, James Sweeny <[email protected]>,
  -   Chris Ridd <[email protected]>, and several other people whose names
  -   I've misplaced.  This code grew slowly over time without much design or
  -   planning, with features being tacked on as required.  It's not
  -   representative of my normal coding style.
  -
  -   Available from http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.c.
  -   Last updated 22 June 2006 (version 20060622, if you prefer it that
  -   way).  To build under Windows, use 'cl /MD dumpasn1.c'.  To build on OS390
  -   or z/OS, use '/bin/c89 -D OS390 -o dumpasn1 dumpasn1.c'.
  +   <[email protected]>, Tor Rustad <[email protected]>, Kjetil
  +   Barvik <[email protected]>, James Sweeny <[email protected]>, Chris
  +   Ridd <[email protected]>, David Lemley <[email protected]> and 
several
  +   other people whose names I've misplaced (a number of those email addresses
  +   probably no longer work, since this code has been around for awhile).
  +
  +   Available from http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.c. Last
  +   updated 18 March 2010 (version 20100318, if you prefer it that way).  
  +   To build under Windows, use 'cl /MD dumpasn1.c'.  To build on OS390 or 
  +   z/OS, use '/bin/c89 -D OS390 -o dumpasn1 dumpasn1.c'.
  +
  +   This code grew slowly over time without much design or planning, and with
  +   extra features being tacked on as required.  It's not representative of my
  +   normal coding style.  cryptlib,
  +   http://www.cs.auckland.ac.nz/~pgut001/cryptlib/, does a much better job of
  +   checking ASN.1 than this does, since dumpasn1 is a display program written
  +   to accept the widest possible range of input and not a compliance checker.
  +   In other words it will bend over backwards to accept even invalid data,
  +   since a common use for it is to try and locate encoding problems that lead
  +   to invalid encoded data.  While it will warn about some types of common
  +   errors, the fact that dumpasn1 will display an ASN.1 data item doesn't 
mean
  +   that the item is valid.
   
      This version of dumpasn1 requires a config file dumpasn1.cfg to be present
  -   in the same location as the program itself or in a standard directory
  -   where binaries live (it will run without it but will display a warning
  -   message, you can configure the path either by hardcoding it in or using an
  +   in the same location as the program itself or in a standard directory 
where
  +   binaries live (it will run without it but will display a warning message,
  +   you can configure the path either by hardcoding it in or using an
      environment variable as explained further down).  The config file is
      available from http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.cfg.
   
  @@ -31,8 +42,8 @@
      that you use a utility like uudeview, which will strip virtually any kind
      of encoding (MIME, PEM, PGP, whatever) to recover the binary original.
   
  -   You can use this code in whatever way you want, as long as you don't try
  -   to claim you wrote it.
  +   You can use this code in whatever way you want, as long as you don't try 
to
  +   claim you wrote it.
   
      Editing notes: Tabs to 4, phasers to stun (and in case anyone wants to
      complain about that, see "Program Indentation and Comprehensiblity",
  @@ -40,6 +51,7 @@
      Communications of the ACM, Vol.26, No.11 (November 1983), p.861) */
   
   #include <ctype.h>
  +#include <limits.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
  @@ -49,7 +61,7 @@
   
   /* The update string, printed as part of the help screen */
   
  -#define UPDATE_STRING        "22 June 2006"
  +#define UPDATE_STRING        "18 March 2010"
   
   /* Useful defines */
   
  @@ -97,6 +109,7 @@
   
   #if ( defined( _WINDOWS ) || defined( WIN32 ) || defined( _WIN32 ) || \
          defined( __WIN32__ ) )
  +  #include <windows.h>
     #define __WIN32__
   #endif /* Win32 */
   
  @@ -113,7 +126,9 @@
     #define __UNIX__
   #endif /* Every commonly-used Unix */
   #if defined( linux ) || defined( __linux__ )
  -  #define __USE_ISOC99
  +  #ifndef __USE_ISOC99
  +     #define __USE_ISOC99
  +  #endif /* __USE_ISOC99 */
     #include <wchar.h>
   #endif /* Linux */
   
  @@ -141,6 +156,10 @@
     #define min(a,b)           ( ( a ) < ( b ) ? ( a ) : ( b ) )
   #endif /* !min */
   
  +/* Macros to avoid problems with sign extension */
  +
  +#define byteToInt( x )       ( ( unsigned char ) ( x ) )
  +
   /* The level of recursion can get scary for deeply-nested structures so we
      use a larger-than-normal stack under DOS */
   
  @@ -148,6 +167,12 @@
     extern unsigned _stklen = 16384;
   #endif /* __TURBOC__ */
   
  +/* Turn off pointless VC++ warnings */
  +
  +#ifdef _MSC_VER
  +  #pragma warning( disable: 4018 )
  +#endif /* VC++ */
  +
   /* When we dump a nested data object encapsulated within a larger object, the
      length is initially set to a magic value which is adjusted to the actual
      length once we start parsing the object */
  @@ -279,8 +304,9 @@
   
   typedef struct tagOIDINFO {
        struct tagOIDINFO *next;                /* Next item in list */
  -     char oid[ MAX_OID_SIZE ], *comment, *description;
  -     int oidLength;                                  /* Name, rank, serial 
number */
  +     unsigned char oid[ MAX_OID_SIZE ];
  +     int oidLength;
  +     char *comment, *description;    /* Name, rank, serial number */
        int warn;                                               /* Whether to 
warn if OID encountered */
        } OIDINFO;
   
  @@ -310,16 +336,19 @@
   
   static const char *configPaths[] = {
        /* Windoze absolute paths.  Usually things are on C:, but older NT 
setups
  -        are easier to do on D: if the initial copy is done to C: */
  +        are easier to do on D: if the initial copy is done to C: (yeah, this
  +        code has been around for awhile, why do you ask?) */
        "c:\\dos\\", "d:\\dos\\", "c:\\windows\\", "d:\\windows\\",
        "c:\\winnt\\", "d:\\winnt\\",
   
        /* It's my program, I'm allowed to hardcode in strange paths that no-one
           else uses */
        "c:\\program files\\bin\\",
  +     "c:\\program files (x86)\\bin\\",
   
        /* This one seems to be popular as well */
        "c:\\program files\\utilities\\",
  +     "c:\\program files (x86)\\utilities\\",
   
        /* General environment-based paths */
        "$DUMPASN1_PATH/",
  @@ -350,8 +379,10 @@
           else uses */
        "$HOME/BIN/",
     #else
  -     /* Debian has specific places where you're supposed to dump things */
  -     "$HOME/", "/etc/dumpasn1/",
  +     /* Debian has specific places where you're supposed to dump things.  
Note
  +        the dot after $HOME, since config files are supposed to start with a
  +        dot for Debian */
  +     "$HOME/.", "/etc/dumpasn1/",
     #endif /* DEBIAN-specific paths */
   
        /* General environment-based paths */
  @@ -442,11 +473,12 @@
        {
        OIDINFO *oidPtr;
   
  -     memset( oid + oidLength, 0, 2 );
        for( oidPtr = oidList; oidPtr != NULL; oidPtr = oidPtr->next )
  +             {
                if( oidLength == oidPtr->oidLength - 2 && \
                        !memcmp( oidPtr->oid + 2, oid, oidLength ) )
                        return( oidPtr );
  +             }
   
        return( NULL );
        }
  @@ -570,8 +602,10 @@
   
        /* If we've just passed a CR, check for a following LF */
        if( ch == '\r' )
  +             {
                if( ( ch = getc( file ) ) != '\n' )
                        ungetc( ch, file );
  +             }
   
        /* Skip trailing whitespace and add der terminador */
        while( bufCount > 0 &&
  @@ -581,14 +615,97 @@
   
        /* Handle special-case of ^Z if file came off an MSDOS system */
        if( ch == CPM_EOF )
  +             {
                while( !feof( file ) )
  +                     {
                        /* Keep going until we hit the true EOF (or some sort 
of error) */
                        ch = getc( file );
  +                     }
  +             }
   
        return( ferror( file ) ? FALSE : TRUE );
        }
   
  -/* Process an OID specified as space-separated hex digits */
  +/* Process an OID specified as space-separated decimal or hex digits */
  +
  +static int processOID( OIDINFO *oidInfo, char *string )
  +     {
  +     unsigned char binaryOID[ MAX_OID_SIZE ];
  +     int firstValue, value, valueIndex = 0, oidIndex = 3;
  +
  +     memset( binaryOID, 0, MAX_OID_SIZE );
  +     binaryOID[ 0 ] = OID;
  +     while( *string && oidIndex < MAX_OID_SIZE )
  +             {
  +             if( oidIndex >= MAX_OID_SIZE - 4 )
  +                     {
  +                     printf( "Excessively long OID in config file line 
%d.\n",
  +                                     lineNo );
  +                     return( FALSE );
  +                     }
  +             if( sscanf( string, "%d", &value ) != 1 || value < 0 )
  +                     {
  +                     printf( "Invalid value in config file line %d.\n", 
lineNo );
  +                     return( FALSE );
  +                     }
  +             if( valueIndex == 0 )
  +                     {
  +                     firstValue = value;
  +                     valueIndex++;
  +                     }
  +             else
  +                     {
  +                     if( valueIndex == 1 )
  +                             {
  +                             if( firstValue < 0 || firstValue > 2 || value < 
0 || \
  +                                     ( ( firstValue < 2 && value > 39 ) || \
  +                                       ( firstValue == 2 && value > 175 ) ) )
  +                                     {
  +                                     printf( "Invalid value in config file 
line %d.\n",
  +                                                     lineNo );
  +                                     return( FALSE );
  +                                     }
  +                             binaryOID[ 2 ] = ( firstValue * 40 ) + value;
  +                             valueIndex++;
  +                             }
  +                     else
  +                             {
  +                             int hasHighBits = FALSE;
  +
  +                             if( value >= 0x200000L )                        
                /* 2^21 */
  +                                     {
  +                                     binaryOID[ oidIndex++ ] = 0x80 | ( 
value >> 21 );
  +                                     value %= 0x200000L;
  +                                     hasHighBits = TRUE;
  +                                     }
  +                             if( ( value >= 0x4000 ) || hasHighBits )        
/* 2^14 */
  +                                     {
  +                                     binaryOID[ oidIndex++ ] = 0x80 | ( 
value >> 14 );
  +                                     value %= 0x4000;
  +                                     hasHighBits = TRUE;
  +                                     }
  +                             if( ( value >= 0x80 ) || hasHighBits )          
/* 2^7 */
  +                                     {
  +                                     binaryOID[ oidIndex++ ] = 0x80 | ( 
value >> 7 );
  +                                     value %= 128;
  +                                     }
  +                             binaryOID[ oidIndex++ ] = value;
  +                             }
  +                     }
  +             while( *string && isdigit( byteToInt( *string ) ) )
  +                     string++;
  +             if( *string && *string++ != ' ' )
  +                     {
  +                     printf( "Invalid OID string in config file line %d.\n", 
lineNo );
  +                     return( FALSE );
  +                     }
  +             }
  +     binaryOID[ 1 ] = oidIndex - 2;
  +     memcpy( oidInfo->oid, binaryOID, oidIndex );
  +     oidInfo->oidLength = oidIndex;
  +
  +     return( TRUE );
  +     }
   
   static int processHexOID( OIDINFO *oidInfo, char *string )
        {
  @@ -623,8 +740,9 @@
   
   static int readConfig( const char *path, const int isDefaultConfig )
        {
  -     OIDINFO dummyOID = { NULL, "Dummy", "Dummy", "Dummy", 1 }, *oidPtr;
  +     OIDINFO dummyOID = { NULL, "Dummy", 0, "Dummy", "Dummy", 1 }, *oidPtr;
        FILE *file;
  +     int seenHexOID = FALSE;
        char buffer[ MAX_LINESIZE ];
        int status;
   
  @@ -680,8 +798,7 @@
                                }
   
                        /* Allocate storage for the new OID */
  -                     if( ( oidPtr->next = ( struct tagOIDINFO * ) \
  -                                                              malloc( 
sizeof( OIDINFO ) ) ) == NULL )
  +                     if( ( oidPtr->next = ( OIDINFO * ) malloc( sizeof( 
OIDINFO ) ) ) == NULL )
                                {
                                puts( "Out of memory." );
                                return( FALSE );
  @@ -692,8 +809,17 @@
                        memset( oidPtr, 0, sizeof( OIDINFO ) );
   
                        /* Add the new OID */
  -                     if( !processHexOID( oidPtr, buffer + 6 ) )
  -                             return( FALSE );
  +                     if( !strncmp( buffer + 6, "06", 2 ) )
  +                             {
  +                             seenHexOID = TRUE;
  +                             if( !processHexOID( oidPtr, buffer + 6 ) )
  +                                     return( FALSE );
  +                             }
  +                     else
  +                             {
  +                             if( !processOID( oidPtr, buffer + 6 ) )
  +                                     return( FALSE );
  +                             }
                        }
                else if( !strncmp( buffer, "Description = ", 14 ) )
                        {
  @@ -738,6 +864,15 @@
                }
        fclose( file );
   
  +     /* If we're processing an old-style config file, tell the user to
  +        upgrade */
  +     if( seenHexOID )
  +             {
  +             puts( "\nWarning: Use of old-style hex OIDs detected in "
  +                       "configuration file, please\n         update your 
dumpasn1 "
  +                       "configuration file.\n" );
  +             }
  +
        return( status );
        }
   
  @@ -779,8 +914,10 @@
                else
                        substringSize = pathLen - pathPos;
                if( substringSize > 0 )
  +                     {
                        memcpy( newPath + newPathPos, pathBuffer + pathPos,
                                        substringSize );
  +                     }
                newPathPos += substringSize;
                pathPos += substringSize;
   
  @@ -826,13 +963,20 @@
   #ifdef __UNIX__
        char *envPath;
   #endif /* __UNIX__ */
  +#ifdef __WIN32__
  +     char filePath[ _MAX_PATH ];
  +     DWORD count;
  +#endif /* __WIN32__ */
        int i;
   
        /* First, try and find the config file in the same directory as the
           executable by walking down the path until we find the last occurrence
           of the program name.  This requires that argv[0] be set up properly,
  -        which isn't the case if Unix search paths are being used, and seems
  -        to be pretty broken under Windows */
  +        which isn't the case if Unix search paths are being used and is a
  +        bit hit-and-miss under Windows where the contents of argv[0] depend
  +        on how the program is being executed.  To avoid this we perform some
  +        Windows-specific processing to try and find the path to the
  +        executable if we can't otherwise find it */
        do
                {
                namePos = lastPos;
  @@ -896,6 +1040,24 @@
                while( pathPtr != NULL );
                }
   #endif /* __UNIX__ */
  +#ifdef __WIN32__
  +     /* Under Windows we can use GetModuleFileName() to find the location of
  +        the program */
  +     count = GetModuleFileName ( NULL, filePath, _MAX_PATH );
  +     if( count > 0 )
  +             {
  +             char *progNameStart = strrchr( filePath, '\\' );
  +             if( progNameStart != NULL && \
  +                     ( progNameStart - filePath ) < _MAX_PATH - 13 )
  +                     {
  +                     /* Replace the program name with the config file name */
  +                     strcpy( progNameStart + 1, CONFIG_NAME );
  +                     if( testConfigPath( filePath ) )
  +                             return( readConfig( filePath, TRUE ) );
  +                     }
  +             }
  +#endif /*__WIN32__*/
  +
   
        /* Default to just the config name (which should fail as it was the
           first entry in configPaths[]).  readConfig() will display the
  @@ -903,6 +1065,25 @@
        return( readConfig( CONFIG_NAME, TRUE ) );
        }
   
  +/* Free the in-memory config data */
  +
  +static void freeConfig( void )
  +     {
  +     OIDINFO *oidPtr = oidList;
  +
  +     while( oidPtr != NULL )
  +             {
  +             OIDINFO *oidCursor = oidPtr;
  +
  +             oidPtr = oidPtr->next;
  +             if( oidCursor->comment != NULL )
  +                     free( oidCursor->comment );
  +             if( oidCursor->description != NULL )
  +                     free( oidCursor->description );
  +             free( oidCursor );
  +             }
  +     }
  +
   /****************************************************************************
   *                                                                            
                                                                        *
   *                                                    Output/Formatting 
Routines                                              *
  @@ -953,7 +1134,7 @@
        long noBytes = length;
        int zeroPadded = FALSE, warnPadding = FALSE, warnNegative = isInteger;
        int singleLine = FALSE;
  -     int maxLevel = ( doPure ) ? 15 : 8, i;
  +     int maxLevel = ( doPure ) ? 15 : 8, prevCh = -1, i;
   
        /* Check if LHS status info + indent + "OCTET STRING" string + data will
           wrap */
  @@ -973,7 +1154,7 @@
                if( !( i % lineLength ) )
                        {
                        if( singleLine )
  -                             putchar( ' ' );
  +                             fputc( ' ', output );
                        else
                                {
                                if( dumpText )
  @@ -996,15 +1177,22 @@
   
                /* If we need to check for negative values and zero padding, 
check
                   this now */
  -             if( !i )
  +             if( i == 0 )
                        {
  +                     prevCh = ch;
                        if( !ch )
                                zeroPadded = TRUE;
                        if( !( ch & 0x80 ) )
                                warnNegative = FALSE;
                        }
  -             if( i == 1 && zeroPadded && ch < 0x80 )
  -                     warnPadding = TRUE;
  +             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 )
                {
  @@ -1047,6 +1235,135 @@
                }
        }
   
  +/* Convert a binary OID to its string equivalent */
  +
  +static int oidToString( char *textOID, int *textOIDlength,
  +                                             const unsigned char *oid, const 
int oidLength )
  +     {
  +     BYTE uuidBuffer[ 32 ];
  +     long value;
  +     int length, uuidBufPos = 0, uuidBitCount = 0, i;
  +     int validEncoding = TRUE, isUUID = FALSE;
  +
  +     for( i = 0, value = 0; i < oidLength; i++ )
  +             {
  +             const unsigned char data = oid[ i ];
  +             const long valTmp = value << 7;
  +
  +             /* Pick apart the encoding.  We keep going after hitting an 
encoding
  +                error at the start of an arc because the overall length is 
  +                bounded and we may still be able to recover something worth 
  +                printing */
  +             if( value == 0 && data == 0x80 )
  +                     {
  +                     /* Invalid leading zero value, 0x80 & 0x7F == 0 */
  +                     validEncoding = FALSE;
  +                     }
  +             if( isUUID )
  +                     {
  +                     value = 1;      /* Set up dummy value since we're 
bypassing normal read */
  +                     if( uuidBitCount == 0 )
  +                             uuidBuffer[ uuidBufPos ] |= data << 1;
  +                     else
  +                             {
  +                             uuidBuffer[ uuidBufPos++ ] |= data >> ( 8 - 
uuidBitCount );
  +                             if( uuidBitCount < 7 )
  +                                     uuidBuffer[ uuidBufPos ] = data << ( 
uuidBitCount + 1 );
  +                             }
  +                     uuidBitCount++;
  +                     if( uuidBitCount > 7 )
  +                             uuidBitCount = 0;
  +                     if( !( data & 0x80 ) )
  +                             {
  +                             if( uuidBufPos != 16 )
  +                                     {
  +                                     validEncoding = FALSE;
  +                                     break;
  +                                     }
  +                             length += sprintf( textOID + length, 
  +                                                                " { 
%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x }", 
  +                                                                uuidBuffer[ 
0 ], uuidBuffer[ 1 ],
  +                                                                uuidBuffer[ 
2 ], uuidBuffer[ 3 ],
  +                                                                uuidBuffer[ 
4 ], uuidBuffer[ 5 ],
  +                                                                uuidBuffer[ 
6 ], uuidBuffer[ 7 ],
  +                                                                uuidBuffer[ 
8 ], uuidBuffer[ 9 ],
  +                                                                uuidBuffer[ 
10 ], uuidBuffer[ 11 ],
  +                                                                uuidBuffer[ 
12 ], uuidBuffer[ 13 ],
  +                                                                uuidBuffer[ 
14 ], uuidBuffer[ 15 ] );
  +                             value = 0;
  +                             }
  +                     continue;
  +                     }
  +             if( value >= ( LONG_MAX >> 7 ) || \
  +                     valTmp >= LONG_MAX - ( data & 0x7F ) )
  +                     {
  +                     validEncoding = FALSE;
  +                     break;
  +                     }
  +             value = valTmp | ( data & 0x7F );
  +             if( value < 0 || value > LONG_MAX / 2 )
  +                     {
  +                     validEncoding = FALSE;
  +                     break;
  +                     }
  +             if( !( data & 0x80 ) )
  +                     {
  +                     if( i == 0 )
  +                             {
  +                             long x, y;
  +
  +                             /* 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 */
  +                             x = value / 40;
  +                             y = value % 40;
  +                             if( x > 2 )
  +                                     {
  +                                     /* Handle special case for large y if x 
== 2 */
  +                                     y += ( x - 2 ) * 40;
  +                                     x = 2;
  +                                     }
  +                             if( x < 0 || x > 2 || y < 0 || \
  +                                     ( ( x < 2 && y > 39 ) || \
  +                                       ( x == 2 && ( y > 50 && y != 100 ) ) 
) )
  +                                     {
  +                                     /* If x = 0 or 1 then y has to be 
0...39, for x = 3
  +                                        it can take any value but there are 
no known 
  +                                        assigned values over 50 except for 
one contrived
  +                                        example in X.690 which sets y = 100, 
so if we see
  +                                        something outside this range it's 
most likely an 
  +                                        encoding error rather than some 
bizarre new ID 
  +                                        that's just appeared */
  +                                     validEncoding = FALSE;
  +                                     break;
  +                                     }
  +                             length = sprintf( textOID, "%ld %ld", x, y );
  +
  +                             /* An insane ITU facility lets people register 
UUIDs as OIDs
  +                                (see 
http://www.itu.int/ITU-T/asn1/uuid.html), if we find
  +                                one of these, which live under the arc '1 
25' = 0x69 we
  +                                have to continue decoding the OID as a UUID 
instead of a
  +                                standard OID */
  +                             if( data == 0x69 )
  +                                     isUUID = TRUE;
  +                             }
  +                     else
  +                             length += sprintf( textOID + length, " %ld", 
value );
  +                     value = 0;
  +                     }
  +             }
  +     if( value != 0 )
  +             {
  +             /* We stopped in the middle of a continued value */
  +             validEncoding = FALSE;
  +             }
  +     textOID[ length ] = '\0';
  +     *textOIDlength = length;
  +
  +     return( validEncoding );
  +     }
  +
   /* Dump a bitstring, reversing the bits into the standard order in the
      process */
   
  @@ -1082,17 +1399,21 @@
                        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;
  @@ -1205,17 +1526,35 @@
                                   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__ ) || \
  -     ( defined( __UNIX__ ) && !( defined( __MACH__ ) || defined( __OpenBSD__ 
) ) )
  -
  -                                     wprintf( L"%c", wCh );
  +#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 */
  @@ -1245,8 +1584,10 @@
                                                ch = '.';       /* Convert 
non-ASCII to placeholders */
                                        }
                                else
  +                                     {
                                        if( !isprint( ch ) )
                                                ch = '.';       /* Convert 
non-ASCII to placeholders */
  +                                     }
   #ifdef __OS390__
                                ch = asciiToEbcdic( ch );
   #endif /* __OS390__ */
  @@ -1267,8 +1608,10 @@
   
                        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
  @@ -1315,6 +1658,7 @@
                        }
                }
        else
  +             {
                if( doTimeStr )
                        {
                        const char *timeStrPtr = ( strOption == STR_UTCTIME ) ? 
\
  @@ -1333,6 +1677,7 @@
                        }
                else
                        fputc( '\'', output );
  +             }
        fputc( '\n', output );
   
        /* Display any problems we encountered */
  @@ -1417,9 +1762,11 @@
   
                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 )
  @@ -1441,7 +1788,7 @@
   
   /* Check whether a BIT STRING or OCTET STRING encapsulates another object */
   
  -static int checkEncapsulate( FILE *inFile, const int tag, const int length )
  +static int checkEncapsulate( FILE *inFile, const int length )
        {
        ASN1_ITEM nestedItem;
        const int currentPos = fPos;
  @@ -1457,12 +1804,35 @@
        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 )
  +     /* If it's not a standard tag class, don't try and dig down into it */
  +     if( ( nestedItem.id & CLASS_MASK ) != UNIVERSAL && \
  +             ( nestedItem.id & CLASS_MASK ) != CONTEXT )
  +             return( FALSE );
  +
  +     /* If it doesn't fit exactly within the current item it's not an
  +        encapsulated object */
  +     if( nestedItem.length != length - diffPos )
  +             return( FALSE );
  +
  +     /* If it doesn't have a valid-looking tag, don't try and go any further 
*/
  +     if( nestedItem.tag <= 0 || nestedItem.tag > 0x31 )
  +             return( FALSE );
  +
  +     /* Now things get a bit complicated because it's possible to get some
  +        (very rare) false positives, for example if a NUMERICSTRING of
  +        exactly the right length is nested within an OCTET STRING, since
  +        numeric values all look like constructed tags of some kind.  To
  +        handle this we look for nested constructed items that should really
  +        be primitive */
  +     if( ( nestedItem.id & FORM_MASK ) == PRIMITIVE )
  +             return( TRUE );
  +
  +     /* It's constructed, make sure that it's something for which it makes
  +        sense as a constructed object.  At worst this will give some false
  +        negatives for really wierd objects (nested constructed strings inside
  +        OCTET STRINGs), but these should probably never occur anyway */
  +     if( nestedItem.tag == SEQUENCE || \
  +             nestedItem.tag == SET )
                return( TRUE );
   
        return( FALSE );
  @@ -1521,7 +1891,7 @@
   
   /* Check whether the next item looks like text */
   
  -static int checkForText( FILE *inFile, const int length )
  +static STR_OPTION checkForText( FILE *inFile, const int length )
        {
        char buffer[ 16 ];
        int isBMP = FALSE, isUnicode = FALSE;
  @@ -1541,22 +1911,28 @@
                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 ] ) ) )
  +                     {
  +                     const int ch = byteToInt( buffer[ i ] );
  +
  +                     if( !( isalpha( ch ) || isdigit( ch ) || isspace( ch ) 
) )
                                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 ) && \
  +     if( isdigit( byteToInt( 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 ] ) )
  +                     {
  +                     if( !isdigit( byteToInt( buffer[ i ] ) ) )
                                break;
  +                     }
                if( i == length - 1 )
                        return( ( length == 13 ) ? STR_UTCTIME : 
STR_GENERALIZED );
                }
  @@ -1581,20 +1957,24 @@
                                   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
                        {
  @@ -1609,8 +1989,10 @@
                                continue;
                                }
                        else
  +                             {
                                if( isUnicode )
                                        return( STR_NONE );
  +                             }
                        }
                if( buffer[ i ] < 0x20 || buffer[ i ] > 0x7E )
                        return( STR_NONE );
  @@ -1662,7 +2044,8 @@
   
   /* Print a constructed ASN.1 object */
   
  -int printAsn1( FILE *inFile, const int level, long length, const int 
isIndefinite );
  +static int printAsn1( FILE *inFile, const int level, long length,
  +                                       const int isIndefinite );
   
   static void printConstructed( FILE *inFile, int level, const ASN1_ITEM *item 
)
        {
  @@ -1696,9 +2079,8 @@
        {
        OIDINFO *oidInfo;
        STR_OPTION stringType;
  -     char buffer[ MAX_OID_SIZE ];
  +     unsigned char buffer[ MAX_OID_SIZE ];
        long value;
  -     int x, y;
   
        if( ( item->id & CLASS_MASK ) != UNIVERSAL )
                {
  @@ -1714,6 +2096,7 @@
                        {
                        int i;
   
  +                     fflush( stdout );
                        fprintf( stderr, "\nError: Object has bad length field, 
tag = %02X, "
                                         "length = %lX, value =", item->tag, 
item->length );
                        fprintf( stderr, "<%02X", *item->header );
  @@ -1761,6 +2144,7 @@
                {
                int i;
   
  +             fflush( stdout );
                fprintf( stderr, "\nError: Object has bad length field, tag = 
%02X, "
                                 "length = %lX, value =", item->tag, 
item->length );
                fprintf( stderr, "<%02X", *item->header );
  @@ -1787,12 +2171,16 @@
        switch( item->tag )
                {
                case BOOLEAN:
  -                     x = getc( inFile );
  -                     fprintf( output, " %s\n", x ? "TRUE" : "FALSE" );
  -                     if( x != 0 && x != 0xFF )
  +                     {
  +                     int ch;
  +
  +                     ch = getc( inFile );
  +                     fprintf( output, " %s\n", ch ? "TRUE" : "FALSE" );
  +                     if( ch != 0 && ch != 0xFF )
                                complain( "BOOLEAN has non-DER encoding", level 
);
                        fPos++;
                        break;
  +                     }
   
                case INTEGER:
                case ENUMERATED:
  @@ -1808,11 +2196,14 @@
                        break;
   
                case BITSTRING:
  -                     if( ( x = getc( inFile ) ) != 0 )
  +                     {
  +                     int ch;
  +
  +                     if( ( ch = getc( inFile ) ) != 0 )
                                fprintf( output, " %d unused bit%s",
  -                                              x, ( x != 1 ) ? "s" : "" );
  +                                              ch, ( ch != 1 ) ? "s" : "" );
                        fPos++;
  -                     if( !--item->length && !x )
  +                     if( !--item->length && !ch )
                                {
                                fputc( '\n', output );
                                complain( "Object has zero length", level );
  @@ -1822,13 +2213,14 @@
                                {
                                /* It's short enough to be a bit flag, dump it 
as a sequence
                                   of bits */
  -                             dumpBitString( inFile, ( int ) item->length, x, 
level );
  +                             dumpBitString( inFile, ( int ) item->length, 
ch, level );
                                break;
                                }
                        /* Drop through to dump it as an octet string */
  +                     }
   
                case OCTETSTRING:
  -                     if( checkEncapsulate( inFile, item->tag, item->length ) 
)
  +                     if( checkEncapsulate( inFile, item->length ) )
                                {
                                /* It's something encapsulated inside the 
string, print it as
                                   a constructed item */
  @@ -1854,12 +2246,14 @@
                        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 */
  +                     {
  +                     char textOID[ 128 ];
  +                     int length, isValid;
  +
  +                     /* Hierarchical Object Identifier */
                        if( item->length > MAX_OID_SIZE )
                                {
  +                             fflush( stdout );
                                fprintf( stderr, "\nError: Object identifier 
length %ld too "
                                                 "large.\n", item->length );
                                exit( EXIT_FAILURE );
  @@ -1868,10 +2262,14 @@
                        fPos += item->length;
                        if( ( oidInfo = getOIDinfo( buffer, ( int ) 
item->length ) ) != NULL )
                                {
  +                             /* Convert the binary OID to text form */
  +                             isValid = oidToString( textOID, &length, buffer,
  +                                                                        ( 
int ) item->length );
  +
                                /* Check if LHS status info + indent + "OID " 
string + oid
  -                                name will wrap */
  +                                name + "(" + oid value + ")" will wrap */
                                if( ( ( doPure ) ? 0 : INDENT_SIZE ) + ( level 
* 2 ) + 18 + \
  -                                     strlen( oidInfo->description ) >= 
outputWidth )
  +                                     strlen( oidInfo->description ) + 2 + 
length >= outputWidth )
                                        {
                                        fputc( '\n', output );
                                        if( !doPure )
  @@ -1880,7 +2278,7 @@
                                        }
                                else
                                        fputc( ' ', output );
  -                             fprintf( output, "%s\n", oidInfo->description );
  +                             fprintf( output, "%s (%s)\n", 
oidInfo->description, textOID );
   
                                /* Display extra comments about the OID if 
required */
                                if( extraOIDinfo && oidInfo->comment != NULL )
  @@ -1890,6 +2288,8 @@
                                        doIndent( level + 1 );
                                        fprintf( output, "(%s)\n", 
oidInfo->comment );
                                        }
  +                             if( !isValid )
  +                                     complain( "OID has invalid encoding", 
level );
   
                                /* If there's a warning associated with this 
OID, remember
                                   that there was a problem */
  @@ -1899,28 +2299,13 @@
                                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" );
  +                     /* Print the OID as a text string */
  +                     isValid = oidToString( textOID, &length, buffer, ( int 
) item->length );
  +                     fprintf( output, " '%s'\n", textOID );
  +                     if( !isValid )
  +                             complain( "OID has invalid encoding", level );
                        break;
  +                     }
   
                case EOC:
                case NULLTAG:
  @@ -1969,8 +2354,8 @@
   
   /* Print a complex ASN.1 object */
   
  -int printAsn1( FILE *inFile, const int level, long length,
  -                        const int isIndefinite )
  +static int printAsn1( FILE *inFile, const int level, long length,
  +                                       const int isIndefinite )
        {
        ASN1_ITEM item;
        long lastPos = fPos;
  @@ -2024,18 +2409,22 @@
                                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
                        }
   
  @@ -2059,6 +2448,7 @@
                                return( 0 );
                        }
                else
  +                     {
                        if( length <= 0 )
                                {
                                if( length < 0 )
  @@ -2066,6 +2456,7 @@
                                return( 0 );
                                }
                        else
  +                             {
                                if( length == 1 )
                                        {
                                        const int ch = fgetc( inFile );
  @@ -2085,11 +2476,14 @@
                                                return( 1 );
                                                }
                                        }
  +                             }
  +                     }
                }
        if( status == -1 )
                {
                int i;
   
  +             fflush( stdout );
                fprintf( stderr, "\nError: Invalid data encountered at position 
"
                                 "%d:", fPos );
                for( i = 0; i < item.headerSize; i++ )
  @@ -2114,7 +2508,7 @@
   static void usageExit( void )
        {
        puts( "DumpASN1 - ASN.1 object dump/syntax check program." );
  -     puts( "Copyright Peter Gutmann 1997 - 2006.  Last updated " 
UPDATE_STRING "." );
  +     puts( "Copyright Peter Gutmann 1997 - 2010.  Last updated " 
UPDATE_STRING "." );
        puts( "" );
   
        puts( "Usage: dumpasn1 [-acdefhlprstuxz] <file>" );
  @@ -2195,12 +2589,12 @@
                        useStdin = TRUE;
                while( *argPtr )
                        {
  -                     if( isdigit( *argPtr ) )
  +                     if( isdigit( byteToInt( *argPtr ) ) )
                                {
                                offset = atol( argPtr );
                                break;
                                }
  -                     switch( toupper( *argPtr ) )
  +                     switch( toupper( byteToInt( *argPtr ) ) )
                                {
                                case '-':
                                        moreArgs = FALSE;       /* GNU-style 
end-of-args flag */
  @@ -2336,11 +2730,14 @@
        if( useStdin )
                inFile = stdin;
        else
  +             {
                if( ( inFile = fopen( argv[ 0 ], "rb" ) ) == NULL )
                        {
                        perror( argv[ 0 ] );
  +                     freeConfig();
                        exit( EXIT_FAILURE );
                        }
  +             }
        if( useStdin )
                {
                while( offset-- )
  @@ -2360,16 +2757,19 @@
                if( status == -1 )
                        {
                        puts( "Non-ASN.1 data encountered." );
  +                     freeConfig();
                        exit( EXIT_FAILURE );
                        }
                if( status == 0 )
                        {
                        puts( "Nothing to read." );
  +                     freeConfig();
                        exit( EXIT_FAILURE );
                        }
                if( item.indefinite )
                        {
                        puts( "Cannot process indefinite-length item." );
  +                     freeConfig();
                        exit( EXIT_FAILURE );
                        }
   
  @@ -2406,10 +2806,12 @@
                        }
                }
        fclose( inFile );
  +     freeConfig();
   
        /* Print a summary of warnings/errors if it's required or appropriate */
        if( !doPure )
                {
  +             fflush( stdout );
                if( !doCheckOnly )
                        fputc( '\n', stderr );
                fprintf( stderr, "%d warning%s, %d error%s.\n", noWarnings,
  @@ .
______________________________________________________________________
RPM Package Manager                                    http://rpm5.org
CVS Sources Repository                                [email protected]

Reply via email to