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. ###                                                               ###
  6. ### Enhanced version by Daniel Marschall, ViaThinkSoft 06-07/2011 ###
  7. ### -- NEW 1.2: 2.48 can also be encoded!                         ###
  8. ### -- NEW 1.2: UUIDs (128-bit) are now supported!                ###
  9. ###             (requires GMPLib)                                 ###
  10. ### -- NEW 1.3: Length can now have more than 1 byte              ###
  11. ### -- NEW 1.4: No command line limitation anymore.               ###
  12. ### -- NEW 1.5: Now also relative OIDs supported                  ###
  13. ### -- NEW 1.6: 0x80 paddings are now disallowed                  ###
  14. ### -- NEW 1.8: Removed Application/Context/Private "OID"s        ###
  15. ### -- NEW 1.9: Also allow decoding C-notation with "-x"          ###
  16. ### -- AS WELL AS SEVERAL BUG FIXES                               ###
  17. ###                                                               ###
  18. ### To compile with gcc simply use:                               ###
  19. ###   gcc -O2 -o oid oid.c -lgmp -lm                              ###
  20. ###                                                               ###
  21. ### To compile using cl, use:                                     ###
  22. ###   cl -DWIN32 -O1 oid.c (+ include gmp library)                ###
  23. ###                                                               ###
  24. ### Freeware - do with it whatever you want.                      ###
  25. ### Use at your own risk. No warranty of any kind.                ###
  26. ###                                                               ###
  27. ###################################################################*/
  28. /* $Version: 1.9$ */
  29.  
  30. // FUTURE
  31. // - Alles in Funktionen kapseln. Als Parameter: Array of integer (= dot notation) oder Array of byte (= hex notation)
  32.  
  33. // MINOR THINGS
  34. // - All stderr: Output new line at stdOut and close stdOut
  35. // - Make as much GMP as possible (e.g. nBinary counter, nBinaryWork etc)
  36. // - überlegen, wie man die return-codes (errorcodes) besser verteilt/definiert
  37. // - irgendwie in funktionen kapseln (z.b. class-tag-parser usw)
  38. // - "TODO"s beachten (unklare dinge)
  39.  
  40. // MINOR PROBLEMS IN CLI-INTERPRETATION:
  41. // - A wrong error message is shown when trying to encode "-0.0" or "x"
  42. // - 2.9a9 is not recognized as error
  43. // - "./oid R 2.999" is not interpretet correctly
  44.  
  45. // NICE TO HAVE:
  46. // - also allow -x to interpret "\x06\x02\x88\x37"
  47. // - makefile, manpage, linuxpackage
  48. // - better make functions instead of putting everything in main() with fprintf...
  49.  
  50. // NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
  51. // - Is it possible to detect integer overflows and therefore output errors?
  52.  
  53.  
  54. // -------------------------------------------------------
  55.  
  56. // Allows OIDs which are bigger than "long"
  57. // Compile with "gcc oid.c -lgmp -lm"
  58. #define is_gmp
  59.  
  60. #include <stdio.h>
  61. #include <string.h>
  62. #include <stdlib.h>
  63.  
  64. #ifdef is_gmp
  65. #include <gmp.h>
  66. #endif
  67.  
  68. #include <stdbool.h>
  69.  
  70. #ifndef __STRNICMP_LOCAL
  71. #ifdef WIN32
  72. #define __STRNICMP_LOCAL strnicmp
  73. #else
  74. #define __STRNICMP_LOCAL strncasecmp
  75. #endif
  76. #endif
  77.  
  78. // char abCommandLine[4096];
  79. const unsigned int CLI_INITIAL_SIZE = 1024;
  80. const unsigned int CLI_EXPANSION_SIZE = 1024;
  81. unsigned int cli_size;
  82. char * abCommandLine;
  83.  
  84. // unsigned char abBinary[128];
  85. const unsigned int ABB_INITIAL_SIZE = 1024;
  86. const unsigned int ABB_EXPANSION_SIZE = 1024;
  87. unsigned int abb_size;
  88. unsigned char * abBinary;
  89.  
  90. unsigned int nBinary = 0;
  91.  
  92. const int MODE_DOT_TO_HEX = 0;
  93. const int MODE_HEX_TO_DOT = 1;
  94.  
  95. #ifdef is_gmp
  96. static void MakeBase128( mpz_t l, int first ) {
  97.         if ( mpz_cmp_si(l, 127) > 0 ) {
  98.                 mpz_t l2;
  99.                 mpz_init(l2);
  100.                 mpz_div_ui(l2, l, 128);
  101.                 MakeBase128( l2 , 0 );
  102.         }
  103.         mpz_mod_ui(l, l, 128);
  104.  
  105.         if (nBinary+1 >= abb_size) {
  106.                 abb_size += ABB_EXPANSION_SIZE;
  107.                 abBinary = (unsigned char*) realloc(abBinary, abb_size);
  108.                 if (abBinary == NULL) {
  109.                         fprintf(stderr, "Memory reallocation failure!\n");
  110.                         exit(EXIT_FAILURE);
  111.                 }
  112.         }
  113.  
  114.         if ( first ) {
  115.                 abBinary[nBinary++] = mpz_get_ui(l);
  116.         } else {
  117.                 abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
  118.         }
  119. }
  120. #else
  121. static void MakeBase128( unsigned long l, int first ) {
  122.         if ( l > 127 ) {
  123.                 MakeBase128( l / 128, 0 );
  124.         }
  125.         l %= 128;
  126.  
  127.         if (nBinary+1 >= abb_size) {
  128.                 abb_size += ABB_EXPANSION_SIZE;
  129.                 abBinary = (unsigned char*) realloc(abBinary, abb_size);
  130.                 if (abBinary == NULL) {
  131.                         fprintf(stderr, "Memory reallocation failure!\n");
  132.                         exit(EXIT_FAILURE);
  133.                 }
  134.         }
  135.  
  136.         if ( first ) {
  137.                 abBinary[nBinary++] = (unsigned char)l;
  138.         } else {
  139.                 abBinary[nBinary++] = 0x80 | (unsigned char)l;
  140.         }
  141. }
  142. #endif
  143.  
  144. int main( int argc, char **argv ) {
  145.         cli_size = CLI_INITIAL_SIZE;
  146.         abCommandLine  = (char*) malloc(cli_size * sizeof(char*));
  147.         if (abCommandLine == NULL) {
  148.                 fprintf(stderr, "Memory allocation failure!\n");
  149.                 return EXIT_FAILURE;
  150.         }
  151.  
  152.         abb_size = ABB_INITIAL_SIZE;
  153.         abBinary  = (unsigned char*) malloc(abb_size * sizeof(unsigned char*));
  154.         if (abBinary == NULL) {
  155.                 fprintf(stderr, "Memory allocation failure!\n");
  156.                 return EXIT_FAILURE;
  157.         }
  158.  
  159.  
  160.         char *fOutName = NULL;
  161.         char *fInName = NULL;
  162.         FILE *fOut = NULL;
  163.  
  164.         int n = 1;
  165.         int nMode = MODE_DOT_TO_HEX;
  166.         bool nCHex = false;
  167.         int nAfterOption = 0;
  168.         bool isRelative = false;
  169.  
  170.         if ( argc == 1 ) {
  171.                 fprintf( stderr,
  172.                 "OID encoder/decoder 1.9 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
  173.                 #ifdef is_gmp
  174.                 "GMP Edition\n"
  175.                 #endif
  176.                 "\nUsage:\n"
  177.                 " OID [-C] [-r] [-o<outfile>] {-i<infile>|2.999.1}\n"
  178.                 "   converts dotted form to ASCII HEX DER output.\n"
  179.                 "   -C: Output as C-syntax.\n"
  180.                 "   -r: Handle the OID as relative and not absolute.\n"
  181.                 " OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
  182.                 "   decodes ASCII HEX DER and gives dotted form.\n" );
  183.                 return 1;
  184.         }
  185.  
  186.         while ( n < argc ) {
  187.                 if ( !nAfterOption && argv[n][0] == '-' ) {
  188.                         if ( argv[n][1] == 'x' ) {
  189.                                 nMode = MODE_HEX_TO_DOT;
  190.                                 if ( argv[n][2] != '\0' ) {
  191.                                         argv[n--] += 2;
  192.                                         nAfterOption = 1;
  193.                                 }
  194.                         } else if ( argv[n][1] == 'C' ) {
  195.                                 nMode = MODE_DOT_TO_HEX;
  196.                                 nCHex = true;
  197.  
  198.                                 if ( argv[n][2] != '\0' ) {
  199.                                         argv[n--] += 2;
  200.                                         nAfterOption = 1;
  201.                                 }
  202.                         } else if ( argv[n][1] == 'r' ) {
  203.                                 nMode = MODE_DOT_TO_HEX;
  204.                                 isRelative = true;
  205.  
  206.                                 if ( argv[n][2] != '\0' ) {
  207.                                         argv[n--] += 2;
  208.                                         nAfterOption = 1;
  209.                                 }
  210.                         } else if ( argv[n][1] == 'o' ) {
  211.                                 if ( argv[n][2] != '\0' ) {
  212.                                         fOutName = &argv[n][2];
  213.                                 } else if ( n < argc-1 ) {
  214.                                         fOutName = argv[++n];
  215.                                 } else {
  216.                                         fprintf(stderr,"Incomplete command line.\n");
  217.                                         return EXIT_FAILURE;
  218.                                 }
  219.                         } else if ( argv[n][1] == 'i' ) {
  220.                                 if ( argv[n][2] != '\0' ) {
  221.                                         fInName = &argv[n][2];
  222.                                 } else if ( n < argc-1 ) {
  223.                                         fInName = argv[++n];
  224.                                 } else {
  225.                                         fprintf(stderr,"Incomplete command line.\n");
  226.                                         return EXIT_FAILURE;
  227.                                 }
  228.                         }
  229.                 } else {
  230.                         if ( fInName != NULL ) { // TODO: (Unklar) Was bewirkt das? Auch für fOutName notwendig?
  231.                                 break;
  232.                         }
  233.  
  234.                         nAfterOption = 1;
  235.                         if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
  236.                                 // fprintf(stderr,"Command line too long.\n");
  237.                                 // return 2;
  238.  
  239.                                 cli_size += CLI_EXPANSION_SIZE + strlen( argv[n] ) + 1; // 1 = "."
  240.                                 abCommandLine = (char*) realloc(abCommandLine, cli_size);
  241.                                 if (abCommandLine == NULL) {
  242.                                         fprintf(stderr, "Memory reallocation failure!\n");
  243.                                         return EXIT_FAILURE;
  244.                                 }
  245.                                 // TODO: (Unklar) Wer garantiert, dass es mit "\0" abschließt?
  246.                         }
  247.                         strcat( abCommandLine, argv[n] );
  248.                         if ( n != argc - 1 && nMode != MODE_HEX_TO_DOT ) {
  249.                                 strcat( abCommandLine, "." );
  250.                         }
  251.                 }
  252.                 n++;
  253.         }
  254.  
  255.         if ( fInName != NULL && nMode == MODE_HEX_TO_DOT ) {
  256.                 FILE *fIn = fopen( fInName, "rb" );
  257.                 size_t nRead = 0;
  258.                 if ( fIn == NULL ) {
  259.                         fprintf(stderr,"Unable to open input file %s.\n", fInName );
  260.                         return 11;
  261.                 }
  262.                 nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
  263.                 abCommandLine[nRead] = '\0';
  264.                 fclose( fIn );
  265.         } else if ( fInName != NULL && nMode == MODE_DOT_TO_HEX ) {
  266.                 FILE *fIn = fopen( fInName, "rt" );
  267.                 if ( fIn == NULL ) {
  268.                         fprintf(stderr,"Unable to open input file %s.\n", fInName );
  269.                         return 11;
  270.                 }
  271.                 fgets( abCommandLine, sizeof(abCommandLine), fIn );
  272.                 fclose( fIn );
  273.         }
  274.  
  275.         while ( nMode == MODE_HEX_TO_DOT )      /* better if */
  276.         {
  277.                 /* hex->dotted */
  278.                 /*printf("Hex-In: %s\n", abCommandLine );*/
  279.  
  280.                 char *p = abCommandLine;
  281.                 char *q = p;
  282.  
  283.                 unsigned char *pb = NULL;
  284.                 unsigned int nn = 0;
  285.                 #ifdef is_gmp
  286.                 mpz_t ll;
  287.                 mpz_init(ll);
  288.                 #else
  289.                 unsigned long ll = 0;
  290.                 #endif
  291.                 bool fOK = false;
  292.                 int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
  293.  
  294.                 while ( *p ) {
  295.                         if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
  296.                                 *q++ = *p;
  297.                         }
  298.                         p++;
  299.                 }
  300.                 *q = '\0';
  301.  
  302.                 if ( strlen( abCommandLine ) % 2 != 0 ) {
  303.                         fprintf(stderr, "Encoded OID must have even number of hex digits!\n" );
  304.                         return 2;
  305.                 }
  306.  
  307.                 if ( strlen( abCommandLine ) < 3 ) {
  308.                         fprintf(stderr, "Encoded OID must have at least three bytes!\n" );
  309.                         return 2;
  310.                 }
  311.  
  312.                 nBinary = 0;
  313.                 p = abCommandLine;
  314.  
  315.                 while ( *p ) {
  316.                         unsigned char b;
  317.  
  318.                         // This allows also C-notation
  319.                         if ((p[0] == '\\') && (p[1] == 'x')) {
  320.                                 p += 2;
  321.                                 continue;
  322.                         }
  323.  
  324.                         // Interpret upper nibble
  325.                         if ( p[0] >= 'A' && p[0] <= 'F' ) {
  326.                                 b = (p[0] - 'A' + 10) * 16;
  327.                         } else if ( p[0] >= 'a' && p[0] <= 'f' ) {
  328.                                 b = (p[0] - 'a' + 10) * 16;
  329.                         } else if ( p[0] >= '0' && p[0] <= '9' ) {
  330.                                 b = (p[0] - '0') * 16;
  331.                         } else {
  332.                                 fprintf(stderr, "Must have hex digits only!\n" );
  333.                                 return 2;
  334.                         }
  335.  
  336.                         // Interpret lower nibble
  337.                         if ( p[1] >= 'A' && p[1] <= 'F' ) {
  338.                                 b += (p[1] - 'A' + 10);
  339.                         } else if ( p[1] >= 'a' && p[1] <= 'f' ) {
  340.                                 b += (p[1] - 'a' + 10);
  341.                         } else if ( p[1] >= '0' && p[1] <= '9' ) {
  342.                                 b += (p[1] - '0');
  343.                         } else {
  344.                                 fprintf(stderr, "Must have hex digits only!\n" );
  345.                                 return 2;
  346.                         }
  347.  
  348.                         if (nBinary+1 >= abb_size) {
  349.                                 abb_size += ABB_EXPANSION_SIZE;
  350.                                 abBinary = (unsigned char*) realloc(abBinary, abb_size);
  351.                                 if (abBinary == NULL) {
  352.                                         fprintf(stderr, "Memory reallocation failure!\n");
  353.                                         return EXIT_FAILURE;
  354.                                 }
  355.                         }
  356.  
  357.                         abBinary[nBinary++] = b;
  358.                         p += 2;
  359.                 }
  360.  
  361.                 /*printf("Hex-In: %s\n", abCommandLine );*/
  362.  
  363.                 if ( fOutName != NULL ) {
  364.                         fOut = fopen( fOutName, "wt" );
  365.                         if ( fOut == NULL ) {
  366.                                 fprintf(stderr,"Unable to open output file %s\n", fOutName );
  367.                                 return 33;
  368.                         }
  369.                 } else {
  370.                         fOut = stdout;
  371.                 }
  372.  
  373.                 pb = abBinary;
  374.                 nn = 0;
  375.                 #ifdef is_gmp
  376.                 mpz_init(ll);
  377.                 #else
  378.                 ll = 0;
  379.                 #endif
  380.                 fOK = false;
  381.                 fSub = 0;
  382.  
  383.                 // 0 = Universal Class Identifier Tag (can be more than 1 byte, but not in our case)
  384.                 // 1 = Length part (may have more than 1 byte!)
  385.                 // 2 = First two arc encoding
  386.                 // 3 = Encoding of arc three and higher
  387.                 unsigned char part = 0;
  388.  
  389.                 unsigned char lengthbyte_count = 0;
  390.                 unsigned char lengthbyte_pos = 0;
  391.                 bool lengthfinished = false;
  392.  
  393.                 while ( nn < nBinary ) {
  394.                         if ( part == 0 ) { // Class Tag
  395.  
  396.                                 // Leading octet
  397.                                 // Bit 7 / Bit 6 = Universal (00), Application (01), Context (10), Private(11)
  398.                                 // Bit 5 = Primitive (0), Constructed (1)
  399.                                 // Bit 4..0 = 00000 .. 11110 => Tag 0..30, 11111 for Tag > 30 (following bytes with the highest bit as "more" bit)
  400.                                 // --> We don't need to respect 11111 (class-tag encodes in more than 1 octet)
  401.                                 //     as we terminate when the tag is not of type OID or RELATEIVE-OID
  402.                                 // See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
  403.  
  404.                                 // Class: 8. - 7. bit
  405.                                 // 0 (00) = Universal
  406.                                 // 1 (01) = Application
  407.                                 // 2 (10) = Context
  408.                                 // 3 (11) = Private
  409.                                 unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
  410.                                 if (cl != 0) {
  411.                                         fprintf(stderr,"\nError at type: The OID tags are only defined as UNIVERSAL class tags.\n");
  412.                                         fprintf(fOut,"\n");
  413.                                         return 6;
  414.                                 }
  415.  
  416.                                 // Primitive/Constructed: 6. bit
  417.                                 // 0 = Primitive
  418.                                 // 1 = Constructed
  419.                                 unsigned char pc = *pb & 0x20;
  420.                                 if (pc != 0) {
  421.                                         fprintf(stderr,"\nError at type: OIDs must be primitive, not constructed.\n");
  422.                                         fprintf(fOut,"\n");
  423.                                         return 6;
  424.                                 }
  425.  
  426.                                 // Tag number: 5. - 1. bit
  427.                                 unsigned char tag = *pb & 0x1F;
  428.                                 if (tag == 0x0D) {
  429.                                         isRelative = true;
  430.                                 } else if (tag == 0x06) {
  431.                                         isRelative = false;
  432.                                 } else {
  433.                                         fprintf(stderr,"\nError at type: The tag number is neither an absolute OID (0x06) nor a relative OID (0x0D).\n");
  434.                                         fprintf(fOut,"\n");
  435.                                         return 6;
  436.                                 }
  437.  
  438.                                 // Output
  439.                                 if (isRelative) {
  440.                                         fprintf(fOut, "RELATIVE");
  441.                                 } else {
  442.                                         fprintf(fOut, "ABSOLUTE");
  443.                                 }
  444.  
  445.                                 fprintf(fOut,".OID");
  446.                                 part++;
  447.                         } else if ( part == 1 ) { // Length
  448.  
  449.                                 // Find out the length and save it into ll
  450.  
  451.                                 // [length] is encoded as follows:
  452.                                 //  0x00 .. 0x7F = The actual length is in this byte, followed by [data].
  453.                                 //  0x80 + n     = The length of [data] is spread over the following 'n' bytes. (0 < n < 0x7F)
  454.                                 //  0x80         = "indefinite length" (only constructed form) -- Invalid
  455.                                 //  0xFF         = Reserved for further implementations -- Invalid
  456.                                 //  See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
  457.  
  458.                                 if (nn == 1) { // The first length byte
  459.                                         lengthbyte_pos = 0;
  460.                                         if ( (*pb & 0x80) != 0 ) {
  461.                                                 // 0x80 + n => The length is spread over the following 'n' bytes
  462.                                                 lengthfinished = false;
  463.                                                 lengthbyte_count = *pb & 0x7F;
  464.                                                 if (lengthbyte_count == 0x00) {
  465.                                                         fprintf(stderr,"\nLength value 0x80 is invalid (\"indefinite length\") for primitive types.\n");
  466.                                                         fprintf(fOut,"\n");
  467.                                                         return 7;
  468.                                                 } else if (lengthbyte_count == 0x7F) {
  469.                                                         fprintf(stderr,"\nLength value 0xFF is reserved for further extensions.\n");
  470.                                                         fprintf(fOut,"\n");
  471.                                                         return 7;
  472.                                                 }
  473.                                                 fOK = false;
  474.                                         } else {
  475.                                                 // 0x01 .. 0x7F => The actual length
  476.  
  477.                                                 if (*pb == 0x00) {
  478.                                                         fprintf(stderr,"\nLength value 0x00 is invalid for an OID.\n");
  479.                                                         fprintf(fOut,"\n");
  480.                                                         return 7;
  481.                                                 }
  482.  
  483.                                                 #ifdef is_gmp
  484.                                                 mpz_set_ui(ll, *pb);
  485.                                                 #else
  486.                                                 ll = *pb;
  487.                                                 #endif
  488.                                                 lengthfinished = true;
  489.                                                 lengthbyte_count = 0;
  490.                                                 fOK = true;
  491.                                         }
  492.                                 } else {
  493.                                         if (lengthbyte_count > lengthbyte_pos) {
  494.                                                 #ifdef is_gmp
  495.                                                 mpz_mul_ui(ll, ll, 0x100);
  496.                                                 mpz_add_ui(ll, ll, *pb);
  497.                                                 #else
  498.                                                 ll *= 0x100;
  499.                                                 ll += *pb;
  500.                                                 #endif
  501.                                                 lengthbyte_pos++;
  502.                                         }
  503.  
  504.                                         if (lengthbyte_count == lengthbyte_pos) {
  505.                                                 lengthfinished = true;
  506.                                                 fOK = true;
  507.                                         }
  508.                                 }
  509.  
  510.                                 if (lengthfinished) { // The length is now in ll
  511.                                         #ifdef is_gmp
  512.                                         if ( mpz_cmp_ui(ll,  nBinary - 2 - lengthbyte_count) != 0 ) {
  513.                                                 fprintf(fOut,"\n");
  514.                                                 if ( fOut != stdout ) {
  515.                                                         fclose( fOut );
  516.                                                 }
  517.                                                 fprintf(stderr,"\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll) );
  518.                                                 return 3;
  519.                                         }
  520.                                         mpz_set_ui(ll, 0); // reset for later usage
  521.                                         #else
  522.                                         if ( ll != nBinary - 2 - lengthbyte_count ) {
  523.                                                 fprintf(fOut,"\n");
  524.                                                 if ( fOut != stdout ) {
  525.                                                         fclose( fOut );
  526.                                                 }
  527.                                                 fprintf(stderr,"\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll );
  528.                                                 return 3;
  529.                                         }
  530.                                         ll = 0; // reset for later usage
  531.                                         #endif
  532.                                         fOK = true;
  533.                                         part++;
  534.                                         if (isRelative) part++; // Goto step 3!
  535.                                 }
  536.                         } else if ( part == 2 ) { // First two arcs
  537.                                 int first = *pb / 40;
  538.                                 int second = *pb % 40;
  539.                                 if (first > 2) {
  540.                                         first = 2;
  541.                                         fprintf(fOut,".%d", first );
  542.  
  543.                                         if ( (*pb & 0x80) != 0 ) {
  544.                                                 // 2.48 and up => 2+ octets
  545.                                                 // Output in "part 3"
  546.  
  547.                                                 if ((*pb & 0x7F) == 0) {
  548.                                                         fprintf(fOut,"\n");
  549.                                                         if ( fOut != stdout ) {
  550.                                                                 fclose( fOut );
  551.                                                         }
  552.                                                         fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
  553.                                                         return 4;
  554.                                                 }
  555.  
  556.                                                 #ifdef is_gmp
  557.                                                 mpz_add_ui(ll, ll, (*pb & 0x7F));
  558.                                                 #else
  559.                                                 ll += (*pb & 0x7F);
  560.                                                 #endif
  561.                                                 fSub = 80;
  562.                                                 fOK = false;
  563.                                         } else {
  564.                                                 // 2.0 till 2.47 => 1 octet
  565.                                                 second = *pb - 80;
  566.                                                 fprintf(fOut,".%d",second);
  567.                                                 fOK = true;
  568.                                                 #ifdef is_gmp
  569.                                                 mpz_set_ui(ll, 0);
  570.                                                 #else
  571.                                                 ll = 0;
  572.                                                 #endif
  573.                                         }
  574.                                 } else {
  575.                                         // 0.0 till 0.37 => 1 octet
  576.                                         // 1.0 till 1.37 => 1 octet
  577.                                         fprintf(fOut,".%d.%d", first, second );
  578.                                         fOK = true;
  579.                                         #ifdef is_gmp
  580.                                         mpz_set_ui(ll, 0);
  581.                                         #else
  582.                                         ll = 0;
  583.                                         #endif
  584.                                 }
  585.                                 part++;
  586.                         } else if ( part == 3 ) { // Arc three and higher
  587.                                 if ( (*pb & 0x80) != 0 ) {
  588.  
  589.                                         if ((*pb & 0x7F) == 0) {
  590.                                                 fprintf(fOut,"\n");
  591.                                                 if ( fOut != stdout ) {
  592.                                                         fclose( fOut );
  593.                                                 }
  594.                                                 fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
  595.                                                 return 4;
  596.                                         }
  597.  
  598.                                         #ifdef is_gmp
  599.                                         mpz_mul_ui(ll, ll, 128);
  600.                                         mpz_add_ui(ll, ll, (*pb & 0x7F));
  601.                                         #else
  602.                                         ll *= 128;
  603.                                         ll += (*pb & 0x7F);
  604.                                         #endif
  605.                                         fOK = false;
  606.                                 } else {
  607.                                         fOK = 1;
  608.                                         #ifdef is_gmp
  609.                                         mpz_mul_ui(ll, ll, 128);
  610.                                         mpz_add_ui(ll, ll, *pb);
  611.                                         mpz_sub_ui(ll, ll, fSub);
  612.                                         fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
  613.                                         // Happens only if 0x80 paddings are allowed
  614.                                         // fOK = mpz_cmp_ui(ll, 0 ) >= 0;
  615.                                         mpz_set_ui(ll, 0);
  616.                                         #else
  617.                                         ll *= 128;
  618.                                         ll += *pb;
  619.                                         ll -= fSub;
  620.                                         fprintf(fOut,".%lu", ll );
  621.                                         // Happens only if 0x80 paddings are allowed
  622.                                         // fOK = ll >= 0;
  623.                                         ll = 0;
  624.                                         #endif
  625.                                         fSub = 0;
  626.                                 }
  627.                         }
  628.  
  629.                         pb++;
  630.                         nn++;
  631.                 }
  632.  
  633.                 if ( !fOK ) {
  634.                         fprintf(fOut,"\n");
  635.                         if ( fOut != stdout ) {
  636.                                 fclose( fOut );
  637.                         }
  638.                         fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
  639.                         return 4;
  640.                 } else {
  641.                         fprintf(fOut,"\n");
  642.                 }
  643.  
  644.                 if ( fOut != stdout ) {
  645.                         fclose( fOut );
  646.                 }
  647.                 break;
  648.         };
  649.  
  650.         while ( nMode == MODE_DOT_TO_HEX )      /* better if */
  651.         {
  652.                 /* dotted->hex */
  653.                 /* printf("OID.%s\n", abCommandLine ); */
  654.  
  655.                 char *p = abCommandLine;
  656.                 unsigned char cl = 0x00;
  657.                 char *q = NULL;
  658.                 int nPieces = 1;
  659.                 int n = 0;
  660.                 unsigned char b = 0;
  661.                 unsigned int nn = 0;
  662.                 #ifdef is_gmp
  663.                 mpz_t l;
  664.                 #else
  665.                 unsigned long l = 0;
  666.                 #endif
  667.                 bool isjoint = false;
  668.  
  669.                 /* if ( __STRNICMP_LOCAL( p, "ABSOLUTE.", 9 ) == 0 ) {
  670.                         isRelative = false;
  671.                         p+=9;
  672.                 } else if ( __STRNICMP_LOCAL( p, "RELATIVE.", 9 ) == 0 ) {
  673.                         isRelative = true;
  674.                         p+=9;
  675.                 } else {
  676.                         isRelative = false;
  677.                 } */
  678.  
  679.                 cl = 0x00; // Class. Always UNIVERSAL (00)
  680.  
  681.                 // Tag for Universal Class
  682.                 if ( isRelative ) {
  683.                         cl |= 0x0D;
  684.                 } else {
  685.                         cl |= 0x06;
  686.                 }
  687.  
  688.                 /* if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
  689.                         p+=4;
  690.                 } */
  691.  
  692.                 q = p;
  693.                 nPieces = 1;
  694.                 while ( *p ) {
  695.                         if ( *p == '.' ) {
  696.                                 nPieces++;
  697.                         }
  698.                         p++;
  699.                 }
  700.  
  701.                 n = 0;
  702.                 b = 0;
  703.                 p = q;
  704.                 while ( n < nPieces ) {
  705.                         q = p;
  706.                         while ( *p ) {
  707.                                 if ( *p == '.' ) {
  708.                                         break;
  709.                                 }
  710.                                 p++;
  711.                         }
  712.  
  713.                         #ifdef is_gmp
  714.                         mpz_init(l);
  715.                         #else
  716.                         l = 0;
  717.                         #endif
  718.                         if ( *p == '.' ) {
  719.                                 *p = 0;
  720.                                 #ifdef is_gmp
  721.                                 mpz_set_str(l, q, 10);
  722.                                 #else
  723.                                 l = (unsigned long) atoi( q );
  724.                                 #endif
  725.                                 q = p+1;
  726.                                 p = q;
  727.                         } else {
  728.                                 #ifdef is_gmp
  729.                                 mpz_set_str(l, q, 10);
  730.                                 #else
  731.                                 l = (unsigned long) atoi( q );
  732.                                 #endif
  733.                                 q = p;
  734.                         }
  735.  
  736.                         /* Digit is in l. */
  737.                         if (( n == 0 ) && (!isRelative)) {
  738.                                 #ifdef is_gmp
  739.                                 if (mpz_cmp_ui(l, 2) > 0) {
  740.                                 #else
  741.                                 if (l > 2) {
  742.                                 #endif
  743.                                         fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
  744.                                         return 5;
  745.                                 }
  746.                                 #ifdef is_gmp
  747.                                 b += 40 * mpz_get_ui(l);
  748.                                 isjoint = mpz_cmp_ui(l, 2) == 0;
  749.                                 #else
  750.                                 b = 40 * ((unsigned char)l);
  751.                                 isjoint = l == 2;
  752.                                 #endif
  753.                         } else if (( n == 1 ) && (!isRelative)) {
  754.                                 #ifdef is_gmp
  755.                                 if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
  756.                                 #else
  757.                                 if ((l > 39) && (!isjoint)) {
  758.                                 #endif
  759.                                         fprintf(stderr,"\nEncoding error. The second arc is limited to 0..39 for root arcs 0 and 1.\n");
  760.                                         return 5;
  761.                                 }
  762.  
  763.                                 #ifdef is_gmp
  764.                                 if (mpz_cmp_ui(l, 47) > 0) {
  765.                                         mpz_add_ui(l, l, 80);
  766.                                         MakeBase128( l, 1 );
  767.                                 } else {
  768.                                         b += mpz_get_ui(l);
  769.                                         if (nBinary+1 >= abb_size) {
  770.                                                 abb_size += ABB_EXPANSION_SIZE;
  771.                                                 abBinary = (unsigned char*) realloc(abBinary, abb_size);
  772.                                                 if (abBinary == NULL) {
  773.                                                         fprintf(stderr, "Memory reallocation failure!\n");
  774.                                                         return EXIT_FAILURE;
  775.                                                 }
  776.                                         }
  777.                                         abBinary[nBinary++] = b;
  778.                                 }
  779.                                 #else
  780.                                 if (l > 47) {
  781.                                         l += 80;
  782.                                         MakeBase128( l, 1 );
  783.                                 } else {
  784.                                         b += ((unsigned char) l);
  785.                                         if (nBinary+1 >= abb_size) {
  786.                                                 abb_size += ABB_EXPANSION_SIZE;
  787.                                                 abBinary = (unsigned char*) realloc(abBinary, abb_size);
  788.                                                 if (abBinary == NULL) {
  789.                                                         fprintf(stderr, "Memory reallocation failure!\n");
  790.                                                         return EXIT_FAILURE;
  791.                                                 }
  792.                                         }
  793.                                         abBinary[nBinary++] = b;
  794.                                 }
  795.                                 #endif
  796.                         } else {
  797.                                 MakeBase128( l, 1 );
  798.                         }
  799.                         n++;
  800.                 }
  801.  
  802.                 if ((n < 2) && (!isRelative)) {
  803.                         fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable absolute OID is 2. (e.g. 2.999)\n");
  804.                         return 5;
  805.                 }
  806.  
  807.                 if ( fOutName != NULL ) {
  808.                         fOut = fopen( fOutName, "wt" );
  809.                         if ( fOut == NULL ) {
  810.                                 fprintf(stderr,"Unable to open output file %s\n", fOutName );
  811.                                 return 33;
  812.                         }
  813.                 } else {
  814.                         fOut = stdout;
  815.                 }
  816.  
  817.                 // Write class-tag
  818.                 if ( nCHex ) {
  819.                         fprintf(fOut,"\"\\x%02X", cl );
  820.                 } else {
  821.                         fprintf(fOut,"%02X ", cl );
  822.                 }
  823.  
  824.                 // Write length
  825.                 if (nBinary <= 0x7F) {
  826.                         if ( nCHex ) {
  827.                                 fprintf(fOut,"\\x%02X", nBinary );
  828.                         } else {
  829.                                 fprintf(fOut,"%02X ", nBinary );
  830.                         }
  831.                 } else {
  832.                         unsigned int nBinaryWork;
  833.                         unsigned int lengthCount = 0;
  834.  
  835.                         nBinaryWork = nBinary;
  836.                         do {
  837.                                 lengthCount++;
  838.                                 nBinaryWork /= 0x100;
  839.                         } while (nBinaryWork > 0);
  840.  
  841.                         if (lengthCount >= 0x7F) {
  842.                                 fprintf(stderr,"\nThe length cannot be encoded.\n");
  843.                                 return 8;
  844.                         }
  845.  
  846.                         if ( nCHex ) {
  847.                                 fprintf(fOut,"\\x%02X", 0x80 + lengthCount );
  848.                         } else {
  849.                                 fprintf(fOut,"%02X ", 0x80 + lengthCount );
  850.                         }
  851.  
  852.                         nBinaryWork = nBinary;
  853.                         do {
  854.                                 if ( nCHex ) {
  855.                                         fprintf(fOut,"\\x%02X", nBinaryWork & 0xFF );
  856.                                 } else {
  857.                                         fprintf(fOut,"%02X ", nBinaryWork & 0xFF );
  858.                                 }
  859.                                 nBinaryWork /= 0x100;
  860.                         } while (nBinaryWork > 0);
  861.                 }
  862.  
  863.                 nn = 0;
  864.                 while ( nn < nBinary ) {
  865.                         unsigned char b = abBinary[nn++];
  866.                         if ( nn == nBinary ) {
  867.                                 if ( nCHex ) {
  868.                                         fprintf(fOut,"\\x%02X\"\n", b );
  869.                                 } else {
  870.                                         fprintf(fOut,"%02X\n", b );
  871.                                 }
  872.                         } else {
  873.                                 if ( nCHex ) {
  874.                                         fprintf(fOut,"\\x%02X", b );
  875.                                 } else {
  876.                                         fprintf(fOut,"%02X ", b );
  877.                                 }
  878.                         }
  879.                 }
  880.                 if ( fOut != stdout ) {
  881.                         fclose( fOut );
  882.                 }
  883.                 break;
  884.         }
  885.  
  886.         free(abCommandLine);
  887.         free(abBinary);
  888.  
  889.         return 0;
  890. }
  891.  
  892. /* */
  893.  
  894.