Subversion Repositories oidconverter

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*###################################################################
  2. ###                                                               ###
  3. ### Object ID converter. Matthias Gaertner, 06/1999               ###
  4. ### Converted to plain 'C' 07/2001                                ###
  5. ### Enhanced version by Daniel Marschall, ViaThinkSoft 06/2011    ###
  6. ### -- NEW: 2.48 can also be encoded!                             ###
  7. ### -- NEW: UUIDs (128-bit) are now supported! (requires GMPLib)  ###
  8. ###                                                               ###
  9. ### To compile with gcc simply use:                               ###
  10. ###   gcc -O2 -o oid oid.c -lgmp -lm                              ###
  11. ###                                                               ###
  12. ### To compile using cl, use:                                     ###
  13. ###   cl -DWIN32 -O1 oid.c (??? unknown: gmp library)             ###
  14. ###                                                               ###
  15. ### Freeware - do with it whatever you want.                      ###
  16. ### Use at your own risk. No warranty of any kind.                ###
  17. ###                                                               ###
  18. ###################################################################*/
  19. /* $Version: 1.2$ */
  20.  
  21. // PROBLEMS:
  22. // - A wrong error message is shown when trying to encode "-0.0" or "x"
  23. // - OIDs with length > 7F are not parsed... (80 95)
  24.  
  25. // NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
  26. // - Remove command line limitation (to allow unlimited long OIDs)
  27. // - The length of the OID could also be GMP and not long, to make real infinite long OIDs.
  28.  
  29. // NICE TO HAVE:
  30. // - makefile / linuxpackage
  31. // - better make functions instead of putting everything in main() with fprintf...
  32.  
  33. // -------------------------------------------------------
  34.  
  35. // Allows OIDs which are bigger than "long"
  36. // Compile with "gcc oid.c -lgmp -lm"
  37. #define is_gmp
  38.  
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include <stdlib.h>
  42.  
  43. #ifdef is_gmp
  44. #include <gmp.h>
  45. #endif
  46.  
  47. #include <stdbool.h>
  48.  
  49. #ifndef __STRNICMP_LOCAL
  50. #ifdef WIN32
  51. #define __STRNICMP_LOCAL strnicmp
  52. #else
  53. #define __STRNICMP_LOCAL strncasecmp
  54. #endif
  55. #endif
  56.  
  57. char                    abCommandLine[1024];
  58. unsigned char   abBinary[128];
  59. unsigned int    nBinary = 0;
  60.  
  61.  
  62. #ifdef is_gmp
  63. static void MakeBase128( mpz_t l, int first )
  64. {
  65.         if ( mpz_cmp_si(l, 127) > 0 ) {
  66.                 mpz_t l2;
  67.                 mpz_init(l2);
  68.                 mpz_div_ui(l2, l, 128);
  69.                 MakeBase128( l2 , 0 );
  70.         }
  71.         mpz_mod_ui(l, l, 128);
  72.         if ( first ) {
  73.                 abBinary[nBinary++] = mpz_get_ui(l);
  74.         } else {
  75.                 abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
  76.         }
  77. }
  78. #else
  79. static void MakeBase128( unsigned long l, int first )
  80. {
  81.         if ( l > 127 ) {
  82.                 MakeBase128( l / 128, 0 );
  83.         }
  84.         l %= 128;
  85.         if ( first ) {
  86.                 abBinary[nBinary++] = (unsigned char)l;
  87.         } else {
  88.                 abBinary[nBinary++] = 0x80 | (unsigned char)l;
  89.         }
  90. }
  91. #endif
  92.  
  93. int main( int argc, char **argv ) {
  94.         char *fOutName = NULL;
  95.         char *fInName = NULL;
  96.         FILE *fOut = NULL;
  97.  
  98.         int n = 1;
  99.         int nMode = 0;  /* dotted->hex */
  100.         int nCHex = 0;
  101.         int nAfterOption = 0;
  102.  
  103.         if ( argc == 1 ) {
  104.                 fprintf( stderr,
  105.                 "OID encoder/decoder 1.2 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
  106.                 #ifdef is_gmp
  107.                 "GMP Edition\n"
  108.                 #endif
  109.                 "\nUsage:\n"
  110.                 " OID [-C] [-o<outfile>] {-i<infile>|1.2.3.4}\n"
  111.                 "   converts dotted form to ASCII HEX DER output.\n"
  112.                 " OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
  113.                 "   decodes ASCII HEX DER and gives dotted form.\n" );
  114.                 return 1;
  115.         }
  116.  
  117.         while ( n < argc ) {
  118.                 if ( !nAfterOption && argv[n][0] == '-' ) {
  119.                         if ( argv[n][1] == 'x' ) {
  120.                                 nMode = 1;      /* hex->dotted */
  121.                                 if ( argv[n][2] != '\0' ) {
  122.                                         argv[n--] += 2;
  123.                                         nAfterOption = 1;
  124.                                 }
  125.                         } else if ( argv[n][1] == 'C' ) {
  126.                                 nMode = 0;
  127.                                 nCHex = 1;
  128.  
  129.                                 if ( argv[n][2] != '\0' ) {
  130.                                         argv[n--] += 2;
  131.                                         nAfterOption = 1;
  132.                                 }
  133.                         } else if ( argv[n][1] == 'o' ) {
  134.                                 if ( argv[n][2] != '\0' ) {
  135.                                         fOutName = &argv[n][2];
  136.                                 } else if ( n < argc-1 ) {
  137.                                         fOutName = argv[++n];
  138.                                 } else {
  139.                                         fprintf(stderr,"Incomplete command line.\n");
  140.                                 }
  141.                         } else if ( argv[n][1] == 'i' ) {
  142.                                 if ( argv[n][2] != '\0' ) {
  143.                                         fInName = &argv[n][2];
  144.                                 } else if ( n < argc-1 ) {
  145.                                         fInName = argv[++n];
  146.                                 } else {
  147.                                         fprintf(stderr,"Incomplete command line.\n");
  148.                                 }
  149.                         }
  150.                 } else {
  151.                         if ( fInName != NULL ) {
  152.                                 break;
  153.                         }
  154.  
  155.                         nAfterOption = 1;
  156.                         if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
  157.                                 fprintf(stderr,"Command line too long.\n");
  158.                                 return 2;
  159.                         }
  160.                         strcat( abCommandLine, argv[n] );
  161.                         if ( n != argc - 1 && nMode != 1 ) {
  162.                                 strcat( abCommandLine, "." );
  163.                         }
  164.                 }
  165.                 n++;
  166.         }
  167.  
  168.         if ( fInName != NULL && nMode == 1 ) {
  169.                 FILE *fIn = fopen( fInName, "rb" );
  170.                 size_t nRead = 0;
  171.                 if ( fIn == NULL ) {
  172.                         fprintf(stderr,"Unable to open input file %s.\n", fInName );
  173.                         return 11;
  174.                 }
  175.                 nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
  176.                 abCommandLine[nRead] = '\0';
  177.                 fclose( fIn );
  178.         } else if ( fInName != NULL && nMode == 0 ) {
  179.                 FILE *fIn = fopen( fInName, "rt" );
  180.                 if ( fIn == NULL ) {
  181.                         fprintf(stderr,"Unable to open input file %s.\n", fInName );
  182.                         return 11;
  183.                 }
  184.                 fgets( abCommandLine, sizeof(abCommandLine), fIn );
  185.                 fclose( fIn );
  186.         }
  187.  
  188.         while ( nMode == 1 )    /* better if */
  189.         {
  190.                 /* hex->dotted */
  191.                 /*printf("Hex-In: %s\n", abCommandLine );*/
  192.  
  193.                 char *p = abCommandLine;
  194.                 char *q = p;
  195.  
  196.                 unsigned char *pb = NULL;
  197.                 unsigned int nn = 0;
  198.                 #ifdef is_gmp
  199.                 mpz_t ll;
  200.                 mpz_init(ll);
  201.                 #else
  202.                 unsigned long ll = 0;
  203.                 #endif
  204.                 bool fOK = false;
  205.                 int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
  206.  
  207.                 while ( *p ) {
  208.                         if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
  209.                                 *q++ = *p;
  210.                         }
  211.                         p++;
  212.                 }
  213.                 *q = '\0';
  214.  
  215.                 if ( strlen( abCommandLine ) % 2 != 0 ) {
  216.                         fprintf(stderr, "OID must have even number of hex digits!\n" );
  217.                         return 2;
  218.                 }
  219.  
  220.                 if ( strlen( abCommandLine ) < 3 ) {
  221.                         fprintf(stderr, "OID must have at least three bytes!\n" );
  222.                         return 2;
  223.                 }
  224.  
  225.                 nBinary = 0;
  226.                 p = abCommandLine;
  227.  
  228.                 while ( *p ) {
  229.                         unsigned char b;
  230.  
  231.                         if ( p[0] >= 'A' && p[0] <= 'F' ) {
  232.                                 b = (p[0] - 'A' + 10) * 16;
  233.                         } else if ( p[0] >= 'a' && p[0] <= 'f' ) {
  234.                                 b = (p[0] - 'a' + 10) * 16;
  235.                         } else if ( p[0] >= '0' && p[0] <= '9' ) {
  236.                                 b = (p[0] - '0') * 16;
  237.                         } else {
  238.                                 fprintf(stderr, "Must have hex digits only!\n" );
  239.                                 return 2;
  240.                         }
  241.  
  242.                         if ( p[1] >= 'A' && p[1] <= 'F' || p[1] >= 'a' && p[1] <= 'f' ) {
  243.                                 b += (p[1] - 'A' + 10);
  244.                         } else if ( p[1] >= '0' && p[1] <= '9' ) {
  245.                                 b += (p[1] - '0');
  246.                         } else {
  247.                                 fprintf(stderr, "Must have hex digits only!\n" );
  248.                                 return 2;
  249.                         }
  250.                         abBinary[nBinary++] = b;
  251.                         p += 2;
  252.                 }
  253.  
  254.                 /*printf("Hex-In: %s\n", abCommandLine );*/
  255.  
  256.                 if ( fOutName != NULL ) {
  257.                         fOut = fopen( fOutName, "wt" );
  258.                         if ( fOut == NULL ) {
  259.                                 fprintf(stderr,"Unable to open output file %s\n", fOutName );
  260.                                 return 33;
  261.                         }
  262.                 } else {
  263.                         fOut = stdout;
  264.                 }
  265.  
  266.                 pb = abBinary;
  267.                 nn = 0;
  268.                 #ifdef is_gmp
  269.                 mpz_init(ll);
  270.                 #else
  271.                 ll = 0;
  272.                 #endif
  273.                 fOK = false;
  274.                 fSub = 0;
  275.                 while ( nn < nBinary ) {
  276.                         if ( nn == 0 ) {
  277.                                 unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
  278.                                 switch ( cl ) {
  279.                                         default:
  280.                                         case 0: fprintf(fOut,"UNIVERSAL"); break;
  281.                                         case 1: fprintf(fOut,"APPLICATION"); break;
  282.                                         case 2: fprintf(fOut,"CONTEXT"); break;
  283.                                         case 3: fprintf(fOut,"PRIVATE"); break;
  284.                                 }
  285.                                 fprintf(fOut," OID");
  286.                         } else if ( nn == 1 ) {
  287.                                 if ( nBinary - 2 != *pb ) {
  288.                                         if ( fOut != stdout ) {
  289.                                                 fclose( fOut );
  290.                                         }
  291.                                         fprintf(stderr,"\nInvalid length (%d)\n", *pb );
  292.                                         fprintf(fOut,"\n");
  293.                                         return 3;
  294.                                 }
  295.                         } else if ( nn == 2 ) {
  296.                                 int first = *pb / 40;
  297.                                 int second = *pb % 40;
  298.                                 if (first > 2) {
  299.                                         first = 2;
  300.                                         fprintf(fOut,".%d", first );
  301.  
  302.                                         if ( (*pb & 0x80) != 0 ) {
  303.                                                 // 2.48 and up => 2+ octets
  304.                                                 #ifdef is_gmp
  305.                                                 mpz_add_ui(ll, ll, (*pb & 0x7F));
  306.                                                 #else
  307.                                                 ll += (*pb & 0x7F);
  308.                                                 #endif
  309.                                                 fSub = 80;
  310.                                                 fOK = false;
  311.                                         } else {
  312.                                                 // 2.0 till 2.47 => 1 octet
  313.                                                 second = *pb - 80;
  314.                                                 fprintf(fOut,".%d",second);
  315.                                                 fOK = true;
  316.                                                 #ifdef is_gmp
  317.                                                 mpz_set_ui(ll, 0);
  318.                                                 #else
  319.                                                 ll = 0;
  320.                                                 #endif
  321.                                         }
  322.                                 } else {
  323.                                         // 0.0 till 0.37 => 1 octet
  324.                                         // 1.0 till 1.37 => 1 octet
  325.                                         fprintf(fOut,".%d.%d", first, second );
  326.                                         fOK = true;
  327.                                         #ifdef is_gmp
  328.                                         mpz_set_ui(ll, 0);
  329.                                         #else
  330.                                         ll = 0;
  331.                                         #endif
  332.                                 }
  333.                         } else if ( (*pb & 0x80) != 0 ) {
  334.                                 #ifdef is_gmp
  335.                                 mpz_mul_ui(ll, ll, 128);
  336.                                 mpz_add_ui(ll, ll, (*pb & 0x7F));
  337.                                 #else
  338.                                 ll *= 128;
  339.                                 ll += (*pb & 0x7F);
  340.                                 #endif
  341.                                 fOK = false;
  342.                         } else {
  343.                                 #ifdef is_gmp
  344.                                 mpz_mul_ui(ll, ll, 128);
  345.                                 mpz_add_ui(ll, ll, *pb);
  346.                                 mpz_sub_ui(ll, ll, fSub);
  347.                                 fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
  348.                                 mpz_set_ui(ll, 0);
  349.                                 #else
  350.                                 ll *= 128;
  351.                                 ll += *pb;
  352.                                 ll -= fSub;
  353.                                 fprintf(fOut,".%lu", ll );
  354.                                 ll = 0;
  355.                                 #endif
  356.                                 fSub = 0;
  357.                                 fOK = true;
  358.                         }
  359.  
  360.                         pb++;
  361.                         nn++;
  362.                 }
  363.  
  364.                 if ( !fOK ) {
  365.                         fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
  366.                         fprintf(fOut,"\n");
  367.                         return 4;
  368.                 } else {
  369.                         fprintf(fOut,"\n");
  370.                 }
  371.  
  372.                 if ( fOut != stdout ) {
  373.                         fclose( fOut );
  374.                 }
  375.                 break;
  376.         };
  377.  
  378.         while ( nMode == 0 )    /* better if */
  379.         {
  380.                 /* dotted->hex */
  381.                 /* printf("OID.%s\n", abCommandLine ); */
  382.  
  383.                 char *p = abCommandLine;
  384.                 unsigned char cl = 0x00;
  385.                 char *q = NULL;
  386.                 int nPieces = 1;
  387.                 int n = 0;
  388.                 unsigned char b = 0;
  389.                 unsigned int nn = 0;
  390.                 #ifdef is_gmp
  391.                 mpz_t l;
  392.                 #else
  393.                 unsigned long l = 0;
  394.                 #endif
  395.                 bool isjoint = false;
  396.  
  397.                 if ( __STRNICMP_LOCAL( p, "UNIVERSAL.", 10 ) == 0 ) {
  398.                         p+=10;
  399.                 } else if ( __STRNICMP_LOCAL( p, "APPLICATION.", 12 ) == 0 ) {
  400.                         cl = 0x40;
  401.                         p+=12;
  402.                 } else if ( __STRNICMP_LOCAL( p, "CONTEXT.", 8 ) == 0 ) {
  403.                         cl = 0x80;
  404.                         p+=8;
  405.                 } else if ( __STRNICMP_LOCAL( p, "PRIVATE.", 8 ) == 0 ) {
  406.                         cl = 0xC0;
  407.                         p+=8;
  408.                 }
  409.  
  410.                 if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
  411.                         p+=4;
  412.                 }
  413.  
  414.                 q = p;
  415.                 nPieces = 1;
  416.                 while ( *p ) {
  417.                         if ( *p == '.' ) {
  418.                                 nPieces++;
  419.                         }
  420.                         p++;
  421.                 }
  422.  
  423.                 n = 0;
  424.                 b = 0;
  425.                 p = q;
  426.                 while ( n < nPieces ) {
  427.                         q = p;
  428.                         while ( *p ) {
  429.                                 if ( *p == '.' ) {
  430.                                         break;
  431.                                 }
  432.                                 p++;
  433.                         }
  434.  
  435.                         #ifdef is_gmp
  436.                         mpz_init(l);
  437.                         #else
  438.                         l = 0;
  439.                         #endif
  440.                         if ( *p == '.' ) {
  441.                                 *p = 0;
  442.                                 #ifdef is_gmp
  443.                                 mpz_set_str(l, q, 10);
  444.                                 #else
  445.                                 l = (unsigned long) atoi( q );
  446.                                 #endif
  447.                                 q = p+1;
  448.                                 p = q;
  449.                         } else {
  450.                                 #ifdef is_gmp
  451.                                 mpz_set_str(l, q, 10);
  452.                                 #else
  453.                                 l = (unsigned long) atoi( q );
  454.                                 #endif
  455.                                 q = p;
  456.                         }
  457.  
  458.                         /* Digit is in l. */
  459.                         if ( n == 0 ) {
  460.                                 #ifdef is_gmp
  461.                                 if (mpz_cmp_ui(l, 2) > 0) {
  462.                                 #else
  463.                                 if (l > 2) {
  464.                                 #endif
  465.                                         fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
  466.                                         return 5;
  467.                                 }
  468.                                 #ifdef is_gmp
  469.                                 b += 40 * mpz_get_ui(l);
  470.                                 isjoint = mpz_cmp_ui(l, 2) == 0;
  471.                                 #else
  472.                                 b = 40 * ((unsigned char)l);
  473.                                 isjoint = l == 2;
  474.                                 #endif
  475.                         } else if ( n == 1 ) {
  476.                                 #ifdef is_gmp
  477.                                 if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
  478.                                 #else
  479.                                 if ((l > 39) && (!isjoint)) {
  480.                                 #endif
  481.                                         fprintf(stderr,"\nEncoding error. The second level is limited to 0..39 for top level arcs 0 and 1.\n");
  482.                                         return 5;
  483.                                 }
  484.  
  485.                                 #ifdef is_gmp
  486.                                 if (mpz_cmp_ui(l, 47) > 0) {
  487.                                         mpz_add_ui(l, l, 80);
  488.                                         MakeBase128( l, 1 );
  489.                                 } else {
  490.                                         b += mpz_get_ui(l);
  491.                                         abBinary[nBinary++] = b;
  492.                                 }
  493.                                 #else
  494.                                 if (l > 47) {
  495.                                         l += 80;
  496.                                         MakeBase128( l, 1 );
  497.                                 } else {
  498.                                         b += ((unsigned char) l);
  499.                                         abBinary[nBinary++] = b;
  500.                                 }
  501.                                 #endif
  502.                         } else {
  503.                                 MakeBase128( l, 1 );
  504.                         }
  505.                         n++;
  506.                 }
  507.  
  508.                 if (n < 2) {
  509.                         fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable OID is 2. (e.g. 2.999)\n");
  510.                         return 5;
  511.                 }
  512.  
  513.                 if ( fOutName != NULL ) {
  514.                         fOut = fopen( fOutName, "wt" );
  515.                         if ( fOut == NULL ) {
  516.                                 fprintf(stderr,"Unable to open output file %s\n", fOutName );
  517.                                 return 33;
  518.                         }
  519.                 } else {
  520.                         fOut = stdout;
  521.                 }
  522.  
  523.                 if ( nCHex ) {
  524.                         fprintf(fOut,"\"\\x%02X\\x%02X", cl | 6, nBinary );
  525.                 } else {
  526.                         fprintf(fOut,"%02X %02X ", cl | 6, nBinary );
  527.                 }
  528.                 nn = 0;
  529.                 while ( nn < nBinary ) {
  530.                         unsigned char b = abBinary[nn++];
  531.                         if ( nn == nBinary ) {
  532.                                 if ( nCHex ) {
  533.                                         fprintf(fOut,"\\x%02X\"\n", b );
  534.                                 } else {
  535.                                         fprintf(fOut,"%02X\n", b );
  536.                                 }
  537.                         } else {
  538.                                 if ( nCHex ) {
  539.                                         fprintf(fOut,"\\x%02X", b );
  540.                                 } else {
  541.                                         fprintf(fOut,"%02X ", b );
  542.                                 }
  543.                         }
  544.                 }
  545.                 if ( fOut != stdout ) {
  546.                         fclose( fOut );
  547.                 }
  548.                 break;
  549.         }
  550.  
  551.         return 0;
  552. }
  553.  
  554. /* */
  555.  
  556.