Subversion Repositories oidconverter

Rev

Rev 2 | Rev 7 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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