Subversion Repositories oidconverter

Compare Revisions

No changes between revisions

Regard whitespace Rev 1 → Rev 2

/trunk/c/Makefile
0,0 → 1,7
all:
gcc -O2 -lgmp -lm -o oid oid.c
 
clean:
rm -f *.o
# TODO: if [ -f ... ] then rm
rm oid
/trunk/c/oid
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:executable
+*
\ No newline at end of property
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/c/oid.c
0,0 → 1,914
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### ###
### Enhanced version by Daniel Marschall, ViaThinkSoft 06-07/2011 ###
### -- NEW 1.2: 2.48 can also be encoded! ###
### -- NEW 1.2: UUIDs (128-bit) are now supported! ###
### (requires GMPLib) ###
### -- NEW 1.3: Length can now have more than 1 byte ###
### -- NEW 1.4: No command line limitation anymore. ###
### -- NEW 1.5: Now also relative OIDs supported ###
### -- NEW 1.6: 0x80 paddings are now disallowed ###
### -- NEW 1.8: Removed Application/Context/Private "OID"s ###
### -- NEW 1.9: Also allow decoding C-notation with "-x" ###
### -- AS WELL AS SEVERAL BUG FIXES ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c -lgmp -lm ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c (+ include gmp library) ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.11$ */
 
// FUTURE
// - Alles in Funktionen kapseln. Als Parameter: Array of integer (= dot notation) oder Array of byte (= hex notation)
 
// MINOR THINGS
// - All stderr: Output new line at stdOut and close stdOut
// - Make as much GMP as possible (e.g. nBinary counter, nBinaryWork etc)
// - überlegen, wie man die return-codes (errorcodes) besser verteilt/definiert
// - irgendwie in funktionen kapseln (z.b. class-tag-parser usw)
// - "TODO"s beachten (unklare dinge)
 
// MINOR PROBLEMS IN CLI-INTERPRETATION:
// - A wrong error message is shown when trying to encode "-0.0" or "x"
// - 2.9a9 is not recognized as error
// - "./oid R 2.999" is not interpretet correctly
// - "./oid .2.999" will be interpreted as "0.2.999"
 
// NICE TO HAVE:
// - also allow -x to interpret "\x06\x02\x88\x37"
// - makefile, manpage, linuxpackage
// - better make functions instead of putting everything in main() with fprintf...
 
// NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
// - Is it possible to detect integer overflows and therefore output errors?
 
 
// -------------------------------------------------------
 
// Allows OIDs which are bigger than "long"
// Compile with "gcc oid.c -lgmp -lm"
#define is_gmp
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifdef is_gmp
#include <gmp.h>
#endif
 
#include <stdbool.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
// char abCommandLine[4096];
const unsigned int CLI_INITIAL_SIZE = 1024;
const unsigned int CLI_EXPANSION_SIZE = 1024;
unsigned int cli_size;
char * abCommandLine;
 
// unsigned char abBinary[128];
const unsigned int ABB_INITIAL_SIZE = 1024;
const unsigned int ABB_EXPANSION_SIZE = 1024;
unsigned int abb_size;
unsigned char * abBinary;
 
unsigned int nBinary = 0;
 
const int MODE_DOT_TO_HEX = 0;
const int MODE_HEX_TO_DOT = 1;
 
