Subversion Repositories oidconverter

Rev

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