home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / crypl200.zip / KEYMGMT / DUMPASN1.C < prev    next >
Text File  |  1996-10-10  |  14KB  |  522 lines

  1. /* ASN.1/cryptlib object dumping code, based on ASN.1 dump program by dpk */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6.  
  7. /* Tag classes */
  8.  
  9. #define CLASS_MASK        0xC0    /* Bits 8 and 7 */
  10. #define UNIVERSAL        0x00    /* 0 = Universal (defined by ITU X.680) */
  11. #define APPLICATION        0x40    /* 1 = Application */
  12. #define CONTEXT            0x80    /* 2 = Context-specific */
  13. #define PRIVATE            0xC0    /* 3 = Private */
  14.  
  15. /* Encoding type */
  16.  
  17. #define FORM_MASK        0x20    /* Bit 6 */
  18. #define PRIMITIVE        0x00    /* 0 = primitive */
  19. #define CONSTRUCTED        0x20    /* 1 = constructed */
  20.  
  21. /* Universal tags */
  22.  
  23. #define TAG_MASK        0x1F    /* Bits 5 - 1 */
  24. #define BOOLEAN            0x01    /*  1: TRUE or FALSE */
  25. #define INTEGER            0x02    /*  2: Arbitrary precision integer */
  26. #define BITSTRING        0x03    /*  2: Sequence of bits */
  27. #define OCTETSTRING        0x04    /*  4: Sequence of bytes */
  28. #define NULLTAG            0x05    /*  5: NULL */
  29. #define OID                0x06    /*  6: Object Identifier (numeric sequence) */
  30. #define OBJDESCRIPTOR    0x07    /*  7: Object Descriptor (human readable) */
  31. #define EXTERNAL        0x08    /*  8: External / Instance Of */
  32. #define REAL            0x09    /*  9: Real (Mantissa * Base^Exponent) */
  33. #define ENUMERATED        0x0A    /* 10: Enumerated */
  34. #define EMBEDDED_PDV    0x0B    /* 11: Embedded Presentation Data Value */
  35. #define SEQUENCE        0x10    /* 16: Constructed Sequence / Sequence Of */
  36. #define SET                0x11    /* 17: Constructed Set / Set Of */
  37. #define NUMERICSTR        0x12    /* 18: Numeric String (digits only) */
  38. #define PRINTABLESTR    0x13    /* 19: Printable String */
  39. #define T61STR            0x14    /* 20: T61 String (Teletex) */
  40. #define VIDEOTEXSTR        0x15    /* 21: Videotex String */
  41. #define IA5STR            0x16    /* 22: IA5 String */
  42. #define UTCTIME            0x17    /* 23: UTC Time */
  43. #define GENERALIZEDTIME    0x18    /* 24: Generalized Time */
  44. #define GRAPHICSTR        0x19    /* 25: Graphic String */
  45. #define VISIBLESTR        0x1A    /* 26: Visible String (ISO 646) */
  46. #define GENERALSTR        0x1B    /* 27: General String */
  47. #define UNIVERSALSTR    0x1C    /* 28: Universal String */
  48. #define BMPSTR            0x1E    /* 30: Basic Multilingual Plane String */
  49.  
  50. /* Length encoding */
  51.  
  52. #define LEN_XTND  0x80        /* Indefinite or long form */
  53. #define LEN_MASK  0x7f        /* Bits 7 - 1 */
  54.  
  55. /* Structure to hold info on an ASN.1 item */
  56.  
  57. struct Item {
  58.     int id;                        /* Identifier/tag */
  59.     long len;                    /* Data length */
  60.     };
  61.  
  62. /* Return descriptive strings for universal tags */
  63.  
  64. char *idstr( int tagID )
  65.     {
  66.     switch( tagID & TAG_MASK )
  67.         {
  68.         case BOOLEAN:
  69.             return( "BOOLEAN" );
  70.         case INTEGER:
  71.             return( "INTEGER" );
  72.         case BITSTRING:
  73.             return( "BIT STRING" );
  74.         case OCTETSTRING:
  75.             return( "OCTET STRING" );
  76.         case NULLTAG:
  77.             return( "NULL" );
  78.         case OID:
  79.             return( "OBJECT IDENTIFIER" );
  80.         case OBJDESCRIPTOR:
  81.             return( "ObjectDescriptor" );
  82.         case EXTERNAL:
  83.             return( "EXTERNAL" );
  84.         case REAL:
  85.             return( "REAL" );
  86.         case ENUMERATED:
  87.             return( "ENUMERATED" );
  88.         case EMBEDDED_PDV:
  89.             return( "EMBEDDED PDV (1993)" );
  90.         case SEQUENCE:
  91.             return( "SEQUENCE" );
  92.         case SET:
  93.             return( "SET" );
  94.         case NUMERICSTR:
  95.             return( "NumericString" );
  96.         case PRINTABLESTR:
  97.             return( "PrintableString" );
  98.         case T61STR:
  99.             return( "TeletexString" );
  100.         case VIDEOTEXSTR:
  101.             return( "VideotexString" );
  102.         case IA5STR:
  103.             return( "IA5String" );
  104.         case UTCTIME:
  105.             return( "UTCTime" );
  106.         case GENERALIZEDTIME:
  107.             return( "GeneralizedTime" );
  108.         case GRAPHICSTR:
  109.             return( "GraphicString" );
  110.         case VISIBLESTR:
  111.             return( "VisibleString" );
  112.         case GENERALSTR:
  113.             return( "GeneralString" );
  114.         case UNIVERSALSTR:
  115.             return( "UniversalString (1993)" );
  116.         case BMPSTR:
  117.             return( "BMPString (1993)" );
  118.         default:
  119.             return( "Unknown (Reserved)" );
  120.         }
  121.     }
  122.  
  123. /* Return descriptive strings for cryptlib objects and algorithms */
  124.  
  125. static char stringBuffer[ 100 ];
  126.  
  127. static char *objectStr( int objectID )
  128.     {
  129.     char *objectName[] = { "TagEncryptedKey", "TagPKCEncryptedKey",
  130.                            "TagSignature", "TagEncryptedData",
  131.                            "TagCompressedData", "TagSignedData",
  132.                            "TagRawData", "TagNonData" };
  133.  
  134.     if( objectID < 8 )
  135.         {
  136.         sprintf( stringBuffer, "%s(%d)", objectName[ objectID ], objectID );
  137.         return( stringBuffer );
  138.         }
  139.     sprintf( stringBuffer, "Unknown(%d)", objectID );
  140.     return( stringBuffer );
  141.     }
  142.  
  143. static char *enumAlgo( int value )
  144.     {
  145.     struct { int value; char *name; } enumInfo[] = {
  146.         { 0, "CRYPT_ALGO_NONE" }, { 1, "CRYPT_ALGO_DES" },
  147.         { 2, "CRYPT_ALGO_3DES" }, { 3, "CRYPT_ALGO_IDEA" },
  148.         { 4, "CRYPT_ALGO_MDCSHS" },{ 5, "CRYPT_ALGO_RC2" },
  149.         { 6, "CRYPT_ALGO_RC4" }, { 7, "CRYPT_ALGO_RC5" },
  150.         { 8, "CRYPT_ALGO_SAFER" }, { 9, "CRYPT_ALGO_BLOWFISH" },
  151.         { 10, "CRYPT_ALGO_GOST" }, { 11, "CRYPT_ALGO_SKIPJACK" },
  152.         { 100, "CRYPT_ALGO_DH" },  { 101, "CRYPT_ALGO_RSA" },
  153.         { 102, "CRYPT_ALGO_DSS" }, { 200, "CRYPT_ALGO_MD2" },
  154.         { 201, "CRYPT_ALGO_MD4" }, { 202, "CRYPT_ALGO_MD5" },
  155.         { 204, "CRYPT_ALGO_SHA" }, { 204, "CRYPT_ALGO_RIPEMD160" },
  156.         { -1, NULL }
  157.         };
  158.     int i;
  159.  
  160.     for( i = 0; enumInfo[ i ].value != -1; i++ )
  161.         if( enumInfo[ i ].value == value )
  162.             {
  163.             sprintf( stringBuffer, "%s (%d)", enumInfo[ i ].name, value );
  164.             return( stringBuffer );
  165.             }
  166.     sprintf( stringBuffer, "CRYPT_ALGO_UNKNOWN (%d)", value );
  167.     return( stringBuffer );
  168.     }
  169.  
  170. static char *enumMode( int value )
  171.     {
  172.     struct { int value; char *name; } enumInfo[] = {
  173.         { 0, "CRYPT_MODE_NONE" }, { 1, "CRYPT_MODE_STREAM" },
  174.         { 2, "CRYPT_MODE_ECB" }, { 3, "CRYPT_MODE_CBC" },
  175.         { 4, "CRYPT_MODE_CFB" }, { 5, "CRYPT_MODE_OFB" },
  176.         { 6, "CRYPT_MODE_PCBC" }, { 7, "CRYPT_MODE_COUNTER" },
  177.         { 100, "CRYPT_MODE_PKC" },
  178.         { -1, NULL }
  179.         };
  180.     int i;
  181.  
  182.     for( i = 0; enumInfo[ i ].value != -1; i++ )
  183.         if( enumInfo[ i ].value == value )
  184.             {
  185.             sprintf( stringBuffer, "%s (%d)", enumInfo[ i ].name, value );
  186.             return( stringBuffer );
  187.             }
  188.     sprintf( stringBuffer, "CRYPT_MODE_UNKNOWN (%d)", value );
  189.     return( stringBuffer );
  190.     }
  191.  
  192. /* Return descriptive strings for an object identifier */
  193.  
  194. static char *oidStr( char *oid, int oidLength )
  195.     {
  196.     struct { char *oid; char *string; } oidInfo[] = {
  197.         { "\x06\x08\x2A\x86\x48\x86\xF7\x0D\x01\x01", "pkcs-1 (1 2 840 113549 1 1)" },
  198.         { "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", "rsaEncryption (1 2 840 113549 1 1 1)" },
  199.         { "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02", "md2withRSAEncryption (1 2 840 113549 1 1 2)" },
  200.         { "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04", "md5withRSAEncryption (1 2 840 113549 1 1 4)" },
  201.         { "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05", "sha1withRSAEncryption (1 2 840 113549 1 1 5)" },
  202.         { "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x03\x01", "dhKeyAgreement (1 2 840 113549 1 3 1)" },
  203.         { "\x06\x08\x2A\x86\x48\x86\xF7\x0D\x03\x04", "rc4 (1 2 840 113549 3 4)" },
  204.         { "\x06\x05\x2B\x0E\x03\x02\x0C", "dsaEncryption (1 3 14 3 2 12)" },
  205.         { "\x06\x05\x2B\x0E\x03\x02\x0D", "dsaWithSHA (1 3 14 3 2 13)" },
  206.         { "\x06\x03\x55\x04\x03", "commonName (2 5 4 3)" },
  207.         { "\x06\x03\x55\x04\x06", "countryName (2 5 4 6)" },
  208.         { "\x06\x03\x55\x04\x07", "localityName (2 5 4 7)" },
  209.         { "\x06\x03\x55\x04\x08", "stateOrProvinceName (2 5 4 8)" },
  210.         { "\x06\x03\x55\x04\x0A", "organizationName (2 5 4 10)" },
  211.         { "\x06\x03\x55\x04\x0B", "organizationalUnitName (2 5 4 11)" },
  212.         { NULL, NULL }
  213.         };
  214.     int i = 0;
  215.  
  216.     memset( oid + oidLength, 0, 2 );
  217.     while( oidInfo[ i ].oid != NULL )
  218.         {
  219.         if( !memcmp( oidInfo[ i ].oid + 2, oid, oidLength ) )
  220.             return( oidInfo[ i ].string );
  221.         i++;
  222.         }
  223.  
  224.     return( NULL );
  225.     }
  226.  
  227. /* Indent a string by the appropriate amount */
  228.  
  229. static void doIndent( int level )
  230.     {
  231.     int i;
  232.  
  233.     for( i = 0; i < level; i++ )
  234.         printf( "  " );
  235.     }
  236.  
  237. /* Dump data as a string of hex digits up to a maximum of 128 bytes */
  238.  
  239. static void dumpHex( FILE *inFile, long length, int level )
  240.     {
  241.     long noBytes = length;
  242.     int i;
  243.  
  244.     if( noBytes > 128 )
  245.         noBytes = 128;    /* Only output a maximum of 128 bytes */
  246.     if( level > 8 )
  247.         level = 8;        /* Make sure we don't go off the edge of the screen */
  248.     for( i = 0; i < noBytes; i++ )
  249.         {
  250.         if( !( i % 16 ) )
  251.             {
  252.             printf( "\n\t    : " );
  253.             doIndent( level + 1 );
  254.             }
  255.         printf( "%s%02X", i % 16 ? " " : "", getc( inFile ) );
  256.         }
  257.     if( length > 128 )
  258.         {
  259.         length -= 128;
  260.         printf( "\n\t    : " );
  261.         doIndent( level + 5 );
  262.         printf( "[ Another %ld bytes skipped ]", length );
  263.         fseek( inFile, length, SEEK_CUR );
  264.         }
  265.  
  266.     printf( "\n" );
  267.     }
  268.  
  269. /* Get an integer value */
  270.  
  271. static long getValue( FILE *inFile, long length )
  272.     {
  273.     long value = 0;
  274.     int i;
  275.  
  276.     for( i = 0; i < length; i++ )
  277.         value = ( value << 8 ) | getc( inFile );
  278.     return( value );
  279.     }
  280.  
  281. /* Get an ASN.1 objects tag and length */
  282.  
  283. struct Item *getItem( FILE *inFile )
  284.     {
  285.     static struct Item object;
  286.     long length;
  287.  
  288.     object.id = fgetc( inFile );
  289.     if( feof( inFile ) )
  290.         return( NULL );
  291.     if( ( length = getc( inFile ) ) & LEN_XTND )
  292.         {
  293.         int i;
  294.  
  295.         length &= LEN_MASK;
  296.         if( !length )
  297.             {
  298.             puts( "\nError: Indefinite-length encoded data found.\n" );
  299.             exit( EXIT_FAILURE );
  300.             }
  301.         if( length > 4 )
  302.             {
  303.             printf( "\nError: Object length field %d too large.\n", length );
  304.             exit( EXIT_FAILURE );
  305.             }
  306.         object.len = 0;
  307.         for( i = 0; i < length; i++ )
  308.             object.len = ( object.len << 8 ) | getc( inFile );
  309.         }
  310.     else
  311.         object.len = length;
  312.  
  313.     return( &object );
  314.     }
  315.  
  316. /* Print an ASN.1 object */
  317.  
  318. void printAsn1( FILE *inFile, int level, long length )
  319.     {
  320.     struct Item *item;
  321.     long lastPos = ftell( inFile );
  322.     int seenEnum = 0;
  323.  
  324.     while( ( item = getItem( inFile ) ) != NULL )
  325.         {
  326.         long value;
  327.         int i;
  328.  
  329.         /* Decrement the enum level */
  330.         if( seenEnum )
  331.             seenEnum--;
  332.  
  333.         /* Print offset into buffer, tag, length, and offset of next item */
  334.         printf( "%4ld %2X %4d: ", lastPos, item->id, item->len );
  335.         doIndent( level );
  336.  
  337.         if( ( item->id & CLASS_MASK ) == UNIVERSAL )
  338.             {
  339.             /* Print the object type */
  340.             printf( "%s", idstr( item->id ) );
  341.  
  342.             /* Perform a sanity check */
  343.             if( ( ( item->id & TAG_MASK ) != NULLTAG ) && ( item->len < 1 ) )
  344.                 {
  345.                 puts( "\nError: Object has bad length field." );
  346.                 exit( EXIT_FAILURE );
  347.                 }
  348.  
  349.             if( ( item->id & FORM_MASK ) == CONSTRUCTED )
  350.                 {
  351.                 puts( " {" );
  352.                 printAsn1( inFile, level + 1, item->len );
  353.                 printf( "\t    :   " );
  354.                 doIndent( level );
  355.                 puts( "}" );
  356.                 }
  357.             else
  358.                 {
  359.                 char string[ 150 ], *oidName;
  360.  
  361.                 switch( item->id & TAG_MASK )
  362.                     {
  363.                     case BOOLEAN:
  364.                         printf(" %s\n", getc( inFile ) ? "TRUE" : "FALSE" );
  365.                         break;
  366.  
  367.                     case INTEGER:
  368.                         if( item->len > 4 )
  369.                             dumpHex( inFile, item->len, level );
  370.                         else
  371.                             printf( " %ld\n", getValue( inFile, item->len ) );
  372.                         break;
  373.  
  374.                     case ENUMERATED:
  375.                         if( !seenEnum )
  376.                             {
  377.                             printf( " %s\n", enumAlgo( ( int ) \
  378.                                         getValue( inFile, item->len ) ) );
  379.                             seenEnum = 2;
  380.                             }
  381.                         else
  382.                             printf( " %s\n", enumMode( ( int ) \
  383.                                         getValue( inFile, item->len ) ) );
  384.                         break;
  385.  
  386.                     case BITSTRING:
  387.                         printf( " %d unused bits", getc( inFile ) );
  388.                         item->len -= 1;
  389.                     case OCTETSTRING:
  390.                         dumpHex( inFile, item->len, level );
  391.                         break;
  392.  
  393.                     case OID:
  394.                         /* Heirarchical Object Identifier: First two
  395.                            levels are encoded into one byte, since the
  396.                            root level has only 3 nodes (40*x + y) */
  397.                         fread( string, 1, ( size_t ) item->len, inFile );
  398.                         if( ( oidName = oidStr( string, ( int ) item->len ) ) != NULL )
  399.                             {
  400.                             if( 14 + ( level * 2 ) + 17 + strlen( oidName ) >= 80 )
  401.                                 {
  402.                                 printf( "\n\t    :" );
  403.                                 doIndent( level + 1 );
  404.                                 }
  405.                             printf( " %s\n", oidName );
  406.                             break;
  407.                             }
  408.  
  409.                         printf( " '%d %d", string[ 0 ] / 40,
  410.                                 string[ 0 ] % 40 );
  411.                         value = 0;
  412.                         for( i = 1; i < item->len; i++ )
  413.                             {
  414.                             value = ( value << 7 ) | ( string[ i ] & 0x7F );
  415.                             if( !( string[ i ] & 0x80 ) )
  416.                                 {
  417.                                 printf( " %ld", value );
  418.                                 value = 0;
  419.                                 }
  420.                             }
  421.                         printf( "'\n" );
  422.                         break;
  423.  
  424.                     case NULLTAG:
  425.                         putchar( '\n' );
  426.                         break;
  427.  
  428.                     case OBJDESCRIPTOR:
  429.                     case PRINTABLESTR:
  430.                     case UTCTIME:
  431.                     case GENERALIZEDTIME:
  432.                     case GRAPHICSTR:
  433.                     case VISIBLESTR:
  434.                     case GENERALSTR:
  435.                     case UNIVERSALSTR:
  436.                     case NUMERICSTR:
  437.                     case T61STR:
  438.                     case VIDEOTEXSTR:
  439.                     case IA5STR:
  440.                     case BMPSTR:
  441.                         fread( string, 1, ( size_t ) item->len, inFile );
  442.                         string[ ( int ) item->len ] = '\0';
  443.                         printf( " '%s'\n", string );
  444.                         break;
  445.  
  446.                     default:
  447.                         printf( "Unrecognised primitive, hex value is:\n ");
  448.                         dumpHex( inFile, item->len, level );
  449.                         break;
  450.                     }
  451.                 }
  452.             }
  453.         else
  454.             {
  455.             /* Print the object type */
  456.             if( ( item->id & CLASS_MASK ) == APPLICATION )
  457.                     printf( "[APPLICATION %s]",
  458.                             objectStr( item->id & TAG_MASK ) );
  459.             else
  460.                 {
  461.                 switch( item->id & CLASS_MASK )
  462.                     {
  463.                     case CONTEXT:
  464.                         printf( "[CONTEXT-SPECIFIC" );
  465.                         break;
  466.  
  467.                     case PRIVATE:
  468.                         printf( "[PRIVATE" );
  469.                     }
  470.                 printf( " %d]", item->id & TAG_MASK );
  471.                 }
  472.  
  473.             /* Perform a sanity check */
  474.             if( ( ( item->id & TAG_MASK ) != NULLTAG ) && ( item->len < 1 ) )
  475.                 {
  476.                 puts( "\nError: Object has bad length." );
  477.                 exit( EXIT_FAILURE );
  478.                 }
  479.  
  480.             /* If it's constructed, print the various fields in it */
  481.             if( ( item->id & FORM_MASK ) == CONSTRUCTED )
  482.                 {
  483.                 puts( " {" );
  484.                 printAsn1( inFile, level + 1, item->len );
  485.                 printf( "\t    :   " );
  486.                 doIndent( level );
  487.                 puts( "}" );
  488.                 }
  489.             else
  490.                 /* This could be anything, dump it as hex data */
  491.                 dumpHex( inFile, item->len, level );
  492.             }
  493.  
  494.  
  495.         length -= ( int )( ftell( inFile ) - lastPos );
  496.         lastPos = ftell( inFile );
  497.         if( length <= 0 )
  498.             return;
  499.         }
  500.     }
  501.  
  502. int main( int argc, char *argv[] )
  503.     {
  504.     FILE *inFile;
  505.  
  506.     /* Check args and open the input file */
  507.     if( argc != 2 )
  508.         {
  509.         puts( "Usage: dumpasn1 <file>" );
  510.         exit( EXIT_FAILURE );
  511.         }
  512.     if( ( inFile = fopen( argv[ 1 ], "rb" ) ) == NULL )
  513.         {
  514.         perror( argv[ 1 ] );
  515.         exit( EXIT_FAILURE );
  516.         }
  517.     printAsn1( inFile, 0, 50000L );
  518.     fclose( inFile );
  519.  
  520.     return( EXIT_SUCCESS );
  521.     }
  522.