#ifdef is_gmp
static void MakeBase128(mpz_t l, int first) {
if (mpz_cmp_si(l, 127) > 0) {
mpz_t l2;
mpz_init(l2);
mpz_div_ui(l2, l, 128);
MakeBase128(l2, 0);
}
mpz_mod_ui(l, l, 128);
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if (first) {
abBinary[nBinary++] = mpz_get_ui(l);
} else {
abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
}
}
#else
static void MakeBase128(unsigned long l, int first) {
if (l > 127) {
MakeBase128(l / 128, 0);
}
l %= 128;
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if (first) {
abBinary[nBinary++] = (unsigned char)l;
} else {
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
#endif
 
int main(int argc, char **argv) {
cli_size = CLI_INITIAL_SIZE;
abCommandLine = (char*) malloc(cli_size * sizeof(char*));
if (abCommandLine == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
abb_size = ABB_INITIAL_SIZE;
abBinary = (unsigned char*) malloc(abb_size * sizeof(unsigned char*));
if (abBinary == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
 
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = MODE_DOT_TO_HEX;
bool nCHex = false;
int nAfterOption = 0;
bool isRelative = false;
 
if (argc == 1) {
fprintf(stderr,
"OID encoder/decoder 1.11 - Matthias Gaertner 1999/2001, Daniel Marschall 2011/2012 - Freeware\n"
#ifdef is_gmp
"GMP Edition (unlimited arc sizes)\n"
#else
"%d-bit Edition (arc sizes are limited!)\n"
#endif
"\nUsage:\n"
" OID [-C] [-r] [-o<outfile>] {-i<infile>|2.999.1}\n"
" converts dotted form to ASCII HEX DER output.\n"
" -C: Output as C-syntax.\n"
" -r: Handle the OID as relative and not absolute.\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" , sizeof(unsigned long) * 8);
return 1;
}
 
while (n < argc) {
if (!nAfterOption && argv[n][0] == '-') {
if (argv[n][1] == 'x') {
nMode = MODE_HEX_TO_DOT;
if (argv[n][2] != '\0') {
argv[n--] += 2;
nAfterOption = 1;
}
} else if (argv[n][1] == 'C') {
nMode = MODE_DOT_TO_HEX;
nCHex = true;
 
if (argv[n][2] != '\0') {
argv[n--] += 2;
nAfterOption = 1;
}
} else if (argv[n][1] == 'r') {
nMode = MODE_DOT_TO_HEX;
isRelative = true;
 
if (argv[n][2] != '\0') {
argv[n--] += 2;
nAfterOption = 1;
}
} else if (argv[n][1] == 'o') {
if (argv[n][2] != '\0') {
fOutName = &argv[n][2];
} else if (n < argc-1) {
fOutName = argv[++n];
} else {
fprintf(stderr, "Incomplete command line.\n");
return EXIT_FAILURE;
}
} else if (argv[n][1] == 'i') {
if (argv[n][2] != '\0') {
fInName = &argv[n][2];
} else if (n < argc-1) {
fInName = argv[++n];
} else {
fprintf(stderr, "Incomplete command line.\n");
return EXIT_FAILURE;
}
}
} else {
if (fInName != NULL) { // TODO: (Unklar) Was bewirkt das? Auch für fOutName notwendig?
break;
}
 
nAfterOption = 1;
if (strlen(argv[n]) + strlen(abCommandLine) >= sizeof(abCommandLine)-2) { // TODO: warum -2 ?
// fprintf(stderr, "Command line too long.\n");
// return 2;
 
cli_size += CLI_EXPANSION_SIZE + strlen(argv[n]) + 1; // 1 = "."
abCommandLine = (char*) realloc(abCommandLine, cli_size);
if (abCommandLine == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
strcat(abCommandLine, argv[n]); // (fügt ein \0 automatisch an)
if (n != argc - 1 && nMode != MODE_HEX_TO_DOT) {
strcat(abCommandLine, ".");
}
}
n++;
}
 
if (fInName != NULL && nMode == MODE_HEX_TO_DOT) {
FILE *fIn = fopen(fInName, "rb");
size_t nRead = 0;
if (fIn == NULL) {
fprintf(stderr, "Unable to open input file %s.\n", fInName);
return 11;
}
nRead = fread(abCommandLine, 1, sizeof(abCommandLine), fIn);
abCommandLine[nRead] = '\0';
fclose(fIn);
} else if (fInName != NULL && nMode == MODE_DOT_TO_HEX) {
FILE *fIn = fopen(fInName, "rt");
if (fIn == NULL) {
fprintf(stderr, "Unable to open input file %s.\n", fInName);
return 11;
}
fgets(abCommandLine, sizeof(abCommandLine), fIn);
fclose(fIn);
}
 
while (nMode == MODE_HEX_TO_DOT) { /* better if */
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine);*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t ll;
mpz_init(ll);
#else
unsigned long ll = 0;
#endif
bool fOK = false;
int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
while (*p) {
if (*p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
*q++ = *p;
}
p++;
}
*q = '\0';
 
if (strlen(abCommandLine) % 2 != 0) {
fprintf(stderr, "Encoded OID must have even number of hex digits!\n");
return 2;
}
 
if (strlen(abCommandLine) < 3) {
fprintf(stderr, "Encoded OID must have at least three bytes!\n");
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while (*p) {
unsigned char b;
 
// This allows also C-notation
if ((p[0] == '\\') && (p[1] == 'x')) {
p += 2;
continue;
}
 
// Interpret upper nibble
if (p[0] >= 'A' && p[0] <= 'F') {
b = (p[0] - 'A' + 10) * 16;
} else if (p[0] >= 'a' && p[0] <= 'f') {
b = (p[0] - 'a' + 10) * 16;
} else if (p[0] >= '0' && p[0] <= '9') {
b = (p[0] - '0') * 16;
} else {
fprintf(stderr, "Must have hex digits only!\n");
return 2;
}
 
// Interpret lower nibble
if (p[1] >= 'A' && p[1] <= 'F') {
b += (p[1] - 'A' + 10);
} else if (p[1] >= 'a' && p[1] <= 'f') {
b += (p[1] - 'a' + 10);
} else if (p[1] >= '0' && p[1] <= '9') {
b += (p[1] - '0');
} else {
fprintf(stderr, "Must have hex digits only!\n");
return 2;
}
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
 
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine);*/
 
if (fOutName != NULL) {
fOut = fopen(fOutName, "wt");
if (fOut == NULL) {
fprintf(stderr, "Unable to open output file %s\n", fOutName);
return 33;
}
} else {
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
#ifdef is_gmp
mpz_init(ll);
#else
ll = 0;
#endif
fOK = false;
fSub = 0;
 
// 0 = Universal Class Identifier Tag (can be more than 1 byte, but not in our case)
// 1 = Length part (may have more than 1 byte!)
// 2 = First two arc encoding
// 3 = Encoding of arc three and higher
unsigned char part = 0;
 
unsigned char lengthbyte_count = 0;
unsigned char lengthbyte_pos = 0;
bool lengthfinished = false;
 
bool arcBeginning = true;
bool firstWrittenArc = true;
 
while (nn < nBinary) {
if (part == 0) { // Class Tag
 
// Leading octet
// Bit 7 / Bit 6 = Universal (00), Application (01), Context (10), Private(11)
// Bit 5 = Primitive (0), Constructed (1)
// Bit 4..0 = 00000 .. 11110 => Tag 0..30, 11111 for Tag > 30 (following bytes with the highest bit as "more" bit)
// --> We don't need to respect 11111 (class-tag encodes in more than 1 octet)
// as we terminate when the tag is not of type OID or RELATEIVE-OID
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
// Class: 8. - 7. bit
// 0 (00) = Universal
// 1 (01) = Application
// 2 (10) = Context
// 3 (11) = Private
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
if (cl != 0) {
fprintf(stderr, "\nError at type: The OID tags are only defined as UNIVERSAL class tags.\n");
fprintf(fOut, "\n");
return 6;
}
 
// Primitive/Constructed: 6. bit
// 0 = Primitive
// 1 = Constructed
unsigned char pc = *pb & 0x20;
if (pc != 0) {
fprintf(stderr, "\nError at type: OIDs must be primitive, not constructed.\n");
fprintf(fOut, "\n");
return 6;
}
 
// Tag number: 5. - 1. bit
unsigned char tag = *pb & 0x1F;
if (tag == 0x0D) {
isRelative = true;
} else if (tag == 0x06) {
isRelative = false;
} else {
fprintf(stderr, "\nError at type: The tag number is neither an absolute OID (0x06) nor a relative OID (0x0D).\n");
fprintf(fOut, "\n");
return 6;
}
 
// Output
if (isRelative) {
fprintf(fOut, "RELATIVE");
} else {
fprintf(fOut, "ABSOLUTE");
}
 
fprintf(fOut, " OID");
part++;
} else if (part == 1) { // Length
 
// Find out the length and save it into ll
 
// [length] is encoded as follows:
// 0x00 .. 0x7F = The actual length is in this byte, followed by [data].
// 0x80 + n = The length of [data] is spread over the following 'n' bytes. (0 < n < 0x7F)
// 0x80 = "indefinite length" (only constructed form) -- Invalid
// 0xFF = Reserved for further implementations -- Invalid
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
if (nn == 1) { // The first length byte
lengthbyte_pos = 0;
if ((*pb & 0x80) != 0) {
// 0x80 + n => The length is spread over the following 'n' bytes
lengthfinished = false;
lengthbyte_count = *pb & 0x7F;
if (lengthbyte_count == 0x00) {
fprintf(stderr, "\nLength value 0x80 is invalid (\"indefinite length\") for primitive types.\n");
fprintf(fOut, "\n");
return 7;
} else if (lengthbyte_count == 0x7F) {
fprintf(stderr, "\nLength value 0xFF is reserved for further extensions.\n");
fprintf(fOut, "\n");
return 7;
}
fOK = false;
} else {
// 0x01 .. 0x7F => The actual length
 
if (*pb == 0x00) {
fprintf(stderr, "\nLength value 0x00 is invalid for an OID.\n");
fprintf(fOut, "\n");
return 7;
}
 
#ifdef is_gmp
mpz_set_ui(ll, *pb);
#else
ll = *pb;
#endif
lengthfinished = true;
lengthbyte_count = 0;
fOK = true;
}
} else {
if (lengthbyte_count > lengthbyte_pos) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x100);
mpz_add_ui(ll, ll, *pb);
#else
ll *= 0x100;
ll += *pb;
#endif
lengthbyte_pos++;
}
 
if (lengthbyte_count == lengthbyte_pos) {
lengthfinished = true;
fOK = true;
}
}
 
if (lengthfinished) { // The length is now in ll
#ifdef is_gmp
if (mpz_cmp_ui(ll, nBinary - 2 - lengthbyte_count) != 0) {
fprintf(fOut, "\n");
if (fOut != stdout) {
fclose(fOut);
}
fprintf(stderr, "\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll));
return 3;
}
mpz_set_ui(ll, 0); // reset for later usage
#else
if (ll != nBinary - 2 - lengthbyte_count) {
fprintf(fOut, "\n");
if (fOut != stdout) {
fclose(fOut);
}
fprintf(stderr, "\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll);
return 3;
}
ll = 0; // reset for later usage
#endif
fOK = true;
part++;
if (isRelative) part++; // Goto step 3!
}
} else if (part == 2) { // First two arcs
int first = *pb / 40;
int second = *pb % 40;
if (first > 2) {
first = 2;
fprintf(fOut, " %d", first);
firstWrittenArc = false;
arcBeginning = true;
 
if ((*pb & 0x80) != 0) {
// 2.48 and up => 2+ octets
// Output in "part 3"
 
if (arcBeginning && (*pb == 0x80)) {
fprintf(fOut, "\n");
if (fOut != stdout) {
fclose(fOut);
}
fprintf(stderr, "\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return 4;
} else {
arcBeginning = false;
}
 
#ifdef is_gmp
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll += (*pb & 0x7F);
#endif
fSub = 80;
fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
second = *pb - 80;
fprintf(fOut, ".%d", second);
arcBeginning = true;
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
fprintf(fOut, " %d.%d", first, second);
firstWrittenArc = false;
arcBeginning = true;
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
part++;
} else if (part == 3) { // Arc three and higher
if ((*pb & 0x80) != 0) {
if (arcBeginning && (*pb == 0x80)) {
fprintf(fOut, "\n");
if (fOut != stdout) {
fclose(fOut);
}
fprintf(stderr, "\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return 4;
} else {
arcBeginning = false;
}
 
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x80);
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll *= 0x80;
ll += (*pb & 0x7F);
#endif
fOK = false;
} else {
fOK = true;
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x80);
mpz_add_ui(ll, ll, *pb);
mpz_sub_ui(ll, ll, fSub);
if (firstWrittenArc) {
fprintf(fOut, " %s", mpz_get_str(NULL, 10, ll));
firstWrittenArc = false;
} else {
fprintf(fOut, ".%s", mpz_get_str(NULL, 10, ll));
}
// Happens only if 0x80 paddings are allowed
// fOK = mpz_cmp_ui(ll, 0) >= 0;
mpz_set_ui(ll, 0);
#else
ll *= 0x80;
ll += *pb;
ll -= fSub;
if (firstWrittenArc) {
fprintf(fOut, " %lu", ll);
firstWrittenArc = false;
} else {
fprintf(fOut, ".%lu", ll);
}
// Happens only if 0x80 paddings are allowed
// fOK = ll >= 0;
ll = 0;
#endif
fSub = 0;
arcBeginning = true;
}
}
 
pb++;
nn++;
}
 
if (!fOK) {
fprintf(fOut, "\n");
if (fOut != stdout) {
fclose(fOut);
}
fprintf(stderr, "\nEncoding error. The OID is not constructed properly.\n");
return 4;
} else {
fprintf(fOut, "\n");
}
 
if (fOut != stdout) {
fclose(fOut);
}
break;
};
 
while (nMode == MODE_DOT_TO_HEX) { /* better if */
/* dotted->hex */
/* printf("OID %s\n", abCommandLine); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t l;
#else
unsigned long l = 0;
#endif
bool isjoint = false;
 
// Alternative call: ./oid RELATIVE.2.999
if (__STRNICMP_LOCAL(p, "ABSOLUTE.", 9) == 0) {
isRelative = false;
p+=9;
} else if (__STRNICMP_LOCAL(p, "RELATIVE.", 9) == 0) {
isRelative = true;
p+=9;
} else {
// use the CLI option
// isRelative = false;
}
 
cl = 0x00; // Class. Always UNIVERSAL (00)
 
// Tag for Universal Class
if (isRelative) {
cl |= 0x0D;
} else {
cl |= 0x06;
}
 
/* if (__STRNICMP_LOCAL(p, "OID.", 4) == 0) {
p+=4;
} */
 
q = p;
nPieces = 1;
while (*p) {
if (*p == '.') {
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while (n < nPieces) {
q = p;
while (*p) {
if (*p == '.') {
break;
}
p++;
}
 
#ifdef is_gmp
mpz_init(l);
#else
l = 0;
#endif
if (*p == '.') {
*p = 0;
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi(q);
#endif
q = p+1;
p = q;
} else {
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi(q);
#endif
q = p;
}
 
/* Digit is in l. */
if ((!isRelative) && (n == 0)) {
#ifdef is_gmp
if (mpz_cmp_ui(l, 2) > 0) {
#else
if (l > 2) {
#endif
fprintf(stderr, "\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
return 5;
}
#ifdef is_gmp
b += 40 * mpz_get_ui(l);
isjoint = mpz_cmp_ui(l, 2) == 0;
#else
b = 40 * ((unsigned char)l);
isjoint = l == 2;
#endif
} else if ((!isRelative) && (n == 1)) {
#ifdef is_gmp
if ((!isjoint) && (mpz_cmp_ui(l, 39) > 0)) {
#else
if ((l > 39) && (!isjoint)) {
#endif
fprintf(stderr, "\nEncoding error. The second arc is limited to 0..39 for root arcs 0 and 1.\n");
return 5;
}
 
#ifdef is_gmp
if (mpz_cmp_ui(l, 47) > 0) {
mpz_add_ui(l, l, 80);
MakeBase128(l, 1);
} else {
b += mpz_get_ui(l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#else
if (l > 47) {
l += 80;
MakeBase128(l, 1);
} else {
b += ((unsigned char) l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#endif
} else {
MakeBase128(l, 1);
}
n++;
}
 
if ((!isRelative) && (n < 2)) {
fprintf(stderr, "\nEncoding error. The minimum depth of an encodeable absolute OID is 2. (e.g. 2.999)\n");
return 5;
}
 
if (fOutName != NULL) {
fOut = fopen(fOutName, "wt");
if (fOut == NULL) {
fprintf(stderr, "Unable to open output file %s\n", fOutName);
return 33;
}
} else {
fOut = stdout;
}
 
// Write class-tag
if (nCHex) {
fprintf(fOut, "\"\\x%02X", cl);
} else {
fprintf(fOut, "%02X ", cl);
}
 
// Write length
if (nBinary <= 0x7F) {
if (nCHex) {
fprintf(fOut, "\\x%02X", nBinary);
} else {
fprintf(fOut, "%02X ", nBinary);
}
} else {
unsigned int nBinaryWork;
unsigned int lengthCount = 0;
 
nBinaryWork = nBinary;
do {
lengthCount++;
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
 
if (lengthCount >= 0x7F) {
fprintf(stderr, "\nThe length cannot be encoded.\n");
return 8;
}
 
if (nCHex) {
fprintf(fOut, "\\x%02X", 0x80 + lengthCount);
} else {
fprintf(fOut, "%02X ", 0x80 + lengthCount);
}
 
nBinaryWork = nBinary;
do {
if (nCHex) {
fprintf(fOut, "\\x%02X", nBinaryWork & 0xFF);
} else {
fprintf(fOut, "%02X ", nBinaryWork & 0xFF);
}
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
}
 
nn = 0;
while (nn < nBinary) {
unsigned char b = abBinary[nn++];
if (nn == nBinary) {
if (nCHex) {
fprintf(fOut, "\\x%02X\"\n", b);
} else {
fprintf(fOut, "%02X\n", b);
}
} else {
if (nCHex) {
fprintf(fOut, "\\x%02X", b);
} else {
fprintf(fOut, "%02X ", b);
}
}
}
if (fOut != stdout) {
fclose(fOut);
}
break;
}
 
free(abCommandLine);
free(abBinary);
 
return 0;
}
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/old/oid_11.c
0,0 → 1,498
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.1$ */
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
char abCommandLine[256];
unsigned char abBinary[128];
unsigned int nBinary = 0;
 
 
static void MakeBase128( unsigned long l, int first )
{
if( l > 127 )
{
MakeBase128( l / 128, 0 );
}
l %= 128;
if( first )
{
abBinary[nBinary++] = (unsigned char)l;
}
else
{
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
 
int main( int argc, char **argv )
{
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = 0; /* dotted->hex */
int nCHex = 0;
int nAfterOption = 0;
 
if( argc == 1 )
{
fprintf( stderr,
"OID encoder/decoder - Matthias Gaertner 1999/2001 - Freeware\n"
"Usage:\n"
" OID [-C] [-o<outfile>] {-i<infile>|1.2.3.4}\n"
" converts dotted form to ASCII HEX DER output.\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" );
return 1;
}
 
while( n < argc )
{
if( !nAfterOption && argv[n][0] == '-' )
{
if( argv[n][1] == 'x' )
{
nMode = 1; /* hex->dotted */
if( argv[n][2] != '\0' )
{
argv[n--] += 2;
nAfterOption = 1;
}
}
else if( argv[n][1] == 'C' )
{
nMode = 0;
nCHex = 1;
 
if( argv[n][2] != '\0' )
{
argv[n--] += 2;
nAfterOption = 1;
}
}
else if( argv[n][1] == 'o' )
{
if( argv[n][2] != '\0' )
{
fOutName = &argv[n][2];
}
else if( n < argc-1 )
{
fOutName = argv[++n];
}
else
{
fprintf(stderr,"Incomplete command line.\n");
}
}
else if( argv[n][1] == 'i' )
{
if( argv[n][2] != '\0' )
{
fInName = &argv[n][2];
}
else if( n < argc-1 )
{
fInName = argv[++n];
}
else
{
fprintf(stderr,"Incomplete command line.\n");
}
}
}
else
{
if( fInName != NULL )
{
break;
}
 
nAfterOption = 1;
if( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 )
{
fprintf(stderr,"Command line too long.\n");
return 2;
}
strcat( abCommandLine, argv[n] );
if( n != argc - 1 && nMode != 1 )
{
strcat( abCommandLine, "." );
}
}
n++;
}
 
if( fInName != NULL && nMode == 1 )
{
FILE *fIn = fopen( fInName, "rb" );
size_t nRead = 0;
if( fIn == NULL )
{
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
abCommandLine[nRead] = '\0';
fclose( fIn );
}
else if( fInName != NULL && nMode == 0 )
{
FILE *fIn = fopen( fInName, "rt" );
if( fIn == NULL )
{
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
fgets( abCommandLine, sizeof(abCommandLine), fIn );
fclose( fIn );
}
 
while( nMode == 1 ) /* better if */
{
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine );*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
unsigned long ll = 0;
int fOK = 0;
 
while( *p )
{
if( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t')
{
*q++ = *p;
}
p++;
}
*q = '\0';
 
if( strlen( abCommandLine ) % 2 != 0 )
{
fprintf(stderr, "OID must have even number of hex digits!\n" );
return 2;
}
 
if( strlen( abCommandLine ) < 3 )
{
fprintf(stderr, "OID must have at least three bytes!\n" );
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while( *p )
{
unsigned char b;
if( p[0] >= 'A' && p[0] <= 'F' )
{
b = (p[0] - 'A' + 10) * 16;
}
else if( p[0] >= 'a' && p[0] <= 'f' )
{
b = (p[0] - 'a' + 10) * 16;
}
else if( p[0] >= '0' && p[0] <= '9' )
{
b = (p[0] - '0') * 16;
}
else
{
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
if( p[1] >= 'A' && p[1] <= 'F' ||
p[1] >= 'a' && p[1] <= 'f' )
{
b += (p[1] - 'A' + 10);
}
else if( p[1] >= '0' && p[1] <= '9' )
{
b += (p[1] - '0');
}
else
{
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine );*/
 
if( fOutName != NULL )
{
fOut = fopen( fOutName, "wt" );
if( fOut == NULL )
{
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
}
else
{
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
ll = 0;
fOK = 0;
while( nn < nBinary )
{
if( nn == 0 )
{
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
switch( cl )
{
default:
case 0: fprintf(fOut,"UNIVERSAL"); break;
case 1: fprintf(fOut,"APPLICATION"); break;
case 2: fprintf(fOut,"CONTEXT"); break;
case 3: fprintf(fOut,"PRIVATE"); break;
}
fprintf(fOut," OID");
}
else if( nn == 1 )
{
if( nBinary - 2 != *pb )
{
if( fOut != stdout )
{
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d)\n", *pb );
return 3;
}
}
else if( nn == 2 )
{
fprintf(fOut,".%d.%d", *pb / 40, *pb % 40 );
fOK = 1;
ll = 0;
}
else if( (*pb & 0x80) != 0 )
{
ll *= 128;
ll += (*pb & 0x7F);
fOK = 0;
}
else
{
ll *= 128;
ll += *pb;
fOK = 1;
 
fprintf(fOut,".%lu", ll );
ll = 0;
}
 
pb++;
nn++;
}
 
if( !fOK )
{
fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
return 4;
}
else
{
fprintf(fOut,"\n");
}
 
if( fOut != stdout )
{
fclose( fOut );
}
break;
};
 
while( nMode == 0 ) /* better if */
{
/* dotted->hex */
/* printf("OID.%s\n", abCommandLine ); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
unsigned long l = 0;
 
if( __STRNICMP_LOCAL( p, "UNIVERSAL.", 10 ) == 0 )
{
p+=10;
}
else if( __STRNICMP_LOCAL( p, "APPLICATION.", 12 ) == 0 )
{
cl = 0x40;
p+=12;
}
else if( __STRNICMP_LOCAL( p, "CONTEXT.", 8 ) == 0 )
{
cl = 0x80;
p+=8;
}
else if( __STRNICMP_LOCAL( p, "PRIVATE.", 8 ) == 0 )
{
cl = 0xC0;
p+=8;
}
if( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 )
{
p+=4;
}
 
q = p;
nPieces = 1;
while( *p )
{
if( *p == '.' )
{
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while( n < nPieces )
{
q = p;
while( *p )
{
if( *p == '.' )
{
break;
}
p++;
}
 
l = 0;
if( *p == '.' )
{
*p = 0;
l = (unsigned long) atoi( q );
q = p+1;
p = q;
}
else
{
l = (unsigned long) atoi( q );
q = p;
}
 
/* Digit is in l. */
if( n == 0 )
{
b = 40 * ((unsigned char)l);
}
else if( n == 1 )
{
b += ((unsigned char) l);
abBinary[nBinary++] = b;
}
else
{
MakeBase128( l, 1 );
}
n++;
}
 
if( fOutName != NULL )
{
fOut = fopen( fOutName, "wt" );
if( fOut == NULL )
{
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
}
else
{
fOut = stdout;
}
 
if( nCHex )
{
fprintf(fOut,"\"\\x%02X\\x%02X", cl | 6, nBinary );
}
else
{
fprintf(fOut,"%02X %02X ", cl | 6, nBinary );
}
nn = 0;
while( nn < nBinary )
{
unsigned char b = abBinary[nn++];
if( nn == nBinary )
{
if( nCHex )
{
fprintf(fOut,"\\x%02X\"\n", b );
}
else
{
fprintf(fOut,"%02X\n", b );
}
}
else
{
if( nCHex )
{
fprintf(fOut,"\\x%02X", b );
}
else
{
fprintf(fOut,"%02X ", b );
}
}
}
if( fOut != stdout )
{
fclose( fOut );
}
break;
}
 
return 0;
}
 
/* */
 
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/old/oid_12.c
0,0 → 1,555
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### Enhanced version by Daniel Marschall, ViaThinkSoft 06/2011 ###
### -- NEW: 2.48 can also be encoded! ###
### -- NEW: UUIDs (128-bit) are now supported! (requires GMPLib) ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c -lgmp -lm ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c (??? unknown: gmp library) ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.2$ */
 
// PROBLEMS:
// - A wrong error message is shown when trying to encode "-0.0" or "x"
// - OIDs with length > 7F are not parsed... (80 95)
 
// NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
// - Remove command line limitation (to allow unlimited long OIDs)
// - The length of the OID could also be GMP and not long, to make real infinite long OIDs.
 
// NICE TO HAVE:
// - makefile / linuxpackage
// - better make functions instead of putting everything in main() with fprintf...
 
// -------------------------------------------------------
 
// Allows OIDs which are bigger than "long"
// Compile with "gcc oid.c -lgmp -lm"
#define is_gmp
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifdef is_gmp
#include <gmp.h>
#endif
 
#include <stdbool.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
char abCommandLine[1024];
unsigned char abBinary[128];
unsigned int nBinary = 0;
 
 
#ifdef is_gmp
static void MakeBase128( mpz_t l, int first )
{
if ( mpz_cmp_si(l, 127) > 0 ) {
mpz_t l2;
mpz_init(l2);
mpz_div_ui(l2, l, 128);
MakeBase128( l2 , 0 );
}
mpz_mod_ui(l, l, 128);
if ( first ) {
abBinary[nBinary++] = mpz_get_ui(l);
} else {
abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
}
}
#else
static void MakeBase128( unsigned long l, int first )
{
if ( l > 127 ) {
MakeBase128( l / 128, 0 );
}
l %= 128;
if ( first ) {
abBinary[nBinary++] = (unsigned char)l;
} else {
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
#endif
 
int main( int argc, char **argv ) {
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = 0; /* dotted->hex */
int nCHex = 0;
int nAfterOption = 0;
 
if ( argc == 1 ) {
fprintf( stderr,
"OID encoder/decoder 1.2 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
#ifdef is_gmp
"GMP Edition\n"
#endif
"\nUsage:\n"
" OID [-C] [-o<outfile>] {-i<infile>|1.2.3.4}\n"
" converts dotted form to ASCII HEX DER output.\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" );
return 1;
}
 
while ( n < argc ) {
if ( !nAfterOption && argv[n][0] == '-' ) {
if ( argv[n][1] == 'x' ) {
nMode = 1; /* hex->dotted */
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'C' ) {
nMode = 0;
nCHex = 1;
 
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'o' ) {
if ( argv[n][2] != '\0' ) {
fOutName = &argv[n][2];
} else if ( n < argc-1 ) {
fOutName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
}
} else if ( argv[n][1] == 'i' ) {
if ( argv[n][2] != '\0' ) {
fInName = &argv[n][2];
} else if ( n < argc-1 ) {
fInName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
}
}
} else {
if ( fInName != NULL ) {
break;
}
 
nAfterOption = 1;
if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
fprintf(stderr,"Command line too long.\n");
return 2;
}
strcat( abCommandLine, argv[n] );
if ( n != argc - 1 && nMode != 1 ) {
strcat( abCommandLine, "." );
}
}
n++;
}
 
if ( fInName != NULL && nMode == 1 ) {
FILE *fIn = fopen( fInName, "rb" );
size_t nRead = 0;
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
abCommandLine[nRead] = '\0';
fclose( fIn );
} else if ( fInName != NULL && nMode == 0 ) {
FILE *fIn = fopen( fInName, "rt" );
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
fgets( abCommandLine, sizeof(abCommandLine), fIn );
fclose( fIn );
}
 
while ( nMode == 1 ) /* better if */
{
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine );*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t ll;
mpz_init(ll);
#else
unsigned long ll = 0;
#endif
bool fOK = false;
int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
while ( *p ) {
if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
*q++ = *p;
}
p++;
}
*q = '\0';
 
if ( strlen( abCommandLine ) % 2 != 0 ) {
fprintf(stderr, "OID must have even number of hex digits!\n" );
return 2;
}
 
if ( strlen( abCommandLine ) < 3 ) {
fprintf(stderr, "OID must have at least three bytes!\n" );
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while ( *p ) {
unsigned char b;
 
if ( p[0] >= 'A' && p[0] <= 'F' ) {
b = (p[0] - 'A' + 10) * 16;
} else if ( p[0] >= 'a' && p[0] <= 'f' ) {
b = (p[0] - 'a' + 10) * 16;
} else if ( p[0] >= '0' && p[0] <= '9' ) {
b = (p[0] - '0') * 16;
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
if ( p[1] >= 'A' && p[1] <= 'F' || p[1] >= 'a' && p[1] <= 'f' ) {
b += (p[1] - 'A' + 10);
} else if ( p[1] >= '0' && p[1] <= '9' ) {
b += (p[1] - '0');
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine );*/
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
#ifdef is_gmp
mpz_init(ll);
#else
ll = 0;
#endif
fOK = false;
fSub = 0;
while ( nn < nBinary ) {
if ( nn == 0 ) {
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
switch ( cl ) {
default:
case 0: fprintf(fOut,"UNIVERSAL"); break;
case 1: fprintf(fOut,"APPLICATION"); break;
case 2: fprintf(fOut,"CONTEXT"); break;
case 3: fprintf(fOut,"PRIVATE"); break;
}
fprintf(fOut," OID");
} else if ( nn == 1 ) {
if ( nBinary - 2 != *pb ) {
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d)\n", *pb );
fprintf(fOut,"\n");
return 3;
}
} else if ( nn == 2 ) {
int first = *pb / 40;
int second = *pb % 40;
if (first > 2) {
first = 2;
fprintf(fOut,".%d", first );
 
if ( (*pb & 0x80) != 0 ) {
// 2.48 and up => 2+ octets
#ifdef is_gmp
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll += (*pb & 0x7F);
#endif
fSub = 80;
fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
second = *pb - 80;
fprintf(fOut,".%d",second);
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
fprintf(fOut,".%d.%d", first, second );
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else if ( (*pb & 0x80) != 0 ) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll *= 128;
ll += (*pb & 0x7F);
#endif
fOK = false;
} else {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, *pb);
mpz_sub_ui(ll, ll, fSub);
fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
mpz_set_ui(ll, 0);
#else
ll *= 128;
ll += *pb;
ll -= fSub;
fprintf(fOut,".%lu", ll );
ll = 0;
#endif
fSub = 0;
fOK = true;
}
 
pb++;
nn++;
}
 
if ( !fOK ) {
fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
fprintf(fOut,"\n");
return 4;
} else {
fprintf(fOut,"\n");
}
 
if ( fOut != stdout ) {
fclose( fOut );
}
break;
};
 
while ( nMode == 0 ) /* better if */
{
/* dotted->hex */
/* printf("OID.%s\n", abCommandLine ); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t l;
#else
unsigned long l = 0;
#endif
bool isjoint = false;
 
if ( __STRNICMP_LOCAL( p, "UNIVERSAL.", 10 ) == 0 ) {
p+=10;
} else if ( __STRNICMP_LOCAL( p, "APPLICATION.", 12 ) == 0 ) {
cl = 0x40;
p+=12;
} else if ( __STRNICMP_LOCAL( p, "CONTEXT.", 8 ) == 0 ) {
cl = 0x80;
p+=8;
} else if ( __STRNICMP_LOCAL( p, "PRIVATE.", 8 ) == 0 ) {
cl = 0xC0;
p+=8;
}
 
if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
p+=4;
}
 
q = p;
nPieces = 1;
while ( *p ) {
if ( *p == '.' ) {
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while ( n < nPieces ) {
q = p;
while ( *p ) {
if ( *p == '.' ) {
break;
}
p++;
}
 
#ifdef is_gmp
mpz_init(l);
#else
l = 0;
#endif
if ( *p == '.' ) {
*p = 0;
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p+1;
p = q;
} else {
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p;
}
 
/* Digit is in l. */
if ( n == 0 ) {
#ifdef is_gmp
if (mpz_cmp_ui(l, 2) > 0) {
#else
if (l > 2) {
#endif
fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
return 5;
}
#ifdef is_gmp
b += 40 * mpz_get_ui(l);
isjoint = mpz_cmp_ui(l, 2) == 0;
#else
b = 40 * ((unsigned char)l);
isjoint = l == 2;
#endif
} else if ( n == 1 ) {
#ifdef is_gmp
if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
#else
if ((l > 39) && (!isjoint)) {
#endif
fprintf(stderr,"\nEncoding error. The second level is limited to 0..39 for top level arcs 0 and 1.\n");
return 5;
}
 
#ifdef is_gmp
if (mpz_cmp_ui(l, 47) > 0) {
mpz_add_ui(l, l, 80);
MakeBase128( l, 1 );
} else {
b += mpz_get_ui(l);
abBinary[nBinary++] = b;
}
#else
if (l > 47) {
l += 80;
MakeBase128( l, 1 );
} else {
b += ((unsigned char) l);
abBinary[nBinary++] = b;
}
#endif
} else {
MakeBase128( l, 1 );
}
n++;
}
 
if (n < 2) {
fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable OID is 2. (e.g. 2.999)\n");
return 5;
}
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
if ( nCHex ) {
fprintf(fOut,"\"\\x%02X\\x%02X", cl | 6, nBinary );
} else {
fprintf(fOut,"%02X %02X ", cl | 6, nBinary );
}
nn = 0;
while ( nn < nBinary ) {
unsigned char b = abBinary[nn++];
if ( nn == nBinary ) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X\"\n", b );
} else {
fprintf(fOut,"%02X\n", b );
}
} else {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", b );
} else {
fprintf(fOut,"%02X ", b );
}
}
}
if ( fOut != stdout ) {
fclose( fOut );
}
break;
}
 
return 0;
}
 
/* */
 
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/old/oid_13.c
0,0 → 1,644
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### ###
### Enhanced version by Daniel Marschall, ViaThinkSoft 06/2011 ###
### -- NEW 1.2: 2.48 can also be encoded! ###
### -- NEW 1.2: UUIDs (128-bit) are now supported! ###
### (requires GMPLib) ###
### -- NEW 1.3: Length can now have more than 1 byte ###
### -- AS WELL AS SEVERAL BUG FIXES ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c -lgmp -lm ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c (+ include gmp library) ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.3$ */
 
// MAJOR PROBLEMS:
// - Long OIDS: Buffer overflow in abBinary[] without any segfault?
 
// MINOR PROBLEMS:
// - A wrong error message is shown when trying to encode "-0.0" or "x"
 
// NICE TO HAVE:
// - makefile / linuxpackage
// - better make functions instead of putting everything in main() with fprintf...
 
// NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
// - Remove command line limitation (to allow unlimited long OIDs)
// - Is it possible to detect overflows and therefore output errors?
 
// -------------------------------------------------------
 
// Allows OIDs which are bigger than "long"
// Compile with "gcc oid.c -lgmp -lm"
#define is_gmp
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifdef is_gmp
#include <gmp.h>
#endif
 
#include <stdbool.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
char abCommandLine[4096]; // TODO: Supersize me
unsigned char abBinary[128]; // TODO: Supersize me (?)
unsigned int nBinary = 0;
 
 
#ifdef is_gmp
static void MakeBase128( mpz_t l, int first ) {
if ( mpz_cmp_si(l, 127) > 0 ) {
mpz_t l2;
mpz_init(l2);
mpz_div_ui(l2, l, 128);
MakeBase128( l2 , 0 );
}
mpz_mod_ui(l, l, 128);
if ( first ) {
abBinary[nBinary++] = mpz_get_ui(l);
} else {
abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
}
}
#else
static void MakeBase128( unsigned long l, int first ) {
if ( l > 127 ) {
MakeBase128( l / 128, 0 );
}
l %= 128;
if ( first ) {
abBinary[nBinary++] = (unsigned char)l;
} else {
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
#endif
 
int main( int argc, char **argv ) {
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = 0; /* dotted->hex */
int nCHex = 0;
int nAfterOption = 0;
 
if ( argc == 1 ) {
fprintf( stderr,
"OID encoder/decoder 1.3 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
#ifdef is_gmp
"GMP Edition\n"
#endif
"\nUsage:\n"
" OID [-C] [-o<outfile>] {-i<infile>|2.999.1}\n"
" converts dotted form to ASCII HEX DER output.\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" );
return 1;
}
 
while ( n < argc ) {
if ( !nAfterOption && argv[n][0] == '-' ) {
if ( argv[n][1] == 'x' ) {
nMode = 1; /* hex->dotted */
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'C' ) {
nMode = 0;
nCHex = 1;
 
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'o' ) {
if ( argv[n][2] != '\0' ) {
fOutName = &argv[n][2];
} else if ( n < argc-1 ) {
fOutName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
}
} else if ( argv[n][1] == 'i' ) {
if ( argv[n][2] != '\0' ) {
fInName = &argv[n][2];
} else if ( n < argc-1 ) {
fInName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
}
}
} else {
if ( fInName != NULL ) {
break;
}
 
nAfterOption = 1;
if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
fprintf(stderr,"Command line too long.\n");
return 2;
}
strcat( abCommandLine, argv[n] );
if ( n != argc - 1 && nMode != 1 ) {
strcat( abCommandLine, "." );
}
}
n++;
}
 
if ( fInName != NULL && nMode == 1 ) {
FILE *fIn = fopen( fInName, "rb" );
size_t nRead = 0;
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
abCommandLine[nRead] = '\0';
fclose( fIn );
} else if ( fInName != NULL && nMode == 0 ) {
FILE *fIn = fopen( fInName, "rt" );
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
fgets( abCommandLine, sizeof(abCommandLine), fIn );
fclose( fIn );
}
 
while ( nMode == 1 ) /* better if */
{
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine );*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t ll;
mpz_init(ll);
#else
unsigned long ll = 0;
#endif
bool fOK = false;
int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
while ( *p ) {
if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
*q++ = *p;
}
p++;
}
*q = '\0';
 
if ( strlen( abCommandLine ) % 2 != 0 ) {
fprintf(stderr, "Encoded OID must have even number of hex digits!\n" );
return 2;
}
 
if ( strlen( abCommandLine ) < 3 ) {
fprintf(stderr, "Encoded OID must have at least three bytes!\n" );
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while ( *p ) {
unsigned char b;
 
// Interpret upper nibble
if ( p[0] >= 'A' && p[0] <= 'F' ) {
b = (p[0] - 'A' + 10) * 16;
} else if ( p[0] >= 'a' && p[0] <= 'f' ) {
b = (p[0] - 'a' + 10) * 16;
} else if ( p[0] >= '0' && p[0] <= '9' ) {
b = (p[0] - '0') * 16;
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
// Interpret lower nibble
if ( p[1] >= 'A' && p[1] <= 'F' ) {
b += (p[1] - 'A' + 10);
} else if ( p[1] >= 'a' && p[1] <= 'f' ) {
b += (p[1] - 'a' + 10);
} else if ( p[1] >= '0' && p[1] <= '9' ) {
b += (p[1] - '0');
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine );*/
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
#ifdef is_gmp
mpz_init(ll);
#else
ll = 0;
#endif
fOK = false;
fSub = 0;
 
// 0 = Universal Class Identifier Tag
// 1 = Length part (may have more than 1 byte!)
// 2 = First two arc encoding
// 3 = Encoding of arc three and higher
unsigned char part = 0;
 
unsigned char lengthbyte_count = 0;
unsigned char lengthbyte_pos = 0;
bool lengthfinished = false;
 
while ( nn < nBinary ) {
if ( part == 0 ) { // Class Tag
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
switch ( cl ) {
default:
case 0: fprintf(fOut,"UNIVERSAL"); break;
case 1: fprintf(fOut,"APPLICATION"); break;
case 2: fprintf(fOut,"CONTEXT"); break;
case 3: fprintf(fOut,"PRIVATE"); break;
}
fprintf(fOut," OID");
part++;
} else if ( part == 1 ) { // Length
 
// Find out the length and save it into ll
 
// 2nd Byte
// 0x00 .. 0x7F => The actual length
// 0x80 + n => The length is spread over the following 'n' bytes
// (Unknown: Is 'n' limited or can it be until 0xFF is reached?)
// (Unknown: How is length=0x80 (=0 following bytes define the length) defined? Is it the same as 0x00?)
 
if (nn == 1) { // The first length byte
lengthbyte_pos = 0;
if ( (*pb & 0x80) != 0 ) {
// 0x80 + n => The length is spread over the following 'n' bytes
lengthfinished = false;
lengthbyte_count = *pb & 0x7F;
fOK = false;
} else {
// 0x00 .. 0x7F => The actual length
#ifdef is_gmp
mpz_set_ui(ll, *pb);
#else
ll = *pb;
#endif
lengthfinished = true;
lengthbyte_count = 0;
fOK = true;
}
} else {
if (lengthbyte_count > lengthbyte_pos) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x100);
mpz_add_ui(ll, ll, *pb);
#else
ll *= 0x100;
ll += *pb;
#endif
lengthbyte_pos++;
}
 
if (lengthbyte_count == lengthbyte_pos) {
lengthfinished = true;
fOK = true;
}
}
 
if (lengthfinished) { // The length is now in ll
#ifdef is_gmp
if ( mpz_cmp_ui(ll, nBinary - 2 - lengthbyte_count) != 0 ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll) );
return 3;
}
mpz_set_ui(ll, 0); // reset for later usage
#else
if ( ll != nBinary - 2 - lengthbyte_count ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll );
return 3;
}
ll = 0; // reset for later usage
#endif
fOK = true;
part++;
}
} else if ( part == 2 ) { // First two arcs
int first = *pb / 40;
int second = *pb % 40;
if (first > 2) {
first = 2;
fprintf(fOut,".%d", first );
 
if ( (*pb & 0x80) != 0 ) {
// 2.48 and up => 2+ octets
#ifdef is_gmp
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll += (*pb & 0x7F);
#endif
fSub = 80;
fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
second = *pb - 80;
fprintf(fOut,".%d",second);
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
fprintf(fOut,".%d.%d", first, second );
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
part++;
} else if ( part == 3 ) { // Arc three and higher
if ( (*pb & 0x80) != 0 ) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll *= 128;
ll += (*pb & 0x7F);
#endif
fOK = false;
} else {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, *pb);
mpz_sub_ui(ll, ll, fSub);
fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
mpz_set_ui(ll, 0);
#else
ll *= 128;
ll += *pb;
ll -= fSub;
fprintf(fOut,".%lu", ll );
ll = 0;
#endif
fSub = 0;
fOK = true;
}
}
 
pb++;
nn++;
}
 
if ( !fOK ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
return 4;
} else {
fprintf(fOut,"\n");
}
 
if ( fOut != stdout ) {
fclose( fOut );
}
break;
};
 
while ( nMode == 0 ) /* better if */
{
/* dotted->hex */
/* printf("OID.%s\n", abCommandLine ); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t l;
#else
unsigned long l = 0;
#endif
bool isjoint = false;
 
if ( __STRNICMP_LOCAL( p, "UNIVERSAL.", 10 ) == 0 ) {
p+=10;
} else if ( __STRNICMP_LOCAL( p, "APPLICATION.", 12 ) == 0 ) {
cl = 0x40;
p+=12;
} else if ( __STRNICMP_LOCAL( p, "CONTEXT.", 8 ) == 0 ) {
cl = 0x80;
p+=8;
} else if ( __STRNICMP_LOCAL( p, "PRIVATE.", 8 ) == 0 ) {
cl = 0xC0;
p+=8;
}
 
if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
p+=4;
}
 
q = p;
nPieces = 1;
while ( *p ) {
if ( *p == '.' ) {
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while ( n < nPieces ) {
q = p;
while ( *p ) {
if ( *p == '.' ) {
break;
}
p++;
}
 
#ifdef is_gmp
mpz_init(l);
#else
l = 0;
#endif
if ( *p == '.' ) {
*p = 0;
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p+1;
p = q;
} else {
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p;
}
 
/* Digit is in l. */
if ( n == 0 ) {
#ifdef is_gmp
if (mpz_cmp_ui(l, 2) > 0) {
#else
if (l > 2) {
#endif
fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
return 5;
}
#ifdef is_gmp
b += 40 * mpz_get_ui(l);
isjoint = mpz_cmp_ui(l, 2) == 0;
#else
b = 40 * ((unsigned char)l);
isjoint = l == 2;
#endif
} else if ( n == 1 ) {
#ifdef is_gmp
if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
#else
if ((l > 39) && (!isjoint)) {
#endif
fprintf(stderr,"\nEncoding error. The second level is limited to 0..39 for top level arcs 0 and 1.\n");
return 5;
}
 
#ifdef is_gmp
if (mpz_cmp_ui(l, 47) > 0) {
mpz_add_ui(l, l, 80);
MakeBase128( l, 1 );
} else {
b += mpz_get_ui(l);
abBinary[nBinary++] = b;
}
#else
if (l > 47) {
l += 80;
MakeBase128( l, 1 );
} else {
b += ((unsigned char) l);
abBinary[nBinary++] = b;
}
#endif
} else {
MakeBase128( l, 1 );
}
n++;
}
 
if (n < 2) {
fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable OID is 2. (e.g. 2.999)\n");
return 5;
}
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
if ( nCHex ) {
fprintf(fOut,"\"\\x%02X\\x%02X", cl | 6, nBinary );
} else {
fprintf(fOut,"%02X %02X ", cl | 6, nBinary );
}
nn = 0;
while ( nn < nBinary ) {
unsigned char b = abBinary[nn++];
if ( nn == nBinary ) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X\"\n", b );
} else {
fprintf(fOut,"%02X\n", b );
}
} else {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", b );
} else {
fprintf(fOut,"%02X ", b );
}
}
}
if ( fOut != stdout ) {
fclose( fOut );
}
break;
}
 
return 0;
}
 
/* */
 
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/old/oid_14.c
0,0 → 1,722
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### ###
### Enhanced version by Daniel Marschall, ViaThinkSoft 06/2011 ###
### -- NEW 1.2: 2.48 can also be encoded! ###
### -- NEW 1.2: UUIDs (128-bit) are now supported! ###
### (requires GMPLib) ###
### -- NEW 1.3: Length can now have more than 1 byte ###
### -- NEW 1.4: No command line limitation anymore. ###
### -- AS WELL AS SEVERAL BUG FIXES ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c -lgmp -lm ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c (+ include gmp library) ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.4$ */
 
// MINOR PROBLEMS:
// - A wrong error message is shown when trying to encode "-0.0" or "x"
 
// NICE TO HAVE:
// - makefile / linuxpackage
// - better make functions instead of putting everything in main() with fprintf...
 
// NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
// - Is it possible to detect integer overflows and therefore output errors?
 
// -------------------------------------------------------
 
// Allows OIDs which are bigger than "long"
// Compile with "gcc oid.c -lgmp -lm"
#define is_gmp
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifdef is_gmp
#include <gmp.h>
#endif
 
#include <stdbool.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
// char abCommandLine[4096];
const unsigned int CLI_INITIAL_SIZE = 1024;
const unsigned int CLI_EXPANSION_SIZE = 1024;
unsigned int cli_size;
char * abCommandLine;
 
// unsigned char abBinary[128];
const unsigned int ABB_INITIAL_SIZE = 1024;
const unsigned int ABB_EXPANSION_SIZE = 1024;
unsigned int abb_size;
unsigned char * abBinary;
 
unsigned int nBinary = 0;
 
 
#ifdef is_gmp
static void MakeBase128( mpz_t l, int first ) {
if ( mpz_cmp_si(l, 127) > 0 ) {
mpz_t l2;
mpz_init(l2);
mpz_div_ui(l2, l, 128);
MakeBase128( l2 , 0 );
}
mpz_mod_ui(l, l, 128);
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = mpz_get_ui(l);
} else {
abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
}
}
#else
static void MakeBase128( unsigned long l, int first ) {
if ( l > 127 ) {
MakeBase128( l / 128, 0 );
}
l %= 128;
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = (unsigned char)l;
} else {
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
#endif
 
int main( int argc, char **argv ) {
cli_size = CLI_INITIAL_SIZE;
abCommandLine = (char*) malloc(cli_size * sizeof(char*));
if (abCommandLine == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
abb_size = ABB_INITIAL_SIZE;
abBinary = (unsigned char*) malloc(abb_size * sizeof(unsigned char*));
if (abBinary == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
 
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = 0; /* dotted->hex */
int nCHex = 0;
int nAfterOption = 0;
 
if ( argc == 1 ) {
fprintf( stderr,
"OID encoder/decoder 1.4 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
#ifdef is_gmp
"GMP Edition\n"
#endif
"\nUsage:\n"
" OID [-C] [-o<outfile>] {-i<infile>|2.999.1}\n"
" converts dotted form to ASCII HEX DER output.\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" );
return 1;
}
 
while ( n < argc ) {
if ( !nAfterOption && argv[n][0] == '-' ) {
if ( argv[n][1] == 'x' ) {
nMode = 1; /* hex->dotted */
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'C' ) {
nMode = 0;
nCHex = 1;
 
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'o' ) {
if ( argv[n][2] != '\0' ) {
fOutName = &argv[n][2];
} else if ( n < argc-1 ) {
fOutName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
}
} else if ( argv[n][1] == 'i' ) {
if ( argv[n][2] != '\0' ) {
fInName = &argv[n][2];
} else if ( n < argc-1 ) {
fInName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
}
}
} else {
if ( fInName != NULL ) {
break;
}
 
nAfterOption = 1;
if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
// fprintf(stderr,"Command line too long.\n");
// return 2;
 
cli_size += CLI_EXPANSION_SIZE + strlen( argv[n] ) + 1; // 1 = "."
abCommandLine = (char*) realloc(abCommandLine, cli_size);
if (abCommandLine == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
// TODO: (Unklar) Wer garantiert, dass es mit "\0" abschließt?
}
strcat( abCommandLine, argv[n] );
if ( n != argc - 1 && nMode != 1 ) {
strcat( abCommandLine, "." );
}
}
n++;
}
 
if ( fInName != NULL && nMode == 1 ) {
FILE *fIn = fopen( fInName, "rb" );
size_t nRead = 0;
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
abCommandLine[nRead] = '\0';
fclose( fIn );
} else if ( fInName != NULL && nMode == 0 ) {
FILE *fIn = fopen( fInName, "rt" );
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
fgets( abCommandLine, sizeof(abCommandLine), fIn );
fclose( fIn );
}
 
while ( nMode == 1 ) /* better if */
{
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine );*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t ll;
mpz_init(ll);
#else
unsigned long ll = 0;
#endif
bool fOK = false;
int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
while ( *p ) {
if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
*q++ = *p;
}
p++;
}
*q = '\0';
 
if ( strlen( abCommandLine ) % 2 != 0 ) {
fprintf(stderr, "Encoded OID must have even number of hex digits!\n" );
return 2;
}
 
if ( strlen( abCommandLine ) < 3 ) {
fprintf(stderr, "Encoded OID must have at least three bytes!\n" );
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while ( *p ) {
unsigned char b;
 
// Interpret upper nibble
if ( p[0] >= 'A' && p[0] <= 'F' ) {
b = (p[0] - 'A' + 10) * 16;
} else if ( p[0] >= 'a' && p[0] <= 'f' ) {
b = (p[0] - 'a' + 10) * 16;
} else if ( p[0] >= '0' && p[0] <= '9' ) {
b = (p[0] - '0') * 16;
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
// Interpret lower nibble
if ( p[1] >= 'A' && p[1] <= 'F' ) {
b += (p[1] - 'A' + 10);
} else if ( p[1] >= 'a' && p[1] <= 'f' ) {
b += (p[1] - 'a' + 10);
} else if ( p[1] >= '0' && p[1] <= '9' ) {
b += (p[1] - '0');
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
 
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine );*/
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
#ifdef is_gmp
mpz_init(ll);
#else
ll = 0;
#endif
fOK = false;
fSub = 0;
 
// 0 = Universal Class Identifier Tag
// 1 = Length part (may have more than 1 byte!)
// 2 = First two arc encoding
// 3 = Encoding of arc three and higher
unsigned char part = 0;
 
unsigned char lengthbyte_count = 0;
unsigned char lengthbyte_pos = 0;
bool lengthfinished = false;
 
while ( nn < nBinary ) {
if ( part == 0 ) { // Class Tag
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
switch ( cl ) {
default:
case 0: fprintf(fOut,"UNIVERSAL"); break;
case 1: fprintf(fOut,"APPLICATION"); break;
case 2: fprintf(fOut,"CONTEXT"); break;
case 3: fprintf(fOut,"PRIVATE"); break;
}
fprintf(fOut," OID");
part++;
} else if ( part == 1 ) { // Length
 
// Find out the length and save it into ll
 
// 2nd Byte
// 0x00 .. 0x7F => The actual length
// 0x80 + n => The length is spread over the following 'n' bytes
// (Unknown: Is 'n' limited or can it be until 0xFF is reached?)
// (Unknown: How is length=0x80 (=0 following bytes define the length) defined? Is it the same as 0x00?)
 
if (nn == 1) { // The first length byte
lengthbyte_pos = 0;
if ( (*pb & 0x80) != 0 ) {
// 0x80 + n => The length is spread over the following 'n' bytes
lengthfinished = false;
lengthbyte_count = *pb & 0x7F;
fOK = false;
} else {
// 0x00 .. 0x7F => The actual length
#ifdef is_gmp
mpz_set_ui(ll, *pb);
#else
ll = *pb;
#endif
lengthfinished = true;
lengthbyte_count = 0;
fOK = true;
}
} else {
if (lengthbyte_count > lengthbyte_pos) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x100);
mpz_add_ui(ll, ll, *pb);
#else
ll *= 0x100;
ll += *pb;
#endif
lengthbyte_pos++;
}
 
if (lengthbyte_count == lengthbyte_pos) {
lengthfinished = true;
fOK = true;
}
}
 
if (lengthfinished) { // The length is now in ll
#ifdef is_gmp
if ( mpz_cmp_ui(ll, nBinary - 2 - lengthbyte_count) != 0 ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll) );
return 3;
}
mpz_set_ui(ll, 0); // reset for later usage
#else
if ( ll != nBinary - 2 - lengthbyte_count ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll );
return 3;
}
ll = 0; // reset for later usage
#endif
fOK = true;
part++;
}
} else if ( part == 2 ) { // First two arcs
int first = *pb / 40;
int second = *pb % 40;
if (first > 2) {
first = 2;
fprintf(fOut,".%d", first );
 
if ( (*pb & 0x80) != 0 ) {
// 2.48 and up => 2+ octets
#ifdef is_gmp
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll += (*pb & 0x7F);
#endif
fSub = 80;
fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
second = *pb - 80;
fprintf(fOut,".%d",second);
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
fprintf(fOut,".%d.%d", first, second );
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
part++;
} else if ( part == 3 ) { // Arc three and higher
if ( (*pb & 0x80) != 0 ) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll *= 128;
ll += (*pb & 0x7F);
#endif
fOK = false;
} else {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, *pb);
mpz_sub_ui(ll, ll, fSub);
fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
mpz_set_ui(ll, 0);
#else
ll *= 128;
ll += *pb;
ll -= fSub;
fprintf(fOut,".%lu", ll );
ll = 0;
#endif
fSub = 0;
fOK = true;
}
}
 
pb++;
nn++;
}
 
if ( !fOK ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
return 4;
} else {
fprintf(fOut,"\n");
}
 
if ( fOut != stdout ) {
fclose( fOut );
}
break;
};
 
while ( nMode == 0 ) /* better if */
{
/* dotted->hex */
/* printf("OID.%s\n", abCommandLine ); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t l;
#else
unsigned long l = 0;
#endif
bool isjoint = false;
 
if ( __STRNICMP_LOCAL( p, "UNIVERSAL.", 10 ) == 0 ) {
p+=10;
} else if ( __STRNICMP_LOCAL( p, "APPLICATION.", 12 ) == 0 ) {
cl = 0x40;
p+=12;
} else if ( __STRNICMP_LOCAL( p, "CONTEXT.", 8 ) == 0 ) {
cl = 0x80;
p+=8;
} else if ( __STRNICMP_LOCAL( p, "PRIVATE.", 8 ) == 0 ) {
cl = 0xC0;
p+=8;
}
 
if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
p+=4;
}
 
q = p;
nPieces = 1;
while ( *p ) {
if ( *p == '.' ) {
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while ( n < nPieces ) {
q = p;
while ( *p ) {
if ( *p == '.' ) {
break;
}
p++;
}
 
#ifdef is_gmp
mpz_init(l);
#else
l = 0;
#endif
if ( *p == '.' ) {
*p = 0;
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p+1;
p = q;
} else {
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p;
}
 
/* Digit is in l. */
if ( n == 0 ) {
#ifdef is_gmp
if (mpz_cmp_ui(l, 2) > 0) {
#else
if (l > 2) {
#endif
fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
return 5;
}
#ifdef is_gmp
b += 40 * mpz_get_ui(l);
isjoint = mpz_cmp_ui(l, 2) == 0;
#else
b = 40 * ((unsigned char)l);
isjoint = l == 2;
#endif
} else if ( n == 1 ) {
#ifdef is_gmp
if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
#else
if ((l > 39) && (!isjoint)) {
#endif
fprintf(stderr,"\nEncoding error. The second level is limited to 0..39 for top level arcs 0 and 1.\n");
return 5;
}
 
#ifdef is_gmp
if (mpz_cmp_ui(l, 47) > 0) {
mpz_add_ui(l, l, 80);
MakeBase128( l, 1 );
} else {
b += mpz_get_ui(l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#else
if (l > 47) {
l += 80;
MakeBase128( l, 1 );
} else {
b += ((unsigned char) l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#endif
} else {
MakeBase128( l, 1 );
}
n++;
}
 
if (n < 2) {
fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable OID is 2. (e.g. 2.999)\n");
return 5;
}
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
if ( nCHex ) {
fprintf(fOut,"\"\\x%02X\\x%02X", cl | 6, nBinary );
} else {
fprintf(fOut,"%02X %02X ", cl | 6, nBinary );
}
nn = 0;
while ( nn < nBinary ) {
unsigned char b = abBinary[nn++];
if ( nn == nBinary ) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X\"\n", b );
} else {
fprintf(fOut,"%02X\n", b );
}
} else {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", b );
} else {
fprintf(fOut,"%02X ", b );
}
}
}
if ( fOut != stdout ) {
fclose( fOut );
}
break;
}
 
free(abCommandLine);
free(abBinary);
 
return 0;
}
 
/* */
 
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/old/oid_17.c
0,0 → 1,860
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### ###
### Enhanced version by Daniel Marschall, ViaThinkSoft 06-07/2011 ###
### -- NEW 1.2: 2.48 can also be encoded! ###
### -- NEW 1.2: UUIDs (128-bit) are now supported! ###
### (requires GMPLib) ###
### -- NEW 1.3: Length can now have more than 1 byte ###
### -- NEW 1.4: No command line limitation anymore. ###
### -- NEW 1.5: Now also relative OIDs supported ###
### -- NEW 1.6: 0x80 paddings are now disallowed ###
### -- AS WELL AS SEVERAL BUG FIXES ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c -lgmp -lm ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c (+ include gmp library) ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.7$ */
 
// MINOR THINGS
// - All stderr: Output new line at stdOut and close stdOut
// - Make as much GMP as possible (e.g. nBinary counter)
 
// MINOR PROBLEMS IN CLI-INTERPRETATION:
// - A wrong error message is shown when trying to encode "-0.0" or "x"
// - 2.9a9 is not recognized as error
// - "./oid R 2.999" is not interpretet correctly
 
// NICE TO HAVE:
// - also allow -x to interpret "\x06\x02\x88\x37"
// - makefile / linuxpackage
// - better make functions instead of putting everything in main() with fprintf...
 
// NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
// - Is it possible to detect integer overflows and therefore output errors?
 
 
// -------------------------------------------------------
 
// Allows OIDs which are bigger than "long"
// Compile with "gcc oid.c -lgmp -lm"
#define is_gmp
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifdef is_gmp
#include <gmp.h>
#endif
 
#include <stdbool.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
// char abCommandLine[4096];
const unsigned int CLI_INITIAL_SIZE = 1024;
const unsigned int CLI_EXPANSION_SIZE = 1024;
unsigned int cli_size;
char * abCommandLine;
 
// unsigned char abBinary[128];
const unsigned int ABB_INITIAL_SIZE = 1024;
const unsigned int ABB_EXPANSION_SIZE = 1024;
unsigned int abb_size;
unsigned char * abBinary;
 
unsigned int nBinary = 0; // Future: Auch als GMP
 
 
#ifdef is_gmp
static void MakeBase128( mpz_t l, int first ) {
if ( mpz_cmp_si(l, 127) > 0 ) {
mpz_t l2;
mpz_init(l2);
mpz_div_ui(l2, l, 128);
MakeBase128( l2 , 0 );
}
mpz_mod_ui(l, l, 128);
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = mpz_get_ui(l);
} else {
abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
}
}
#else
static void MakeBase128( unsigned long l, int first ) {
if ( l > 127 ) {
MakeBase128( l / 128, 0 );
}
l %= 128;
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = (unsigned char)l;
} else {
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
#endif
 
int main( int argc, char **argv ) {
cli_size = CLI_INITIAL_SIZE;
abCommandLine = (char*) malloc(cli_size * sizeof(char*));
if (abCommandLine == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
abb_size = ABB_INITIAL_SIZE;
abBinary = (unsigned char*) malloc(abb_size * sizeof(unsigned char*));
if (abBinary == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
 
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = 0; /* dotted->hex */
int nCHex = 0;
int nAfterOption = 0;
bool isRelative = false;
 
if ( argc == 1 ) {
fprintf( stderr,
"OID encoder/decoder 1.7 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
#ifdef is_gmp
"GMP Edition\n"
#endif
"\nUsage:\n"
" OID [-C] [-o<outfile>] {-i<infile>|2.999.1}\n"
" converts dotted form to ASCII HEX DER output.\n"
" allowed OID syntax: [UNIVERSAL.|CONTEXT.|APPLICATION.|PRIVATE.][ABSOLUTE.|RELATIVE.]2.999\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" );
return 1;
}
 
while ( n < argc ) {
if ( !nAfterOption && argv[n][0] == '-' ) {
if ( argv[n][1] == 'x' ) {
nMode = 1; /* hex->dotted */
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'C' ) {
nMode = 0;
nCHex = 1;
 
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'o' ) {
if ( argv[n][2] != '\0' ) {
fOutName = &argv[n][2];
} else if ( n < argc-1 ) {
fOutName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n"); // TODO: exit?
}
} else if ( argv[n][1] == 'i' ) {
if ( argv[n][2] != '\0' ) {
fInName = &argv[n][2];
} else if ( n < argc-1 ) {
fInName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n"); // TODO: exit?
}
}
} else {
if ( fInName != NULL ) {
break;
}
 
nAfterOption = 1;
if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
// fprintf(stderr,"Command line too long.\n");
// return 2;
 
cli_size += CLI_EXPANSION_SIZE + strlen( argv[n] ) + 1; // 1 = "."
abCommandLine = (char*) realloc(abCommandLine, cli_size);
if (abCommandLine == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
// TODO: (Unklar) Wer garantiert, dass es mit "\0" abschließt?
}
strcat( abCommandLine, argv[n] );
if ( n != argc - 1 && nMode != 1 ) {
strcat( abCommandLine, "." );
}
}
n++;
}
 
if ( fInName != NULL && nMode == 1 ) {
FILE *fIn = fopen( fInName, "rb" );
size_t nRead = 0;
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
abCommandLine[nRead] = '\0';
fclose( fIn );
} else if ( fInName != NULL && nMode == 0 ) {
FILE *fIn = fopen( fInName, "rt" );
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
fgets( abCommandLine, sizeof(abCommandLine), fIn );
fclose( fIn );
}
 
while ( nMode == 1 ) /* better if */
{
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine );*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t ll;
mpz_init(ll);
#else
unsigned long ll = 0;
#endif
bool fOK = false;
int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
while ( *p ) {
if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
*q++ = *p;
}
p++;
}
*q = '\0';
 
if ( strlen( abCommandLine ) % 2 != 0 ) {
fprintf(stderr, "Encoded OID must have even number of hex digits!\n" );
return 2;
}
 
if ( strlen( abCommandLine ) < 3 ) {
fprintf(stderr, "Encoded OID must have at least three bytes!\n" );
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while ( *p ) {
unsigned char b;
 
// Interpret upper nibble
if ( p[0] >= 'A' && p[0] <= 'F' ) {
b = (p[0] - 'A' + 10) * 16;
} else if ( p[0] >= 'a' && p[0] <= 'f' ) {
b = (p[0] - 'a' + 10) * 16;
} else if ( p[0] >= '0' && p[0] <= '9' ) {
b = (p[0] - '0') * 16;
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
// Interpret lower nibble
if ( p[1] >= 'A' && p[1] <= 'F' ) {
b += (p[1] - 'A' + 10);
} else if ( p[1] >= 'a' && p[1] <= 'f' ) {
b += (p[1] - 'a' + 10);
} else if ( p[1] >= '0' && p[1] <= '9' ) {
b += (p[1] - '0');
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
 
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine );*/
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
#ifdef is_gmp
mpz_init(ll);
#else
ll = 0;
#endif
fOK = false;
fSub = 0;
 
// 0 = Universal Class Identifier Tag (can be more than 1 byte, but not in our case)
// 1 = Length part (may have more than 1 byte!)
// 2 = First two arc encoding
// 3 = Encoding of arc three and higher
unsigned char part = 0;
 
unsigned char lengthbyte_count = 0;
unsigned char lengthbyte_pos = 0;
bool lengthfinished = false;
 
while ( nn < nBinary ) {
if ( part == 0 ) { // Class Tag
 
// Leading octet
// Bit 7 / Bit 6 = Universal (00), Application (01), Context (10), Private(11)
// Bit 5 = Primitive (0), Constructed (1)
// Bit 4..0 = 00000 .. 11110 => Tag 0..30, 11111 for Tag > 30 (following bytes with the highest bit as "more" bit)
// --> We don't need to respect 11111 (class-tag encodes in more than 1 octet)
// as we terminate when the tag is not of type OID or RELATEIVE-OID
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
if ((*pb & 0x1F) == 0x0D) {
isRelative = true;
} else if ((*pb & 0x1F) == 0x06) {
isRelative = false;
} else {
fprintf(stderr,"\nError: The class tag is not an absolute OID (0x06) nor a relative OID (0x0D).\n");
fprintf(fOut,"\n");
return 6;
}
 
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
switch ( cl ) {
default:
case 0: fprintf(fOut,"UNIVERSAL"); break;
case 1: fprintf(fOut,"APPLICATION"); break;
case 2: fprintf(fOut,"CONTEXT"); break;
case 3: fprintf(fOut,"PRIVATE"); break;
}
 
if (isRelative) {
fprintf(fOut, " RELATIVE");
} else {
fprintf(fOut, " ABSOLUTE");
}
 
fprintf(fOut," OID");
part++;
} else if ( part == 1 ) { // Length
 
// Find out the length and save it into ll
 
// [length] is encoded as follows:
// 0x00 .. 0x7F = The actual length is in this byte, followed by [data].
// 0x80 + n = The length of [data] is spread over the following 'n' bytes. (0 < n < 0x7F)
// 0x80 = "indefinite length" (only constructed form) -- Invalid
// 0xFF = Reserved for further implementations -- Invalid
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
if (nn == 1) { // The first length byte
lengthbyte_pos = 0;
if ( (*pb & 0x80) != 0 ) {
// 0x80 + n => The length is spread over the following 'n' bytes
lengthfinished = false;
lengthbyte_count = *pb & 0x7F;
if (lengthbyte_count == 0x00) {
fprintf(stderr,"\nLength value 0x80 is invalid (\"indefinite length\") for primitive types.\n");
fprintf(fOut,"\n");
return 7;
} else if (lengthbyte_count == 0x7F) {
fprintf(stderr,"\nLength value 0xFF is reserved for further extensions.\n");
fprintf(fOut,"\n");
return 7;
}
fOK = false;
} else {
// 0x01 .. 0x7F => The actual length
 
if (*pb == 0x00) {
fprintf(stderr,"\nLength value 0x00 is invalid for an OID.\n");
fprintf(fOut,"\n");
return 7;
}
 
#ifdef is_gmp
mpz_set_ui(ll, *pb);
#else
ll = *pb;
#endif
lengthfinished = true;
lengthbyte_count = 0;
fOK = true;
}
} else {
if (lengthbyte_count > lengthbyte_pos) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x100);
mpz_add_ui(ll, ll, *pb);
#else
ll *= 0x100;
ll += *pb;
#endif
lengthbyte_pos++;
}
 
if (lengthbyte_count == lengthbyte_pos) {
lengthfinished = true;
fOK = true;
}
}
 
if (lengthfinished) { // The length is now in ll
#ifdef is_gmp
if ( mpz_cmp_ui(ll, nBinary - 2 - lengthbyte_count) != 0 ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll) );
return 3;
}
mpz_set_ui(ll, 0); // reset for later usage
#else
if ( ll != nBinary - 2 - lengthbyte_count ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll );
return 3;
}
ll = 0; // reset for later usage
#endif
fOK = true;
part++;
if (isRelative) part++; // Goto step 3!
}
} else if ( part == 2 ) { // First two arcs
int first = *pb / 40;
int second = *pb % 40;
if (first > 2) {
first = 2;
fprintf(fOut,".%d", first );
 
if ( (*pb & 0x80) != 0 ) {
// 2.48 and up => 2+ octets
// Output in "part 3"
 
if ((*pb & 0x7F) == 0) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See ITU-T Rec. X.690 8.19.2)\n");
return 4;
}
 
#ifdef is_gmp
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll += (*pb & 0x7F);
#endif
fSub = 80;
fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
second = *pb - 80;
fprintf(fOut,".%d",second);
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
fprintf(fOut,".%d.%d", first, second );
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
part++;
} else if ( part == 3 ) { // Arc three and higher
if ( (*pb & 0x80) != 0 ) {
 
if ((*pb & 0x7F) == 0) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See ITU-T Rec. X.690 8.19.2)\n");
return 4;
}
 
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll *= 128;
ll += (*pb & 0x7F);
#endif
fOK = false;
} else {
fOK = 1;
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, *pb);
mpz_sub_ui(ll, ll, fSub);
fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
// Happens only if 0x80 paddings are allowed
// fOK = mpz_cmp_ui(ll, 0 ) >= 0;
mpz_set_ui(ll, 0);
#else
ll *= 128;
ll += *pb;
ll -= fSub;
fprintf(fOut,".%lu", ll );
// Happens only if 0x80 paddings are allowed
// fOK = ll >= 0;
ll = 0;
#endif
fSub = 0;
}
}
 
pb++;
nn++;
}
 
if ( !fOK ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
return 4;
} else {
fprintf(fOut,"\n");
}
 
if ( fOut != stdout ) {
fclose( fOut );
}
break;
};
 
while ( nMode == 0 ) /* better if */
{
/* dotted->hex */
/* printf("OID.%s\n", abCommandLine ); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t l;
#else
unsigned long l = 0;
#endif
bool isjoint = false;
 
if ( __STRNICMP_LOCAL( p, "UNIVERSAL.", 10 ) == 0 ) {
p+=10;
} else if ( __STRNICMP_LOCAL( p, "APPLICATION.", 12 ) == 0 ) {
cl = 0x40;
p+=12;
} else if ( __STRNICMP_LOCAL( p, "CONTEXT.", 8 ) == 0 ) {
cl = 0x80;
p+=8;
} else if ( __STRNICMP_LOCAL( p, "PRIVATE.", 8 ) == 0 ) {
cl = 0xC0;
p+=8;
}
 
if ( __STRNICMP_LOCAL( p, "ABSOLUTE.", 9 ) == 0 ) {
isRelative = false;
p+=9;
} else if ( __STRNICMP_LOCAL( p, "RELATIVE.", 9 ) == 0 ) {
isRelative = true;
p+=9;
} else {
isRelative = false;
}
 
if ( isRelative ) {
cl |= 0x0D;
} else {
cl |= 0x06;
}
 
if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
p+=4;
}
 
q = p;
nPieces = 1;
while ( *p ) {
if ( *p == '.' ) {
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while ( n < nPieces ) {
q = p;
while ( *p ) {
if ( *p == '.' ) {
break;
}
p++;
}
 
#ifdef is_gmp
mpz_init(l);
#else
l = 0;
#endif
if ( *p == '.' ) {
*p = 0;
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p+1;
p = q;
} else {
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p;
}
 
/* Digit is in l. */
if (( n == 0 ) && (!isRelative)) {
#ifdef is_gmp
if (mpz_cmp_ui(l, 2) > 0) {
#else
if (l > 2) {
#endif
fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
return 5;
}
#ifdef is_gmp
b += 40 * mpz_get_ui(l);
isjoint = mpz_cmp_ui(l, 2) == 0;
#else
b = 40 * ((unsigned char)l);
isjoint = l == 2;
#endif
} else if (( n == 1 ) && (!isRelative)) {
#ifdef is_gmp
if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
#else
if ((l > 39) && (!isjoint)) {
#endif
fprintf(stderr,"\nEncoding error. The second arc is limited to 0..39 for root arcs 0 and 1.\n");
return 5;
}
 
#ifdef is_gmp
if (mpz_cmp_ui(l, 47) > 0) {
mpz_add_ui(l, l, 80);
MakeBase128( l, 1 );
} else {
b += mpz_get_ui(l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#else
if (l > 47) {
l += 80;
MakeBase128( l, 1 );
} else {
b += ((unsigned char) l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#endif
} else {
MakeBase128( l, 1 );
}
n++;
}
 
if (n < 2) {
fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable OID is 2. (e.g. 2.999)\n");
return 5;
}
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
// Write class-tag
if ( nCHex ) {
fprintf(fOut,"\"\\x%02X", cl );
} else {
fprintf(fOut,"%02X ", cl );
}
 
// Write length
if (nBinary <= 0x7F) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", nBinary );
} else {
fprintf(fOut,"%02X ", nBinary );
}
} else {
unsigned int nBinaryWork = 0; // TODO: GMP
unsigned int lengthCount = 0;
 
nBinaryWork = nBinary;
do {
lengthCount++;
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
 
if (lengthCount >= 0x7F) {
fprintf(stderr,"\nThe length cannot be encoded.\n");
return 8;
}
 
if ( nCHex ) {
fprintf(fOut,"\\x%02X", 0x80 + lengthCount );
} else {
fprintf(fOut,"%02X ", 0x80 + lengthCount );
}
 
nBinaryWork = nBinary;
do {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", nBinaryWork & 0xFF );
} else {
fprintf(fOut,"%02X ", nBinaryWork & 0xFF );
}
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
}
 
nn = 0;
while ( nn < nBinary ) {
unsigned char b = abBinary[nn++];
if ( nn == nBinary ) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X\"\n", b );
} else {
fprintf(fOut,"%02X\n", b );
}
} else {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", b );
} else {
fprintf(fOut,"%02X ", b );
}
}
}
if ( fOut != stdout ) {
fclose( fOut );
}
break;
}
 
free(abCommandLine);
free(abBinary);
 
return 0;
}
 
/* */
 
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/old/oid_18.c
0,0 → 1,859
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### ###
### Enhanced version by Daniel Marschall, ViaThinkSoft 06-07/2011 ###
### -- NEW 1.2: 2.48 can also be encoded! ###
### -- NEW 1.2: UUIDs (128-bit) are now supported! ###
### (requires GMPLib) ###
### -- NEW 1.3: Length can now have more than 1 byte ###
### -- NEW 1.4: No command line limitation anymore. ###
### -- NEW 1.5: Now also relative OIDs supported ###
### -- NEW 1.6: 0x80 paddings are now disallowed ###
### -- NEW 1.8: Removed Application/Context/Private "OID"s ###
### -- AS WELL AS SEVERAL BUG FIXES ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c -lgmp -lm ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c (+ include gmp library) ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.8$ */
 
// MINOR THINGS
// - All stderr: Output new line at stdOut and close stdOut
// - Make as much GMP as possible (e.g. nBinary counter)
// - überlegen, wie man die return-codes (errorcodes) besser verteilt/definiert
// - irgendwie in funktionen kapseln (z.b. class-tag-parser usw)
 
// MINOR PROBLEMS IN CLI-INTERPRETATION:
// - A wrong error message is shown when trying to encode "-0.0" or "x"
// - 2.9a9 is not recognized as error
// - "./oid R 2.999" is not interpretet correctly
 
// NICE TO HAVE:
// - also allow -x to interpret "\x06\x02\x88\x37"
// - makefile / linuxpackage
// - better make functions instead of putting everything in main() with fprintf...
 
// IDEAS
// - Instead of "RELATIVE" rather a "-r" option?
 
// NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
// - Is it possible to detect integer overflows and therefore output errors?
 
 
// -------------------------------------------------------
 
// Allows OIDs which are bigger than "long"
// Compile with "gcc oid.c -lgmp -lm"
#define is_gmp
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifdef is_gmp
#include <gmp.h>
#endif
 
#include <stdbool.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
// char abCommandLine[4096];
const unsigned int CLI_INITIAL_SIZE = 1024;
const unsigned int CLI_EXPANSION_SIZE = 1024;
unsigned int cli_size;
char * abCommandLine;
 
// unsigned char abBinary[128];
const unsigned int ABB_INITIAL_SIZE = 1024;
const unsigned int ABB_EXPANSION_SIZE = 1024;
unsigned int abb_size;
unsigned char * abBinary;
 
unsigned int nBinary = 0; // Future: Auch als GMP
 
 
#ifdef is_gmp
static void MakeBase128( mpz_t l, int first ) {
if ( mpz_cmp_si(l, 127) > 0 ) {
mpz_t l2;
mpz_init(l2);
mpz_div_ui(l2, l, 128);
MakeBase128( l2 , 0 );
}
mpz_mod_ui(l, l, 128);
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = mpz_get_ui(l);
} else {
abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
}
}
#else
static void MakeBase128( unsigned long l, int first ) {
if ( l > 127 ) {
MakeBase128( l / 128, 0 );
}
l %= 128;
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = (unsigned char)l;
} else {
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
#endif
 
int main( int argc, char **argv ) {
cli_size = CLI_INITIAL_SIZE;
abCommandLine = (char*) malloc(cli_size * sizeof(char*));
if (abCommandLine == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
abb_size = ABB_INITIAL_SIZE;
abBinary = (unsigned char*) malloc(abb_size * sizeof(unsigned char*));
if (abBinary == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
 
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = 0; /* dotted->hex */
int nCHex = 0;
int nAfterOption = 0;
bool isRelative = false;
 
if ( argc == 1 ) {
fprintf( stderr,
"OID encoder/decoder 1.8 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
#ifdef is_gmp
"GMP Edition\n"
#endif
"\nUsage:\n"
" OID [-C] [-o<outfile>] {-i<infile>|2.999.1}\n"
" converts dotted form to ASCII HEX DER output.\n"
" allowed OID syntax: [ABSOLUTE.|RELATIVE.]2.999\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" );
return 1;
}
 
while ( n < argc ) {
if ( !nAfterOption && argv[n][0] == '-' ) {
if ( argv[n][1] == 'x' ) {
nMode = 1; /* hex->dotted */
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'C' ) {
nMode = 0;
nCHex = 1;
 
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'o' ) {
if ( argv[n][2] != '\0' ) {
fOutName = &argv[n][2];
} else if ( n < argc-1 ) {
fOutName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n"); // TODO: exit?
}
} else if ( argv[n][1] == 'i' ) {
if ( argv[n][2] != '\0' ) {
fInName = &argv[n][2];
} else if ( n < argc-1 ) {
fInName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n"); // TODO: exit?
}
}
} else {
if ( fInName != NULL ) {
break;
}
 
nAfterOption = 1;
if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
// fprintf(stderr,"Command line too long.\n");
// return 2;
 
cli_size += CLI_EXPANSION_SIZE + strlen( argv[n] ) + 1; // 1 = "."
abCommandLine = (char*) realloc(abCommandLine, cli_size);
if (abCommandLine == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
// TODO: (Unklar) Wer garantiert, dass es mit "\0" abschließt?
}
strcat( abCommandLine, argv[n] );
if ( n != argc - 1 && nMode != 1 ) {
strcat( abCommandLine, "." );
}
}
n++;
}
 
if ( fInName != NULL && nMode == 1 ) {
FILE *fIn = fopen( fInName, "rb" );
size_t nRead = 0;
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
abCommandLine[nRead] = '\0';
fclose( fIn );
} else if ( fInName != NULL && nMode == 0 ) {
FILE *fIn = fopen( fInName, "rt" );
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
fgets( abCommandLine, sizeof(abCommandLine), fIn );
fclose( fIn );
}
 
while ( nMode == 1 ) /* better if */
{
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine );*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t ll;
mpz_init(ll);
#else
unsigned long ll = 0;
#endif
bool fOK = false;
int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
while ( *p ) {
if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
*q++ = *p;
}
p++;
}
*q = '\0';
 
if ( strlen( abCommandLine ) % 2 != 0 ) {
fprintf(stderr, "Encoded OID must have even number of hex digits!\n" );
return 2;
}
 
if ( strlen( abCommandLine ) < 3 ) {
fprintf(stderr, "Encoded OID must have at least three bytes!\n" );
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while ( *p ) {
unsigned char b;
 
// Interpret upper nibble
if ( p[0] >= 'A' && p[0] <= 'F' ) {
b = (p[0] - 'A' + 10) * 16;
} else if ( p[0] >= 'a' && p[0] <= 'f' ) {
b = (p[0] - 'a' + 10) * 16;
} else if ( p[0] >= '0' && p[0] <= '9' ) {
b = (p[0] - '0') * 16;
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
// Interpret lower nibble
if ( p[1] >= 'A' && p[1] <= 'F' ) {
b += (p[1] - 'A' + 10);
} else if ( p[1] >= 'a' && p[1] <= 'f' ) {
b += (p[1] - 'a' + 10);
} else if ( p[1] >= '0' && p[1] <= '9' ) {
b += (p[1] - '0');
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
 
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine );*/
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
#ifdef is_gmp
mpz_init(ll);
#else
ll = 0;
#endif
fOK = false;
fSub = 0;
 
// 0 = Universal Class Identifier Tag (can be more than 1 byte, but not in our case)
// 1 = Length part (may have more than 1 byte!)
// 2 = First two arc encoding
// 3 = Encoding of arc three and higher
unsigned char part = 0;
 
unsigned char lengthbyte_count = 0;
unsigned char lengthbyte_pos = 0;
bool lengthfinished = false;
 
while ( nn < nBinary ) {
if ( part == 0 ) { // Class Tag
 
// Leading octet
// Bit 7 / Bit 6 = Universal (00), Application (01), Context (10), Private(11)
// Bit 5 = Primitive (0), Constructed (1)
// Bit 4..0 = 00000 .. 11110 => Tag 0..30, 11111 for Tag > 30 (following bytes with the highest bit as "more" bit)
// --> We don't need to respect 11111 (class-tag encodes in more than 1 octet)
// as we terminate when the tag is not of type OID or RELATEIVE-OID
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
if ((*pb & 0x1F) == 0x0D) {
isRelative = true;
} else if ((*pb & 0x1F) == 0x06) {
isRelative = false;
} else {
fprintf(stderr,"\nError: The class tag is neither an absolute OID (0x06) nor a relative OID (0x0D).\n");
fprintf(fOut,"\n");
return 6;
}
 
// Class
// 0 (00) = Universal
// 1 (01) = Application
// 2 (10) = Context
// 3 (11) = Private
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
if (cl != 0) {
fprintf(stderr,"\nError: The OID tags are only defined as UNIVERSAL class tags.\n");
fprintf(fOut,"\n");
return 6;
}
 
if (isRelative) {
fprintf(fOut, "RELATIVE");
} else {
fprintf(fOut, "ABSOLUTE");
}
 
fprintf(fOut,".OID");
part++;
} else if ( part == 1 ) { // Length
 
// Find out the length and save it into ll
 
// [length] is encoded as follows:
// 0x00 .. 0x7F = The actual length is in this byte, followed by [data].
// 0x80 + n = The length of [data] is spread over the following 'n' bytes. (0 < n < 0x7F)
// 0x80 = "indefinite length" (only constructed form) -- Invalid
// 0xFF = Reserved for further implementations -- Invalid
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
if (nn == 1) { // The first length byte
lengthbyte_pos = 0;
if ( (*pb & 0x80) != 0 ) {
// 0x80 + n => The length is spread over the following 'n' bytes
lengthfinished = false;
lengthbyte_count = *pb & 0x7F;
if (lengthbyte_count == 0x00) {
fprintf(stderr,"\nLength value 0x80 is invalid (\"indefinite length\") for primitive types.\n");
fprintf(fOut,"\n");
return 7;
} else if (lengthbyte_count == 0x7F) {
fprintf(stderr,"\nLength value 0xFF is reserved for further extensions.\n");
fprintf(fOut,"\n");
return 7;
}
fOK = false;
} else {
// 0x01 .. 0x7F => The actual length
 
if (*pb == 0x00) {
fprintf(stderr,"\nLength value 0x00 is invalid for an OID.\n");
fprintf(fOut,"\n");
return 7;
}
 
#ifdef is_gmp
mpz_set_ui(ll, *pb);
#else
ll = *pb;
#endif
lengthfinished = true;
lengthbyte_count = 0;
fOK = true;
}
} else {
if (lengthbyte_count > lengthbyte_pos) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x100);
mpz_add_ui(ll, ll, *pb);
#else
ll *= 0x100;
ll += *pb;
#endif
lengthbyte_pos++;
}
 
if (lengthbyte_count == lengthbyte_pos) {
lengthfinished = true;
fOK = true;
}
}
 
if (lengthfinished) { // The length is now in ll
#ifdef is_gmp
if ( mpz_cmp_ui(ll, nBinary - 2 - lengthbyte_count) != 0 ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll) );
return 3;
}
mpz_set_ui(ll, 0); // reset for later usage
#else
if ( ll != nBinary - 2 - lengthbyte_count ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll );
return 3;
}
ll = 0; // reset for later usage
#endif
fOK = true;
part++;
if (isRelative) part++; // Goto step 3!
}
} else if ( part == 2 ) { // First two arcs
int first = *pb / 40;
int second = *pb % 40;
if (first > 2) {
first = 2;
fprintf(fOut,".%d", first );
 
if ( (*pb & 0x80) != 0 ) {
// 2.48 and up => 2+ octets
// Output in "part 3"
 
if ((*pb & 0x7F) == 0) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return 4;
}
 
#ifdef is_gmp
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll += (*pb & 0x7F);
#endif
fSub = 80;
fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
second = *pb - 80;
fprintf(fOut,".%d",second);
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
fprintf(fOut,".%d.%d", first, second );
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
part++;
} else if ( part == 3 ) { // Arc three and higher
if ( (*pb & 0x80) != 0 ) {
 
if ((*pb & 0x7F) == 0) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return 4;
}
 
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll *= 128;
ll += (*pb & 0x7F);
#endif
fOK = false;
} else {
fOK = 1;
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, *pb);
mpz_sub_ui(ll, ll, fSub);
fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
// Happens only if 0x80 paddings are allowed
// fOK = mpz_cmp_ui(ll, 0 ) >= 0;
mpz_set_ui(ll, 0);
#else
ll *= 128;
ll += *pb;
ll -= fSub;
fprintf(fOut,".%lu", ll );
// Happens only if 0x80 paddings are allowed
// fOK = ll >= 0;
ll = 0;
#endif
fSub = 0;
}
}
 
pb++;
nn++;
}
 
if ( !fOK ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
return 4;
} else {
fprintf(fOut,"\n");
}
 
if ( fOut != stdout ) {
fclose( fOut );
}
break;
};
 
while ( nMode == 0 ) /* better if */
{
/* dotted->hex */
/* printf("OID.%s\n", abCommandLine ); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t l;
#else
unsigned long l = 0;
#endif
bool isjoint = false;
 
if ( __STRNICMP_LOCAL( p, "ABSOLUTE.", 9 ) == 0 ) {
isRelative = false;
p+=9;
} else if ( __STRNICMP_LOCAL( p, "RELATIVE.", 9 ) == 0 ) {
isRelative = true;
p+=9;
} else {
isRelative = false;
}
 
cl = 0x00; // Class. Always UNIVERSAL (00)
 
// Tag for Universal Class
if ( isRelative ) {
cl |= 0x0D;
} else {
cl |= 0x06;
}
 
if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
p+=4;
}
 
q = p;
nPieces = 1;
while ( *p ) {
if ( *p == '.' ) {
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while ( n < nPieces ) {
q = p;
while ( *p ) {
if ( *p == '.' ) {
break;
}
p++;
}
 
#ifdef is_gmp
mpz_init(l);
#else
l = 0;
#endif
if ( *p == '.' ) {
*p = 0;
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p+1;
p = q;
} else {
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p;
}
 
/* Digit is in l. */
if (( n == 0 ) && (!isRelative)) {
#ifdef is_gmp
if (mpz_cmp_ui(l, 2) > 0) {
#else
if (l > 2) {
#endif
fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
return 5;
}
#ifdef is_gmp
b += 40 * mpz_get_ui(l);
isjoint = mpz_cmp_ui(l, 2) == 0;
#else
b = 40 * ((unsigned char)l);
isjoint = l == 2;
#endif
} else if (( n == 1 ) && (!isRelative)) {
#ifdef is_gmp
if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
#else
if ((l > 39) && (!isjoint)) {
#endif
fprintf(stderr,"\nEncoding error. The second arc is limited to 0..39 for root arcs 0 and 1.\n");
return 5;
}
 
#ifdef is_gmp
if (mpz_cmp_ui(l, 47) > 0) {
mpz_add_ui(l, l, 80);
MakeBase128( l, 1 );
} else {
b += mpz_get_ui(l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#else
if (l > 47) {
l += 80;
MakeBase128( l, 1 );
} else {
b += ((unsigned char) l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#endif
} else {
MakeBase128( l, 1 );
}
n++;
}
 
if (n < 2) {
fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable OID is 2. (e.g. 2.999)\n");
return 5;
}
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
// Write class-tag
if ( nCHex ) {
fprintf(fOut,"\"\\x%02X", cl );
} else {
fprintf(fOut,"%02X ", cl );
}
 
// Write length
if (nBinary <= 0x7F) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", nBinary );
} else {
fprintf(fOut,"%02X ", nBinary );
}
} else {
unsigned int nBinaryWork = 0; // TODO: GMP
unsigned int lengthCount = 0;
 
nBinaryWork = nBinary;
do {
lengthCount++;
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
 
if (lengthCount >= 0x7F) {
fprintf(stderr,"\nThe length cannot be encoded.\n");
return 8;
}
 
if ( nCHex ) {
fprintf(fOut,"\\x%02X", 0x80 + lengthCount );
} else {
fprintf(fOut,"%02X ", 0x80 + lengthCount );
}
 
nBinaryWork = nBinary;
do {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", nBinaryWork & 0xFF );
} else {
fprintf(fOut,"%02X ", nBinaryWork & 0xFF );
}
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
}
 
nn = 0;
while ( nn < nBinary ) {
unsigned char b = abBinary[nn++];
if ( nn == nBinary ) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X\"\n", b );
} else {
fprintf(fOut,"%02X\n", b );
}
} else {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", b );
} else {
fprintf(fOut,"%02X ", b );
}
}
}
if ( fOut != stdout ) {
fclose( fOut );
}
break;
}
 
free(abCommandLine);
free(abBinary);
 
return 0;
}
 
/* */
 
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/old/oid_19.c
0,0 → 1,893
/*###################################################################
### ###
### Object ID converter. Matthias Gaertner, 06/1999 ###
### Converted to plain 'C' 07/2001 ###
### ###
### Enhanced version by Daniel Marschall, ViaThinkSoft 06-07/2011 ###
### -- NEW 1.2: 2.48 can also be encoded! ###
### -- NEW 1.2: UUIDs (128-bit) are now supported! ###
### (requires GMPLib) ###
### -- NEW 1.3: Length can now have more than 1 byte ###
### -- NEW 1.4: No command line limitation anymore. ###
### -- NEW 1.5: Now also relative OIDs supported ###
### -- NEW 1.6: 0x80 paddings are now disallowed ###
### -- NEW 1.8: Removed Application/Context/Private "OID"s ###
### -- NEW 1.9: Also allow decoding C-notation with "-x" ###
### -- AS WELL AS SEVERAL BUG FIXES ###
### ###
### To compile with gcc simply use: ###
### gcc -O2 -o oid oid.c -lgmp -lm ###
### ###
### To compile using cl, use: ###
### cl -DWIN32 -O1 oid.c (+ include gmp library) ###
### ###
### Freeware - do with it whatever you want. ###
### Use at your own risk. No warranty of any kind. ###
### ###
###################################################################*/
/* $Version: 1.9$ */
 
// FUTURE
// - Alles in Funktionen kapseln. Als Parameter: Array of integer (= dot notation) oder Array of byte (= hex notation)
 
// MINOR THINGS
// - All stderr: Output new line at stdOut and close stdOut
// - Make as much GMP as possible (e.g. nBinary counter, nBinaryWork etc)
// - überlegen, wie man die return-codes (errorcodes) besser verteilt/definiert
// - irgendwie in funktionen kapseln (z.b. class-tag-parser usw)
// - "TODO"s beachten (unklare dinge)
 
// MINOR PROBLEMS IN CLI-INTERPRETATION:
// - A wrong error message is shown when trying to encode "-0.0" or "x"
// - 2.9a9 is not recognized as error
// - "./oid R 2.999" is not interpretet correctly
 
// NICE TO HAVE:
// - also allow -x to interpret "\x06\x02\x88\x37"
// - makefile, manpage, linuxpackage
// - better make functions instead of putting everything in main() with fprintf...
 
// NICE TO HAVE (INFINITY-IDEA - NOT IMPORTANT):
// - Is it possible to detect integer overflows and therefore output errors?
 
 
// -------------------------------------------------------
 
// Allows OIDs which are bigger than "long"
// Compile with "gcc oid.c -lgmp -lm"
#define is_gmp
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#ifdef is_gmp
#include <gmp.h>
#endif
 
#include <stdbool.h>
 
#ifndef __STRNICMP_LOCAL
#ifdef WIN32
#define __STRNICMP_LOCAL strnicmp
#else
#define __STRNICMP_LOCAL strncasecmp
#endif
#endif
 
// char abCommandLine[4096];
const unsigned int CLI_INITIAL_SIZE = 1024;
const unsigned int CLI_EXPANSION_SIZE = 1024;
unsigned int cli_size;
char * abCommandLine;
 
// unsigned char abBinary[128];
const unsigned int ABB_INITIAL_SIZE = 1024;
const unsigned int ABB_EXPANSION_SIZE = 1024;
unsigned int abb_size;
unsigned char * abBinary;
 
unsigned int nBinary = 0;
 
const int MODE_DOT_TO_HEX = 0;
const int MODE_HEX_TO_DOT = 1;
 
#ifdef is_gmp
static void MakeBase128( mpz_t l, int first ) {
if ( mpz_cmp_si(l, 127) > 0 ) {
mpz_t l2;
mpz_init(l2);
mpz_div_ui(l2, l, 128);
MakeBase128( l2 , 0 );
}
mpz_mod_ui(l, l, 128);
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = mpz_get_ui(l);
} else {
abBinary[nBinary++] = 0x80 | mpz_get_ui(l);
}
}
#else
static void MakeBase128( unsigned long l, int first ) {
if ( l > 127 ) {
MakeBase128( l / 128, 0 );
}
l %= 128;
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
exit(EXIT_FAILURE);
}
}
 
if ( first ) {
abBinary[nBinary++] = (unsigned char)l;
} else {
abBinary[nBinary++] = 0x80 | (unsigned char)l;
}
}
#endif
 
int main( int argc, char **argv ) {
cli_size = CLI_INITIAL_SIZE;
abCommandLine = (char*) malloc(cli_size * sizeof(char*));
if (abCommandLine == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
abb_size = ABB_INITIAL_SIZE;
abBinary = (unsigned char*) malloc(abb_size * sizeof(unsigned char*));
if (abBinary == NULL) {
fprintf(stderr, "Memory allocation failure!\n");
return EXIT_FAILURE;
}
 
 
char *fOutName = NULL;
char *fInName = NULL;
FILE *fOut = NULL;
 
int n = 1;
int nMode = MODE_DOT_TO_HEX;
bool nCHex = false;
int nAfterOption = 0;
bool isRelative = false;
 
if ( argc == 1 ) {
fprintf( stderr,
"OID encoder/decoder 1.9 - Matthias Gaertner 1999/2001, Daniel Marschall 2011 - Freeware\n"
#ifdef is_gmp
"GMP Edition\n"
#endif
"\nUsage:\n"
" OID [-C] [-r] [-o<outfile>] {-i<infile>|2.999.1}\n"
" converts dotted form to ASCII HEX DER output.\n"
" -C: Output as C-syntax.\n"
" -r: Handle the OID as relative and not absolute.\n"
" OID -x [-o<outfile>] {-i<infile>|hex-digits}\n"
" decodes ASCII HEX DER and gives dotted form.\n" );
return 1;
}
 
while ( n < argc ) {
if ( !nAfterOption && argv[n][0] == '-' ) {
if ( argv[n][1] == 'x' ) {
nMode = MODE_HEX_TO_DOT;
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'C' ) {
nMode = MODE_DOT_TO_HEX;
nCHex = true;
 
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'r' ) {
nMode = MODE_DOT_TO_HEX;
isRelative = true;
 
if ( argv[n][2] != '\0' ) {
argv[n--] += 2;
nAfterOption = 1;
}
} else if ( argv[n][1] == 'o' ) {
if ( argv[n][2] != '\0' ) {
fOutName = &argv[n][2];
} else if ( n < argc-1 ) {
fOutName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
return EXIT_FAILURE;
}
} else if ( argv[n][1] == 'i' ) {
if ( argv[n][2] != '\0' ) {
fInName = &argv[n][2];
} else if ( n < argc-1 ) {
fInName = argv[++n];
} else {
fprintf(stderr,"Incomplete command line.\n");
return EXIT_FAILURE;
}
}
} else {
if ( fInName != NULL ) { // TODO: (Unklar) Was bewirkt das? Auch für fOutName notwendig?
break;
}
 
nAfterOption = 1;
if ( strlen( argv[n] ) + strlen( abCommandLine ) >= sizeof(abCommandLine)-2 ) {
// fprintf(stderr,"Command line too long.\n");
// return 2;
 
cli_size += CLI_EXPANSION_SIZE + strlen( argv[n] ) + 1; // 1 = "."
abCommandLine = (char*) realloc(abCommandLine, cli_size);
if (abCommandLine == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
// TODO: (Unklar) Wer garantiert, dass es mit "\0" abschließt?
}
strcat( abCommandLine, argv[n] );
if ( n != argc - 1 && nMode != MODE_HEX_TO_DOT ) {
strcat( abCommandLine, "." );
}
}
n++;
}
 
if ( fInName != NULL && nMode == MODE_HEX_TO_DOT ) {
FILE *fIn = fopen( fInName, "rb" );
size_t nRead = 0;
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
nRead = fread( abCommandLine, 1, sizeof(abCommandLine), fIn );
abCommandLine[nRead] = '\0';
fclose( fIn );
} else if ( fInName != NULL && nMode == MODE_DOT_TO_HEX ) {
FILE *fIn = fopen( fInName, "rt" );
if ( fIn == NULL ) {
fprintf(stderr,"Unable to open input file %s.\n", fInName );
return 11;
}
fgets( abCommandLine, sizeof(abCommandLine), fIn );
fclose( fIn );
}
 
while ( nMode == MODE_HEX_TO_DOT ) /* better if */
{
/* hex->dotted */
/*printf("Hex-In: %s\n", abCommandLine );*/
 
char *p = abCommandLine;
char *q = p;
 
unsigned char *pb = NULL;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t ll;
mpz_init(ll);
#else
unsigned long ll = 0;
#endif
bool fOK = false;
int fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
while ( *p ) {
if ( *p != '.' && *p != '\r' && *p != '\n' && *p != '\x20' && *p != '\t') {
*q++ = *p;
}
p++;
}
*q = '\0';
 
if ( strlen( abCommandLine ) % 2 != 0 ) {
fprintf(stderr, "Encoded OID must have even number of hex digits!\n" );
return 2;
}
 
if ( strlen( abCommandLine ) < 3 ) {
fprintf(stderr, "Encoded OID must have at least three bytes!\n" );
return 2;
}
 
nBinary = 0;
p = abCommandLine;
 
while ( *p ) {
unsigned char b;
 
// This allows also C-notation
if ((p[0] == '\\') && (p[1] == 'x')) {
p += 2;
continue;
}
 
// Interpret upper nibble
if ( p[0] >= 'A' && p[0] <= 'F' ) {
b = (p[0] - 'A' + 10) * 16;
} else if ( p[0] >= 'a' && p[0] <= 'f' ) {
b = (p[0] - 'a' + 10) * 16;
} else if ( p[0] >= '0' && p[0] <= '9' ) {
b = (p[0] - '0') * 16;
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
// Interpret lower nibble
if ( p[1] >= 'A' && p[1] <= 'F' ) {
b += (p[1] - 'A' + 10);
} else if ( p[1] >= 'a' && p[1] <= 'f' ) {
b += (p[1] - 'a' + 10);
} else if ( p[1] >= '0' && p[1] <= '9' ) {
b += (p[1] - '0');
} else {
fprintf(stderr, "Must have hex digits only!\n" );
return 2;
}
 
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
 
abBinary[nBinary++] = b;
p += 2;
}
 
/*printf("Hex-In: %s\n", abCommandLine );*/
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
pb = abBinary;
nn = 0;
#ifdef is_gmp
mpz_init(ll);
#else
ll = 0;
#endif
fOK = false;
fSub = 0;
 
// 0 = Universal Class Identifier Tag (can be more than 1 byte, but not in our case)
// 1 = Length part (may have more than 1 byte!)
// 2 = First two arc encoding
// 3 = Encoding of arc three and higher
unsigned char part = 0;
 
unsigned char lengthbyte_count = 0;
unsigned char lengthbyte_pos = 0;
bool lengthfinished = false;
 
while ( nn < nBinary ) {
if ( part == 0 ) { // Class Tag
 
// Leading octet
// Bit 7 / Bit 6 = Universal (00), Application (01), Context (10), Private(11)
// Bit 5 = Primitive (0), Constructed (1)
// Bit 4..0 = 00000 .. 11110 => Tag 0..30, 11111 for Tag > 30 (following bytes with the highest bit as "more" bit)
// --> We don't need to respect 11111 (class-tag encodes in more than 1 octet)
// as we terminate when the tag is not of type OID or RELATEIVE-OID
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
// Class: 8. - 7. bit
// 0 (00) = Universal
// 1 (01) = Application
// 2 (10) = Context
// 3 (11) = Private
unsigned char cl = ((*pb & 0xC0) >> 6) & 0x03;
if (cl != 0) {
fprintf(stderr,"\nError at type: The OID tags are only defined as UNIVERSAL class tags.\n");
fprintf(fOut,"\n");
return 6;
}
 
// Primitive/Constructed: 6. bit
// 0 = Primitive
// 1 = Constructed
unsigned char pc = *pb & 0x20;
if (pc != 0) {
fprintf(stderr,"\nError at type: OIDs must be primitive, not constructed.\n");
fprintf(fOut,"\n");
return 6;
}
 
// Tag number: 5. - 1. bit
unsigned char tag = *pb & 0x1F;
if (tag == 0x0D) {
isRelative = true;
} else if (tag == 0x06) {
isRelative = false;
} else {
fprintf(stderr,"\nError at type: The tag number is neither an absolute OID (0x06) nor a relative OID (0x0D).\n");
fprintf(fOut,"\n");
return 6;
}
 
// Output
if (isRelative) {
fprintf(fOut, "RELATIVE");
} else {
fprintf(fOut, "ABSOLUTE");
}
 
fprintf(fOut,".OID");
part++;
} else if ( part == 1 ) { // Length
 
// Find out the length and save it into ll
 
// [length] is encoded as follows:
// 0x00 .. 0x7F = The actual length is in this byte, followed by [data].
// 0x80 + n = The length of [data] is spread over the following 'n' bytes. (0 < n < 0x7F)
// 0x80 = "indefinite length" (only constructed form) -- Invalid
// 0xFF = Reserved for further implementations -- Invalid
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
if (nn == 1) { // The first length byte
lengthbyte_pos = 0;
if ( (*pb & 0x80) != 0 ) {
// 0x80 + n => The length is spread over the following 'n' bytes
lengthfinished = false;
lengthbyte_count = *pb & 0x7F;
if (lengthbyte_count == 0x00) {
fprintf(stderr,"\nLength value 0x80 is invalid (\"indefinite length\") for primitive types.\n");
fprintf(fOut,"\n");
return 7;
} else if (lengthbyte_count == 0x7F) {
fprintf(stderr,"\nLength value 0xFF is reserved for further extensions.\n");
fprintf(fOut,"\n");
return 7;
}
fOK = false;
} else {
// 0x01 .. 0x7F => The actual length
 
if (*pb == 0x00) {
fprintf(stderr,"\nLength value 0x00 is invalid for an OID.\n");
fprintf(fOut,"\n");
return 7;
}
 
#ifdef is_gmp
mpz_set_ui(ll, *pb);
#else
ll = *pb;
#endif
lengthfinished = true;
lengthbyte_count = 0;
fOK = true;
}
} else {
if (lengthbyte_count > lengthbyte_pos) {
#ifdef is_gmp
mpz_mul_ui(ll, ll, 0x100);
mpz_add_ui(ll, ll, *pb);
#else
ll *= 0x100;
ll += *pb;
#endif
lengthbyte_pos++;
}
 
if (lengthbyte_count == lengthbyte_pos) {
lengthfinished = true;
fOK = true;
}
}
 
if (lengthfinished) { // The length is now in ll
#ifdef is_gmp
if ( mpz_cmp_ui(ll, nBinary - 2 - lengthbyte_count) != 0 ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %s expected)\n", nBinary - 2, mpz_get_str(NULL, 10, ll) );
return 3;
}
mpz_set_ui(ll, 0); // reset for later usage
#else
if ( ll != nBinary - 2 - lengthbyte_count ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nInvalid length (%d entered, but %d expected)\n", nBinary - 2, ll );
return 3;
}
ll = 0; // reset for later usage
#endif
fOK = true;
part++;
if (isRelative) part++; // Goto step 3!
}
} else if ( part == 2 ) { // First two arcs
int first = *pb / 40;
int second = *pb % 40;
if (first > 2) {
first = 2;
fprintf(fOut,".%d", first );
 
if ( (*pb & 0x80) != 0 ) {
// 2.48 and up => 2+ octets
// Output in "part 3"
 
if ((*pb & 0x7F) == 0) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return 4;
}
 
#ifdef is_gmp
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll += (*pb & 0x7F);
#endif
fSub = 80;
fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
second = *pb - 80;
fprintf(fOut,".%d",second);
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
fprintf(fOut,".%d.%d", first, second );
fOK = true;
#ifdef is_gmp
mpz_set_ui(ll, 0);
#else
ll = 0;
#endif
}
part++;
} else if ( part == 3 ) { // Arc three and higher
if ( (*pb & 0x80) != 0 ) {
 
if ((*pb & 0x7F) == 0) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return 4;
}
 
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, (*pb & 0x7F));
#else
ll *= 128;
ll += (*pb & 0x7F);
#endif
fOK = false;
} else {
fOK = 1;
#ifdef is_gmp
mpz_mul_ui(ll, ll, 128);
mpz_add_ui(ll, ll, *pb);
mpz_sub_ui(ll, ll, fSub);
fprintf(fOut,".%s", mpz_get_str(NULL, 10, ll) );
// Happens only if 0x80 paddings are allowed
// fOK = mpz_cmp_ui(ll, 0 ) >= 0;
mpz_set_ui(ll, 0);
#else
ll *= 128;
ll += *pb;
ll -= fSub;
fprintf(fOut,".%lu", ll );
// Happens only if 0x80 paddings are allowed
// fOK = ll >= 0;
ll = 0;
#endif
fSub = 0;
}
}
 
pb++;
nn++;
}
 
if ( !fOK ) {
fprintf(fOut,"\n");
if ( fOut != stdout ) {
fclose( fOut );
}
fprintf(stderr,"\nEncoding error. The OID is not constructed properly.\n");
return 4;
} else {
fprintf(fOut,"\n");
}
 
if ( fOut != stdout ) {
fclose( fOut );
}
break;
};
 
while ( nMode == MODE_DOT_TO_HEX ) /* better if */
{
/* dotted->hex */
/* printf("OID.%s\n", abCommandLine ); */
 
char *p = abCommandLine;
unsigned char cl = 0x00;
char *q = NULL;
int nPieces = 1;
int n = 0;
unsigned char b = 0;
unsigned int nn = 0;
#ifdef is_gmp
mpz_t l;
#else
unsigned long l = 0;
#endif
bool isjoint = false;
 
/* if ( __STRNICMP_LOCAL( p, "ABSOLUTE.", 9 ) == 0 ) {
isRelative = false;
p+=9;
} else if ( __STRNICMP_LOCAL( p, "RELATIVE.", 9 ) == 0 ) {
isRelative = true;
p+=9;
} else {
isRelative = false;
} */
 
cl = 0x00; // Class. Always UNIVERSAL (00)
 
// Tag for Universal Class
if ( isRelative ) {
cl |= 0x0D;
} else {
cl |= 0x06;
}
 
/* if ( __STRNICMP_LOCAL( p, "OID.", 4 ) == 0 ) {
p+=4;
} */
 
q = p;
nPieces = 1;
while ( *p ) {
if ( *p == '.' ) {
nPieces++;
}
p++;
}
 
n = 0;
b = 0;
p = q;
while ( n < nPieces ) {
q = p;
while ( *p ) {
if ( *p == '.' ) {
break;
}
p++;
}
 
#ifdef is_gmp
mpz_init(l);
#else
l = 0;
#endif
if ( *p == '.' ) {
*p = 0;
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p+1;
p = q;
} else {
#ifdef is_gmp
mpz_set_str(l, q, 10);
#else
l = (unsigned long) atoi( q );
#endif
q = p;
}
 
/* Digit is in l. */
if (( n == 0 ) && (!isRelative)) {
#ifdef is_gmp
if (mpz_cmp_ui(l, 2) > 0) {
#else
if (l > 2) {
#endif
fprintf(stderr,"\nEncoding error. The top arc is limited to 0, 1 and 2.\n");
return 5;
}
#ifdef is_gmp
b += 40 * mpz_get_ui(l);
isjoint = mpz_cmp_ui(l, 2) == 0;
#else
b = 40 * ((unsigned char)l);
isjoint = l == 2;
#endif
} else if (( n == 1 ) && (!isRelative)) {
#ifdef is_gmp
if ((mpz_cmp_ui(l, 39) > 0) && (!isjoint)) {
#else
if ((l > 39) && (!isjoint)) {
#endif
fprintf(stderr,"\nEncoding error. The second arc is limited to 0..39 for root arcs 0 and 1.\n");
return 5;
}
 
#ifdef is_gmp
if (mpz_cmp_ui(l, 47) > 0) {
mpz_add_ui(l, l, 80);
MakeBase128( l, 1 );
} else {
b += mpz_get_ui(l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#else
if (l > 47) {
l += 80;
MakeBase128( l, 1 );
} else {
b += ((unsigned char) l);
if (nBinary+1 >= abb_size) {
abb_size += ABB_EXPANSION_SIZE;
abBinary = (unsigned char*) realloc(abBinary, abb_size);
if (abBinary == NULL) {
fprintf(stderr, "Memory reallocation failure!\n");
return EXIT_FAILURE;
}
}
abBinary[nBinary++] = b;
}
#endif
} else {
MakeBase128( l, 1 );
}
n++;
}
 
if ((n < 2) && (!isRelative)) {
fprintf(stderr,"\nEncoding error. The minimum depth of an encodeable absolute OID is 2. (e.g. 2.999)\n");
return 5;
}
 
if ( fOutName != NULL ) {
fOut = fopen( fOutName, "wt" );
if ( fOut == NULL ) {
fprintf(stderr,"Unable to open output file %s\n", fOutName );
return 33;
}
} else {
fOut = stdout;
}
 
// Write class-tag
if ( nCHex ) {
fprintf(fOut,"\"\\x%02X", cl );
} else {
fprintf(fOut,"%02X ", cl );
}
 
// Write length
if (nBinary <= 0x7F) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", nBinary );
} else {
fprintf(fOut,"%02X ", nBinary );
}
} else {
unsigned int nBinaryWork;
unsigned int lengthCount = 0;
 
nBinaryWork = nBinary;
do {
lengthCount++;
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
 
if (lengthCount >= 0x7F) {
fprintf(stderr,"\nThe length cannot be encoded.\n");
return 8;
}
 
if ( nCHex ) {
fprintf(fOut,"\\x%02X", 0x80 + lengthCount );
} else {
fprintf(fOut,"%02X ", 0x80 + lengthCount );
}
 
nBinaryWork = nBinary;
do {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", nBinaryWork & 0xFF );
} else {
fprintf(fOut,"%02X ", nBinaryWork & 0xFF );
}
nBinaryWork /= 0x100;
} while (nBinaryWork > 0);
}
 
nn = 0;
while ( nn < nBinary ) {
unsigned char b = abBinary[nn++];
if ( nn == nBinary ) {
if ( nCHex ) {
fprintf(fOut,"\\x%02X\"\n", b );
} else {
fprintf(fOut,"%02X\n", b );
}
} else {
if ( nCHex ) {
fprintf(fOut,"\\x%02X", b );
} else {
fprintf(fOut,"%02X ", b );
}
}
}
if ( fOut != stdout ) {
fclose( fOut );
}
break;
}
 
free(abCommandLine);
free(abBinary);
 
return 0;
}
 
/* */
 
Property changes:
Added: svn:mime-type
+text/x-csrc
\ No newline at end of property
/trunk/c/test.sh
0,0 → 1,81
#!/bin/sh
 
make
 
# echo "-- test A"
# ./oid -x "06 07 01 80 80 80 80 80 7F"
 
# echo "-- test B"
# ./oid -x "06 02 80 01"
 
# echo "-- test C"
# ./oid -x "06 02 80 7F"
 
echo "-- 2.999";
./oid 2.999
echo "-- RELATIVE.2.999";
./oid RELATIVE.2.999
 
echo "-- 06 00"
./oid -x "06 00";
echo "-- 06 80"
./oid -x "06 80";
echo "-- 06 FF";
./oid -x "06 FF";
 
echo "-- 05 02 88 37"
./oid -x "05 02 88 37";
 
echo "-- 06 02 88 37"
./oid -x "06 02 88 37"
 
echo "-- 0D 03 02 87 67"
./oid -x "0D 03 02 87 67"
 
exit
 
echo "LONG OID"
./oid -x "06 82 02 4C 88 37 82 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 7f"
 
echo "-1.0 [NOT VALID]"
./oid -1.0
echo ""
 
echo "0.0"
./oid 0.0
echo ""
 
echo "0.39"
./oid 0.39
echo ""
 
echo "0.40 [NOT VALID]"
./oid 0.40
echo ""
 
echo "1.39"
./oid 1.39
echo ""
 
echo "1.40 [NOT VALID]"
./oid 1.40
echo ""
 
echo "3.0 [NOT VALID]"
./oid 3.0
echo ""
 
echo "2.999 == (06 02 88 37)";
./oid 2.999
echo ""
 
echo "(06 01 27)"
./oid -x "06 01 27"
echo "(06 01 4F)"
./oid -x "06 01 4F"
echo "(06 01 7F)"
./oid -x "06 01 7F"
echo "(06 01 80) [NOT VALID]"
./oid -x "06 01 80"
echo "(06 02 88 37)"
./oid -x "06 02 88 37"
Property changes:
Added: svn:executable
+*
\ No newline at end of property
Added: svn:mime-type
+text/x-sh
\ No newline at end of property
/trunk/php/OidDerConverter.class.phps
0,0 → 1,380
<?php
 
/*
* OidDerConverter.class.php, Version 1.1; Based on version 1.11 of oid.c
* Copyright 2014-2015 Daniel Marschall, ViaThinkSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
 
 
// Note: Leading zeros are permitted in dotted notation.
 
// TODO: define output format as parameter; don't force the user to use hexStrToArray
 
class OidDerConverter {
 
/**
* @arg $str "\x12\x23" or "12 34"
* @return array(0x12, 0x23)
*/
// Doesn't need to be public, but it is a nice handy function, especially in the testcases
public static function hexStrToArray($str) {
$out = array();
 
$str = str_replace('\x', ' ', $str);
$str = trim($str);
$ary = explode(' ', $str);
 
foreach ($ary as &$a) {
$out[] = hexdec($a);
}
 
return $out;
}
 
/**
* @return Outputs .<oid> for an absolute OID and <oid> for a relative OID.
*/
public static function derToOID($abBinary, $verbose=false) {
$output_oid = array();
$output_absolute = true;
 
if (count($abBinary) < 3) {
if ($verbose) fprintf(STDERR, "Encoded OID must have at least three bytes!\n");
return false;
}
 
$nBinary = count($abBinary);
$ll = gmp_init(0);
$fOK = false;
$fSub = 0; // Subtract value from next number output. Used when encoding {2 48} and up
 
// 0 = Universal Class Identifier Tag (can be more than 1 byte, but not in our case)
// 1 = Length part (may have more than 1 byte!)
// 2 = First two arc encoding
// 3 = Encoding of arc three and higher
$part = 0;
 
$lengthbyte_count = 0;
$lengthbyte_pos = 0;
$lengthfinished = false;
 
$arcBeginning = true;
 
foreach ($abBinary as $nn => &$pb) {
if ($part == 0) { // Class Tag
// Leading octet
// Bit 7 / Bit 6 = Universal (00), Application (01), Context (10), Private(11)
// Bit 5 = Primitive (0), Constructed (1)
// Bit 4..0 = 00000 .. 11110 => Tag 0..30, 11111 for Tag > 30 (following bytes with the highest bit as "more" bit)
// --> We don't need to respect 11111 (class-tag encodes in more than 1 octet)
// as we terminate when the tag is not of type OID or RELATEIVE-OID
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
// Class: 8. - 7. bit
// 0 (00) = Universal
// 1 (01) = Application
// 2 (10) = Context
// 3 (11) = Private
$cl = (($pb & 0xC0) >> 6) & 0x03;
if ($cl != 0) {
if ($verbose) fprintf(STDERR, "Error at type: The OID tags are only defined as UNIVERSAL class tags.\n");
return false;
}
 
// Primitive/Constructed: 6. bit
// 0 = Primitive
// 1 = Constructed
$pc = $pb & 0x20;
if ($pc != 0) {
if ($verbose) fprintf(STDERR, "Error at type: OIDs must be primitive, not constructed.\n");
return false;
}
 
// Tag number: 5. - 1. bit
$tag = $pb & 0x1F;
if ($tag == 0x0D) {
$isRelative = true;
} else if ($tag == 0x06) {
$isRelative = false;
} else {
if ($verbose) fprintf(STDERR, "Error at type: The tag number is neither an absolute OID (0x06) nor a relative OID (0x0D).\n");
return false;
}
 
// Output
$output_absolute = !$isRelative;
 
$part++;
} else if ($part == 1) { // Length
// Find out the length and save it into $ll
 
// [length] is encoded as follows:
// 0x00 .. 0x7F = The actual length is in this byte, followed by [data].
// 0x80 + n = The length of [data] is spread over the following 'n' bytes. (0 < n < 0x7F)
// 0x80 = "indefinite length" (only constructed form) -- Invalid
// 0xFF = Reserved for further implementations -- Invalid
// See page 396 of "ASN.1 - Communication between Heterogeneous Systems" by Olivier Dubuisson.
 
if ($nn == 1) { // The first length byte
$lengthbyte_pos = 0;
if (($pb & 0x80) != 0) {
// 0x80 + n => The length is spread over the following 'n' bytes
$lengthfinished = false;
$lengthbyte_count = $pb & 0x7F;
if ($lengthbyte_count == 0x00) {
if ($verbose) fprintf(STDERR, "Length value 0x80 is invalid (\"indefinite length\") for primitive types.\n");
return false;
} else if ($lengthbyte_count == 0x7F) {
if ($verbose) fprintf(STDERR, "Length value 0xFF is reserved for further extensions.\n");
return false;
}
$fOK = false;
} else {
// 0x01 .. 0x7F => The actual length
 
if ($pb == 0x00) {
if ($verbose) fprintf(STDERR, "Length value 0x00 is invalid for an OID.\n");
return false;
}
 
$ll = gmp_init($pb);
$lengthfinished = true;
$lengthbyte_count = 0;
$fOK = true;
}
} else {
if ($lengthbyte_count > $lengthbyte_pos) {
$ll = gmp_mul($ll, 0x100);
$ll = gmp_add($ll, $pb);
$lengthbyte_pos++;
}
 
if ($lengthbyte_count == $lengthbyte_pos) {
$lengthfinished = true;
$fOK = true;
}
}
 
if ($lengthfinished) { // The length is now in $ll
if (gmp_cmp($ll, $nBinary - 2 - $lengthbyte_count) != 0) {
if ($verbose) fprintf(STDERR, "Invalid length (%d entered, but %s expected)\n", $nBinary - 2, gmp_strval($ll, 10));
return false;
}
$ll = gmp_init(0); // reset for later usage
$fOK = true;
$part++;
if ($isRelative) $part++; // Goto step 3!
}
} else if ($part == 2) { // First two arcs
$first = $pb / 40;
$second = $pb % 40;
if ($first > 2) {
$first = 2;
$output_oid[] = $first;
$arcBeginning = true;
 
if (($pb & 0x80) != 0) {
// 2.48 and up => 2+ octets
// Output in "part 3"
 
if ($arcBeginning && ($pb == 0x80)) {
if ($verbose) fprintf(STDERR, "Encoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return false;
} else {
$arcBeginning = false;
}
 
$ll = gmp_add($ll, ($pb & 0x7F));
$fSub = 80;
$fOK = false;
} else {
// 2.0 till 2.47 => 1 octet
$second = $pb - 80;
$output_oid[] = $second;
$arcBeginning = true;
$fOK = true;
$ll = gmp_init(0);
}
} else {
// 0.0 till 0.37 => 1 octet
// 1.0 till 1.37 => 1 octet
$output_oid[] = $first;
$output_oid[] = $second;
$arcBeginning = true;
$fOK = true;
$ll = gmp_init(0);
}
$part++;
} else if ($part == 3) { // Arc three and higher
if (($pb & 0x80) != 0) {
if ($arcBeginning && ($pb == 0x80)) {
if ($verbose) fprintf(STDERR, "Encoding error. Illegal 0x80 paddings. (See Rec. ITU-T X.690, clause 8.19.2)\n");
return false;
} else {
$arcBeginning = false;
}
 
$ll = gmp_mul($ll, 0x80);
$ll = gmp_add($ll, ($pb & 0x7F));
$fOK = false;
} else {
$fOK = true;
$ll = gmp_mul($ll, 0x80);
$ll = gmp_add($ll, $pb);
$ll = gmp_sub($ll, $fSub);
$output_oid[] = gmp_strval($ll, 10);
 
// Happens only if 0x80 paddings are allowed
// $fOK = gmp_cmp($ll, 0) >= 0;
$ll = gmp_init(0);
$fSub = 0;
$arcBeginning = true;
}
}
}
 
if (!$fOK) {
if ($verbose) fprintf(STDERR, "Encoding error. The OID is not constructed properly.\n");
return false;
}
 
return ($output_absolute ? '.' : '').implode('.', $output_oid);
}
 
// Doesn't need to be public, but it is a nice handy function, especially in the testcases
public static function hexarrayToStr($ary, $nCHex=false) {
$str = '';
if ($ary === false) return false;
foreach ($ary as &$a) {
if ($nCHex) {
$str .= sprintf("\"\\x%02X", $a);
} else {
$str .= sprintf("%02X ", $a);
}
}
return trim($str);
}
 
public static function oidToDER($oid, $isRelative=false, $verbose=false) {
if ($oid[0] == '.') { // MIB notation
$oid = substr($oid, 1);
$isRelative = false;
}
 
$cl = 0x00; // Class. Always UNIVERSAL (00)
 
// Tag for Universal Class
if ($isRelative) {
$cl |= 0x0D;
} else {
$cl |= 0x06;
}
 
$arcs = explode('.', $oid);
 
$b = 0;
$isjoint = false;
$abBinary = array();
 
if ((!$isRelative) && (count($arcs) < 2)) {
if ($verbose) fprintf(STDERR, "Encoding error. The minimum depth of an encodeable absolute OID is 2. (e.g. 2.999)\n");
return false;
}
 
foreach ($arcs as $n => &$arc) {
if (!preg_match('@^\d+$@', $arc)) {
if ($verbose) fprintf(STDERR, "Encoding error. Arc '%s' is invalid.\n", $arc);
return false;
}
 
$l = gmp_init($arc, 10);
 
if ((!$isRelative) && ($n == 0)) {
if (gmp_cmp($l, 2) > 0) {
if ($verbose) fprintf(STDERR, "Encoding error. The top arc is limited to 0, 1 and 2.\n");
return false;
}
$b += 40 * gmp_intval($l);
$isjoint = gmp_cmp($l, 2) == 0;
} else if ((!$isRelative) && ($n == 1)) {
if ((!$isjoint) && (gmp_cmp($l, 39) > 0)) {
if ($verbose) fprintf(STDERR, "Encoding error. The second arc is limited to 0..39 for root arcs 0 and 1.\n");
return false;
}
 
if (gmp_cmp($l, 47) > 0) {
$l = gmp_add($l, 80);
self::makeBase128($l, 1, $abBinary);
} else {
$b += gmp_intval($l);
$abBinary[] = $b;
}
} else {
self::makeBase128($l, 1, $abBinary);
}
}
 
$output = array();
 
// Write class-tag
$output[] = $cl;
 
// Write length
$nBinary = count($abBinary);
if ($nBinary <= 0x7F) {
$output[] = $nBinary;
} else {
$lengthCount = 0;
$nBinaryWork = $nBinary;
do {
$lengthCount++;
$nBinaryWork /= 0x100;
} while ($nBinaryWork > 0);
 
if ($lengthCount >= 0x7F) {
if ($verbose) fprintf(STDERR, "The length cannot be encoded.\n");
return false;
}
 
$output[] = 0x80 + $lengthCount;
 
$nBinaryWork = $nBinary;
do {
$output[] = nBinaryWork & 0xFF;
$nBinaryWork /= 0x100;
} while ($nBinaryWork > 0);
}
 
foreach ($abBinary as $b) {
$output[] = $b;
}
 
return $output;
}
 
protected static function makeBase128($l, $first, &$abBinary) {
if (gmp_cmp($l, 127) > 0) {
$l2 = gmp_div($l, 128);
self::makeBase128($l2 , 0, $abBinary);
}
$l = gmp_mod($l, 128);
 
if ($first) {
$abBinary[] = gmp_intval($l);
} else {
$abBinary[] = 0x80 | gmp_intval($l);
}
}
}
/trunk/php/test.phps
0,0 → 1,34
<?php
 
/*
* tests.phps, Version 1.0; Based on version 1.11 of oid.c
* Copyright 2014-2015 Daniel Marschall, ViaThinkSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
 
 
// TODO: more testcases
 
error_reporting(E_ALL | E_NOTICE | E_DEPRECATED | E_STRICT);
 
require_once __DIR__ . '/OidDerConverter.class.phps';
 
assert(OidDerConverter::hexarrayToStr(OidDerConverter::oidToDER('.2.999')) == '06 02 88 37');
assert(OidDerConverter::derToOID(array(0x06, 0x02, 0x88, 0x37)) == '.2.999');
 
assert(OidDerConverter::hexarrayToStr(OidDerConverter::oidToDER('2.999', true)) == '0D 03 02 87 67');
assert(OidDerConverter::derToOID(array(0x0D, 0x03, 0x02, 0x87, 0x67)) == '2.999');
 
assert(OidDerConverter::derToOID(OidDerConverter::hexstrToArray('0D 03 02 87 67')) == '2.999');
assert(OidDerConverter::derToOID(OidDerConverter::hexstrToArray('\x0D\x03\x02\x87\x67')) == '2.999');