- startet importing pluto ASN1 stuff
authorMartin Willi <martin@strongswan.org>
Mon, 10 Apr 2006 14:19:10 +0000 (14:19 -0000)
committerMartin Willi <martin@strongswan.org>
Mon, 10 Apr 2006 14:19:10 +0000 (14:19 -0000)
- der PKCS#1 key loading works (as it did with der_decoder)

21 files changed:
Source/Makefile
Source/charon/network/socket.c
Source/doc/Known-bugs.txt
Source/doc/Todo-list.txt
Source/lib/Makefile.lib
Source/lib/asn1-pluto/Makefile.asn1 [new file with mode: 0644]
Source/lib/asn1-pluto/asn1-pluto.c [new file with mode: 0644]
Source/lib/asn1-pluto/asn1-pluto.h [new file with mode: 0644]
Source/lib/asn1-pluto/oid.c [new file with mode: 0644]
Source/lib/asn1-pluto/oid.h [new file with mode: 0644]
Source/lib/asn1-pluto/oid.pl [new file with mode: 0644]
Source/lib/asn1-pluto/oid.txt [new file with mode: 0644]
Source/lib/asn1-pluto/pem.c [new file with mode: 0755]
Source/lib/asn1-pluto/pem.h [new file with mode: 0755]
Source/lib/asn1-pluto/ttodata.c [new file with mode: 0644]
Source/lib/asn1-pluto/ttodata.h [new file with mode: 0644]
Source/lib/crypto/rsa/rsa_private_key.c
Source/lib/types.h
Source/lib/utils/logger.c
Source/lib/utils/logger_manager.c
Source/lib/utils/logger_manager.h

index b202bcb..ceb9876 100644 (file)
@@ -29,7 +29,7 @@ MAIN_DIR= ./
 
 LDFLAGS= -ldl -lgmp -lpthread -rdynamic
 
-CFLAGS= -Icharon -Ilib -Istroke -Wall -g -fPIC -fomit-frame-pointer -DLEAK_DETECTIVE 
+CFLAGS= -Icharon -Ilib -Istroke -Wall -g -fPIC -DLEAK_DETECTIVE 
 
 # objects is extended by each included Makefile
 CHARON_OBJS=
index 733071f..79c7c42 100644 (file)
@@ -448,6 +448,8 @@ socket_t *socket_create(u_int16_t port)
        
        if (build_interface_list(this, port) != SUCCESS)
        {
+               this->interfaces->destroy(this->interfaces);
+               free(this);
                charon->kill(charon, "could not bind any interface!");
        }
 
index 079d4d0..e7ee0b9 100644 (file)
@@ -1,5 +1,5 @@
  Known bugs in charon
 ======================
 
-- intiating the same connection twice makes trouble.
-- 
+- intiating the same connection twice makes trouble
+- leak_detective gets confused from libpthread (invalid frees)
index 4915ea7..0942def 100644 (file)
   + new charon build - libstrong?
     + transforms
     + utils (plus host)
-    - doxygen fixes (two doxyfiles?)
-    - allocator cleanup (used in lib, charon and pluto(!))
-    - logger reimplementation? (one logger for lib, charon, pluto)
+    + logger_manager instance in lib
+    + leak detective usable for charon and pluto and anything else
+    - doxygen fixes (multiple doxyfiles?)
   - integrate asn1 parser/oid (asn1/oid)
   - integrate PEM loading (pem)
-  - ... (more to come, for sure)
+  - ... (more to come)
 
 - ipsec.secrets parsing
 
@@ -42,3 +42,5 @@
 - delete notify, when to send?
 - notifys on connection setup failure
 - create child sa message
+
+- new build environment (autotools?)
\ No newline at end of file
index 389a31b..ff41072 100644 (file)
@@ -25,3 +25,4 @@ $(BUILD_DIR)definitions.o :           $(LIB_DIR)definitions.c $(LIB_DIR)definitions.h
 include $(MAIN_DIR)lib/crypto/Makefile.transforms
 include $(MAIN_DIR)lib/utils/Makefile.utils
 include $(MAIN_DIR)lib/asn1/Makefile.asn1
+include $(MAIN_DIR)lib/asn1-pluto/Makefile.asn1
diff --git a/Source/lib/asn1-pluto/Makefile.asn1 b/Source/lib/asn1-pluto/Makefile.asn1
new file mode 100644 (file)
index 0000000..44726ff
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (C) 2006 Martin Willi
+# Hochschule fuer Technik Rapperswil
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+
+ASN1_DIR= $(LIB_DIR)asn1-pluto/
+
+
+LIB_OBJS+= $(BUILD_DIR)oid.o
+$(BUILD_DIR)oid.o :                                                    $(ASN1_DIR)oid.c $(ASN1_DIR)oid.h
+                                                                                       $(CC) $(CFLAGS) -c -o $@ $<
+LIB_OBJS+= $(BUILD_DIR)asn1-pluto.o
+$(BUILD_DIR)asn1-pluto.o :                                     $(ASN1_DIR)asn1-pluto.c $(ASN1_DIR)asn1-pluto.h
+                                                                                       $(CC) $(CFLAGS) -c -o $@ $<
+LIB_OBJS+= $(BUILD_DIR)pem.o
+$(BUILD_DIR)pem.o :                                                    $(ASN1_DIR)pem.c $(ASN1_DIR)pem.h
+                                                                                       $(CC) $(CFLAGS) -c -o $@ $<
+LIB_OBJS+= $(BUILD_DIR)ttodata.o
+$(BUILD_DIR)ttodata.o :                                                $(ASN1_DIR)ttodata.c $(ASN1_DIR)ttodata.h
+                                                                                       $(CC) $(CFLAGS) -c -o $@ $<
\ No newline at end of file
diff --git a/Source/lib/asn1-pluto/asn1-pluto.c b/Source/lib/asn1-pluto/asn1-pluto.c
new file mode 100644 (file)
index 0000000..46764e1
--- /dev/null
@@ -0,0 +1,574 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2006 Martin Will, Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "asn1-pluto.h"
+#include "oid.h"
+
+#include <utils/logger_manager.h>
+
+static logger_t *logger;
+
+/* Names of the months */
+static const char* months[] = {
+       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+/* some common prefabricated ASN.1 constants */
+static u_char ASN1_INTEGER_0_str[] = { 0x02, 0x00 };
+static u_char ASN1_INTEGER_1_str[] = { 0x02, 0x01, 0x01 };
+static u_char ASN1_INTEGER_2_str[] = { 0x02, 0x01, 0x02 };
+
+const chunk_t ASN1_INTEGER_0 = chunk_from_buf(ASN1_INTEGER_0_str);
+const chunk_t ASN1_INTEGER_1 = chunk_from_buf(ASN1_INTEGER_1_str);
+const chunk_t ASN1_INTEGER_2 = chunk_from_buf(ASN1_INTEGER_2_str);
+
+/* some popular algorithmIdentifiers */
+
+static u_char ASN1_md5_id_str[] = {
+       0x30, 0x0C,
+       0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
+       0x05, 0x00
+};
+
+static u_char ASN1_sha1_id_str[] = {
+       0x30, 0x09,
+       0x06, 0x05, 0x2B, 0x0E,0x03, 0x02, 0x1A,
+       0x05, 0x00
+};
+
+static u_char ASN1_md5WithRSA_id_str[] = {
+       0x30, 0x0D,
+       0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
+       0x05, 0x00
+};
+
+static u_char ASN1_sha1WithRSA_id_str[] = {
+       0x30, 0x0D,
+       0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
+       0x05, 0x00
+};
+
+static u_char ASN1_rsaEncryption_id_str[] = {
+       0x30, 0x0D,
+       0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
+       0x05, 0x00
+};
+
+const chunk_t ASN1_md5_id = chunk_from_buf(ASN1_md5_id_str);
+const chunk_t ASN1_sha1_id = chunk_from_buf(ASN1_sha1_id_str);
+const chunk_t ASN1_rsaEncryption_id = chunk_from_buf(ASN1_rsaEncryption_id_str);
+const chunk_t ASN1_md5WithRSA_id = chunk_from_buf(ASN1_md5WithRSA_id_str);
+const chunk_t ASN1_sha1WithRSA_id = chunk_from_buf(ASN1_sha1WithRSA_id_str);
+
+/* ASN.1 definiton of an algorithmIdentifier */
+static const asn1Object_t algorithmIdentifierObjects[] = {
+       { 0, "algorithmIdentifier",     ASN1_SEQUENCE,  ASN1_NONE }, /* 0 */
+       { 1,   "algorithm",                     ASN1_OID,               ASN1_BODY }, /* 1 */
+       { 1,   "parameters",            ASN1_EOC,               ASN1_RAW  }  /* 2 */
+};
+
+#define ALGORITHM_ID_ALG               1
+#define ALGORITHM_ID_PARAMETERS        2
+#define ALGORITHM_ID_ROOF              3
+
+/*
+ * return the ASN.1 encoded algorithm identifier
+ */
+chunk_t asn1_algorithmIdentifier(int oid)
+{
+       switch (oid)
+       {
+               case OID_RSA_ENCRYPTION:
+                       return ASN1_rsaEncryption_id;
+               case OID_MD5_WITH_RSA:
+                       return ASN1_md5WithRSA_id;
+               case OID_SHA1_WITH_RSA:
+                       return ASN1_sha1WithRSA_id;
+               case OID_MD5:
+                       return ASN1_md5_id;
+               case OID_SHA1:
+                       return ASN1_sha1_id;
+               default:
+                       return CHUNK_INITIALIZER;
+       }
+}
+
+/*
+ * If the oid is listed in the oid_names table then the corresponding
+ * position in the oid_names table is returned otherwise -1 is returned
+ */
+int known_oid(chunk_t object)
+{
+       int oid = 0;
+       
+       while (object.len)
+       {
+               if (oid_names[oid].octet == *object.ptr)
+               {
+                       if (--object.len == 0 || oid_names[oid].down == 0)
+                       {
+                               return oid;          /* found terminal symbol */
+                       }
+                       else
+                       {
+                               object.ptr++; oid++; /* advance to next hex octet */
+                       }
+               }
+               else
+               {
+                       if (oid_names[oid].next)
+                               oid = oid_names[oid].next;
+                       else
+                               return OID_UNKNOWN;
+               }
+       }
+       return -1;
+}
+
+/*
+ * Decodes the length in bytes of an ASN.1 object
+ */
+u_int asn1_length(chunk_t *blob)
+{
+       u_char n;
+       size_t len;
+       
+       /* advance from tag field on to length field */
+       blob->ptr++;
+       blob->len--;
+       
+       /* read first octet of length field */
+       n = *blob->ptr++;
+       blob->len--;
+       
+       if ((n & 0x80) == 0) 
+       {/* single length octet */
+               return n;
+       }
+       
+       /* composite length, determine number of length octets */
+       n &= 0x7f;
+       
+       if (n > blob->len)
+       {
+               logger->log(logger, ERROR|LEVEL1, "number of length octets is larger than ASN.1 object");
+               return ASN1_INVALID_LENGTH;
+       }
+       
+       if (n > sizeof(len))
+       {
+               logger->log(logger, ERROR|LEVEL1, "number of length octets is larger than limit of %d octets", 
+                                       (int)sizeof(len));
+               return ASN1_INVALID_LENGTH;
+       }
+       
+       len = 0;
+       
+       while (n-- > 0)
+       {
+               len = 256*len + *blob->ptr++;
+               blob->len--;
+       }
+       return len;
+}
+
+/*
+ * determines if a character string is of type ASN.1 printableString
+ */
+bool is_printablestring(chunk_t str)
+{
+       const char printablestring_charset[] =
+               "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
+       u_int i;
+       
+       for (i = 0; i < str.len; i++)
+       {
+               if (strchr(printablestring_charset, str.ptr[i]) == NULL)
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+/*
+ * Display a date either in local or UTC time
+ * TODO: Does not seem to be thread save
+ */
+char* timetoa(const time_t *time, bool utc)
+{
+       static char buf[30];
+
+       if (*time == 0)
+               sprintf(buf, "--- -- --:--:--%s----", (utc)?" UTC ":" ");
+       else
+       {
+               struct tm *t = (utc)? gmtime(time) : localtime(time);
+               sprintf(buf, "%s %02d %02d:%02d:%02d%s%04d",
+                               months[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
+                               (utc)?" UTC ":" ", t->tm_year + 1900);
+       }
+       return buf;
+}
+
+/*
+ * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
+ */
+time_t asn1totime(const chunk_t *utctime, asn1_t type)
+{
+       struct tm t;
+       time_t tz_offset;
+       u_char *eot = NULL;
+       
+       if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
+       {
+               tz_offset = 0; /* Zulu time with a zero time zone offset */
+       }
+       else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
+       {
+               int tz_hour, tz_min;
+       
+               sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
+               tz_offset = 3600*tz_hour + 60*tz_min;  /* positive time zone offset */
+       }
+       else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
+       {
+               int tz_hour, tz_min;
+       
+               sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
+               tz_offset = -3600*tz_hour - 60*tz_min;  /* negative time zone offset */
+       }
+       else
+       {
+               return 0; /* error in time format */
+       }
+       
+       {
+       const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
+                       "%4d%2d%2d%2d%2d";
+       
+       sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday,
+                  &t.tm_hour, &t.tm_min);
+       }
+       
+       /* is there a seconds field? */
+       if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
+       {
+               sscanf(eot-2, "%2d", &t.tm_sec);
+       }
+       else
+       {
+               t.tm_sec = 0;
+       }
+       
+       /* representation of year */
+       if (t.tm_year >= 1900)
+       {
+               t.tm_year -= 1900;
+       }
+       else if (t.tm_year >= 100)
+       {
+               return 0;
+       }
+       else if (t.tm_year < 50)
+       {
+               t.tm_year += 100;
+       }
+       
+       /* representation of month 0..11*/
+       t.tm_mon--;
+       
+       /* set daylight saving time to off */
+       t.tm_isdst = 0;
+       
+       /* compensate timezone */
+       
+       return mktime(&t) - timezone - tz_offset;
+}
+
+/*
+ * Initializes the internal context of the ASN.1 parser
+ */
+void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit)
+{
+       logger = logger_manager->get_logger(logger_manager, ASN1);
+       ctx->blobs[0] = blob;
+       ctx->level0   = level0;
+       ctx->implicit = implicit;
+       memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));
+}
+
+/*
+ * print the value of an ASN.1 simple object
+ */
+static void debug_asn1_simple_object(chunk_t object, asn1_t type)
+{
+       int oid;
+       time_t time;
+       
+       switch (type)
+       {
+               case ASN1_OID:
+                       oid = known_oid(object);
+                       if (oid != OID_UNKNOWN)
+                       {
+                               logger->log(logger, CONTROL|LEVEL1, "  '%s'", oid_names[oid].name);
+                               return;
+                       }
+                       break;
+               case ASN1_UTF8STRING:
+               case ASN1_IA5STRING:
+               case ASN1_PRINTABLESTRING:
+               case ASN1_T61STRING:
+               case ASN1_VISIBLESTRING:
+                       logger->log(logger, CONTROL|LEVEL1, "  '%.*s'", (int)object.len, object.ptr);
+                       return;
+               case ASN1_UTCTIME:
+               case ASN1_GENERALIZEDTIME:
+                       time = asn1totime(&object, type);
+                       logger->log(logger, CONTROL|LEVEL1, "  '%s'", timetoa(&time, TRUE));
+                       return;
+               default:
+                       break;
+       }
+       logger->log_chunk(logger, RAW|LEVEL1, "", object);
+}
+
+/*
+ * Parses and extracts the next ASN.1 object
+ */
+bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx)
+{
+       asn1Object_t obj = objects[*objectID];
+       chunk_t *blob;
+       chunk_t *blob1;
+       u_char *start_ptr;
+       
+       *object = CHUNK_INITIALIZER;
+       
+       if (obj.flags & ASN1_END)  /* end of loop or option found */
+       {
+               if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0)
+               {
+                       *objectID = ctx->loopAddr[obj.level]; /* another iteration */
+                       obj = objects[*objectID];
+               }
+               else
+               {
+                       ctx->loopAddr[obj.level] = 0;         /* exit loop or option*/
+                       return TRUE;
+               }
+       }
+       
+       *level = ctx->level0 + obj.level;
+       blob = ctx->blobs + obj.level;
+       blob1 = blob + 1;
+       start_ptr = blob->ptr;
+       
+       /* handle ASN.1 defaults values */
+       if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) )
+       {
+               /* field is missing */
+               logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", *level, obj.name);
+               if (obj.type & ASN1_CONSTRUCTED)
+               {
+                       (*objectID)++ ;  /* skip context-specific tag */
+               }
+               return TRUE;
+       }
+       
+       /* handle ASN.1 options */
+       
+       if ((obj.flags & ASN1_OPT)
+                       && (blob->len == 0 || *start_ptr != obj.type))
+       {
+               /* advance to end of missing option field */
+               do
+                       (*objectID)++;
+               while (!((objects[*objectID].flags & ASN1_END)
+                                               && (objects[*objectID].level == obj.level)));
+               return TRUE;
+       }
+               
+       /* an ASN.1 object must possess at least a tag and length field */
+       
+       if (blob->len < 2)
+       {
+               logger->log(logger, ERROR|LEVEL1, "L%d - %s:  ASN.1 object smaller than 2 octets", 
+                                       *level, obj.name);
+               return FALSE;
+       }
+       
+       blob1->len = asn1_length(blob);
+       
+       if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)
+       {
+               logger->log(logger, ERROR|LEVEL1, "L%d - %s:  length of ASN.1 object invalid or too large", 
+                                       *level, obj.name);
+               return FALSE;
+       }
+       
+       blob1->ptr = blob->ptr;
+       blob->ptr += blob1->len;
+       blob->len -= blob1->len;
+       
+       /* return raw ASN.1 object without prior type checking */
+       
+       if (obj.flags & ASN1_RAW)
+       {
+               logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", *level, obj.name);
+               object->ptr = start_ptr;
+               object->len = (size_t)(blob->ptr - start_ptr);
+               return TRUE;
+       }
+
+       if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0))
+       {
+               logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+                                       *level, obj.name, obj.type, *start_ptr);
+               logger->log_bytes(logger, RAW|LEVEL1, "", start_ptr, (u_int)(blob->ptr - start_ptr));
+               return FALSE;
+       }
+       
+       logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", ctx->level0+obj.level, obj.name);
+       
+       /* In case of "SEQUENCE OF" or "SET OF" start a loop */ 
+       if (obj.flags & ASN1_LOOP)
+       {
+               if (blob1->len > 0)
+               {
+                       /* at least one item, start the loop */
+                       ctx->loopAddr[obj.level] = *objectID + 1;
+               }
+               else
+               {
+                       /* no items, advance directly to end of loop */
+                       do
+                               (*objectID)++;
+                       while (!((objects[*objectID].flags & ASN1_END)
+                                                          && (objects[*objectID].level == obj.level)));
+                       return TRUE;
+               }
+       }
+
+       if (obj.flags & ASN1_OBJ)
+       {
+               object->ptr = start_ptr;
+               object->len = (size_t)(blob->ptr - start_ptr);
+               logger->log_chunk(logger, RAW|LEVEL1, "", *object);
+       }
+       else if (obj.flags & ASN1_BODY)
+       {
+               *object = *blob1;
+               debug_asn1_simple_object(*object, obj.type);
+       }
+       return TRUE;
+}
+
+/*
+ * parse an ASN.1 simple type
+ */
+bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name)
+{
+       size_t len;
+       
+       /* an ASN.1 object must possess at least a tag and length field */
+       if (object->len < 2)
+       {
+               logger->log(logger, ERROR|LEVEL1, "L%d - %s:  ASN.1 object smaller than 2 octets", 
+                                       level, name);
+               return FALSE;
+       }
+       
+       if (*object->ptr != type)
+       {
+               logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
+                                       level, name, type, *object->ptr);
+               return FALSE;
+       }
+       
+       len = asn1_length(object);
+       
+       if (len == ASN1_INVALID_LENGTH || object->len < len)
+       {
+               logger->log(logger, ERROR|LEVEL1, "L%d - %s:  length of ASN.1 object invalid or too large",
+                                       level, name);
+               return FALSE;
+       }
+       
+       logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", level, name);
+       debug_asn1_simple_object(*object, type);
+       return TRUE;
+}
+
+/*
+ * extracts an algorithmIdentifier
+ */
+int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int alg = OID_UNKNOWN;
+       int objectID = 0;
+       
+       asn1_init(&ctx, blob, level0, FALSE);
+       
+       while (objectID < ALGORITHM_ID_ROOF)
+       {
+               if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx))
+                       return OID_UNKNOWN;
+               
+               switch (objectID)
+               {
+                       case ALGORITHM_ID_ALG:
+                               alg = known_oid(object);
+                               break;
+                       case ALGORITHM_ID_PARAMETERS:
+                               if (parameters != NULL)
+                                       *parameters = object;
+                               break;
+                       default:
+                               break;
+               }
+               objectID++;
+       }
+       return alg;
+ }
+
+/*
+ *  tests if a blob contains a valid ASN.1 set or sequence
+ */
+bool is_asn1(chunk_t blob)
+{
+       u_int len;
+       u_char tag = *blob.ptr;
+       
+       if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
+       {
+               logger->log(logger, ERROR|LEVEL2, "  file content is not binary ASN.1");
+               return FALSE;
+       }
+       len = asn1_length(&blob);
+       if (len != blob.len)
+       {
+               logger->log(logger, ERROR|LEVEL2, "  file size does not match ASN.1 coded length");
+               return FALSE;
+       }
+       return TRUE;
+}
diff --git a/Source/lib/asn1-pluto/asn1-pluto.h b/Source/lib/asn1-pluto/asn1-pluto.h
new file mode 100644 (file)
index 0000000..c7cc29e
--- /dev/null
@@ -0,0 +1,129 @@
+/* Simple ASN.1 parser
+ * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2006 Martin Will, Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef _ASN1_H
+#define _ASN1_H
+
+#include <stdarg.h>
+#include <gmp.h>
+
+#include <types.h>
+
+
+/* Defines some primitive ASN1 types */
+
+typedef enum {
+    ASN1_EOC =                 0x00,
+    ASN1_BOOLEAN =             0x01,
+    ASN1_INTEGER =             0x02,
+    ASN1_BIT_STRING =          0x03,
+    ASN1_OCTET_STRING =        0x04,
+    ASN1_NULL =                0x05,
+    ASN1_OID =                 0x06,
+    ASN1_ENUMERATED =          0x0A,
+    ASN1_UTF8STRING =          0x0C,
+    ASN1_NUMERICSTRING =       0x12,
+    ASN1_PRINTABLESTRING =     0x13,
+    ASN1_T61STRING =           0x14,
+    ASN1_VIDEOTEXSTRING =      0x15,
+    ASN1_IA5STRING =           0x16,
+    ASN1_UTCTIME =             0x17,
+    ASN1_GENERALIZEDTIME =     0x18,
+    ASN1_GRAPHICSTRING =       0x19,
+    ASN1_VISIBLESTRING =       0x1A,
+    ASN1_GENERALSTRING =       0x1B,
+    ASN1_UNIVERSALSTRING =     0x1C,
+    ASN1_BMPSTRING =           0x1E,
+
+    ASN1_CONSTRUCTED =         0x20,
+
+    ASN1_SEQUENCE =            0x30,
+
+    ASN1_SET =                 0x31,
+
+    ASN1_CONTEXT_S_0 =         0x80,
+    ASN1_CONTEXT_S_1 =         0x81,
+    ASN1_CONTEXT_S_2 =         0x82,
+    ASN1_CONTEXT_S_3 =         0x83,
+    ASN1_CONTEXT_S_4 =         0x84,
+    ASN1_CONTEXT_S_5 =         0x85,
+    ASN1_CONTEXT_S_6 =         0x86,
+    ASN1_CONTEXT_S_7 =         0x87,
+    ASN1_CONTEXT_S_8 =         0x88,
+
+    ASN1_CONTEXT_C_0 =         0xA0,
+    ASN1_CONTEXT_C_1 =         0xA1,
+    ASN1_CONTEXT_C_2 =         0xA2,
+    ASN1_CONTEXT_C_3 =         0xA3,
+    ASN1_CONTEXT_C_4 =         0xA4,
+    ASN1_CONTEXT_C_5 =         0xA5
+} asn1_t;
+
+/* Definition of ASN1 flags */
+
+#define ASN1_NONE      0x00
+#define ASN1_DEF       0x01
+#define ASN1_OPT       0x02
+#define ASN1_LOOP      0x04
+#define ASN1_END       0x08
+#define ASN1_OBJ       0x10
+#define ASN1_BODY      0x20
+#define ASN1_RAW       0x40
+
+#define ASN1_INVALID_LENGTH    0xffffffff
+
+/* definition of an ASN.1 object */
+
+typedef struct {
+    u_int   level;
+    const u_char  *name;
+    asn1_t  type;
+    u_char  flags;
+} asn1Object_t;
+
+#define ASN1_MAX_LEVEL 10
+
+typedef struct {
+    bool  implicit;
+    u_int level0;
+    u_int loopAddr[ASN1_MAX_LEVEL+1];
+    chunk_t  blobs[ASN1_MAX_LEVEL+2];
+} asn1_ctx_t;
+
+/* some common prefabricated ASN.1 constants */
+
+extern const chunk_t ASN1_INTEGER_0;
+extern const chunk_t ASN1_INTEGER_1;
+extern const chunk_t ASN1_INTEGER_2;
+
+/* some popular algorithmIdentifiers */
+extern const chunk_t ASN1_md5_id;
+extern const chunk_t ASN1_sha1_id;
+extern const chunk_t ASN1_rsaEncryption_id;
+extern const chunk_t ASN1_md5WithRSA_id;
+extern const chunk_t ASN1_sha1WithRSA_id;
+
+extern chunk_t asn1_algorithmIdentifier(int oid);
+extern int known_oid(chunk_t object);
+extern u_int asn1_length(chunk_t *blob);
+extern bool is_printablestring(chunk_t str);
+extern time_t asn1totime(const chunk_t *utctime, asn1_t type);
+extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit);
+extern bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx);
+extern bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name);
+extern int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters);
+extern bool is_asn1(chunk_t blob);
+
+#endif /* _ASN1_H */
diff --git a/Source/lib/asn1-pluto/oid.c b/Source/lib/asn1-pluto/oid.c
new file mode 100644 (file)
index 0000000..7b0135d
--- /dev/null
@@ -0,0 +1,194 @@
+/* List of some useful object identifiers (OIDs)
+ * Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * 
+ * This file has been automatically generated by the script oid.pl
+ * Do not edit manually!
+ */
+
+#include <stdlib.h>
+
+#include "oid.h"
+
+const oid_t oid_names[] = {
+  {0x02,                       7, 1, "ITU-T Administration"   },  /*   0 */
+  {  0x82,                     0, 1, ""                       },  /*   1 */
+  {    0x06,                   0, 1, "Germany ITU-T member"   },  /*   2 */
+  {      0x01,                 0, 1, "Deutsche Telekom AG"    },  /*   3 */
+  {        0x0A,               0, 1, ""                       },  /*   4 */
+  {          0x07,             0, 1, ""                       },  /*   5 */
+  {            0x14,           0, 0, "ND"                     },  /*   6 */
+  {0x09,                      18, 1, "data"                   },  /*   7 */
+  {  0x92,                     0, 1, ""                       },  /*   8 */
+  {    0x26,                   0, 1, ""                       },  /*   9 */
+  {      0x89,                 0, 1, ""                       },  /*  10 */
+  {        0x93,               0, 1, ""                       },  /*  11 */
+  {          0xF2,             0, 1, ""                       },  /*  12 */
+  {            0x2C,           0, 1, ""                       },  /*  13 */
+  {              0x64,         0, 1, "pilot"                  },  /*  14 */
+  {                0x01,       0, 1, "pilotAttributeType"     },  /*  15 */
+  {                  0x01,    17, 0, "UID"                    },  /*  16 */
+  {                  0x19,     0, 0, "DC"                     },  /*  17 */
+  {0x55,                      51, 1, "X.500"                  },  /*  18 */
+  {  0x04,                    36, 1, "X.509"                  },  /*  19 */
+  {    0x03,                  21, 0, "CN"                     },  /*  20 */
+  {    0x04,                  22, 0, "S"                      },  /*  21 */
+  {    0x05,                  23, 0, "SN"                     },  /*  22 */
+  {    0x06,                  24, 0, "C"                      },  /*  23 */
+  {    0x07,                  25, 0, "L"                      },  /*  24 */
+  {    0x08,                  26, 0, "ST"                     },  /*  25 */
+  {    0x0A,                  27, 0, "O"                      },  /*  26 */
+  {    0x0B,                  28, 0, "OU"                     },  /*  27 */
+  {    0x0C,                  29, 0, "T"                      },  /*  28 */
+  {    0x0D,                  30, 0, "D"                      },  /*  29 */
+  {    0x24,                  31, 0, "userCertificate"        },  /*  30 */
+  {    0x29,                  32, 0, "N"                      },  /*  31 */
+  {    0x2A,                  33, 0, "G"                      },  /*  32 */
+  {    0x2B,                  34, 0, "I"                      },  /*  33 */
+  {    0x2D,                  35, 0, "ID"                     },  /*  34 */
+  {    0x48,                   0, 0, "role"                   },  /*  35 */
+  {  0x1D,                     0, 1, "id-ce"                  },  /*  36 */
+  {    0x09,                  38, 0, "subjectDirectoryAttrs"  },  /*  37 */
+  {    0x0E,                  39, 0, "subjectKeyIdentifier"   },  /*  38 */
+  {    0x0F,                  40, 0, "keyUsage"               },  /*  39 */
+  {    0x10,                  41, 0, "privateKeyUsagePeriod"  },  /*  40 */
+  {    0x11,                  42, 0, "subjectAltName"         },  /*  41 */
+  {    0x12,                  43, 0, "issuerAltName"          },  /*  42 */
+  {    0x13,                  44, 0, "basicConstraints"       },  /*  43 */
+  {    0x15,                  45, 0, "reasonCode"             },  /*  44 */
+  {    0x1F,                  46, 0, "crlDistributionPoints"  },  /*  45 */
+  {    0x20,                  47, 0, "certificatePolicies"    },  /*  46 */
+  {    0x23,                  48, 0, "authorityKeyIdentifier" },  /*  47 */
+  {    0x25,                  49, 0, "extendedKeyUsage"       },  /*  48 */
+  {    0x37,                  50, 0, "targetInformation"      },  /*  49 */
+  {    0x38,                   0, 0, "noRevAvail"             },  /*  50 */
+  {0x2A,                      88, 1, ""                       },  /*  51 */
+  {  0x86,                     0, 1, ""                       },  /*  52 */
+  {    0x48,                   0, 1, ""                       },  /*  53 */
+  {      0x86,                 0, 1, ""                       },  /*  54 */
+  {        0xF7,               0, 1, ""                       },  /*  55 */
+  {          0x0D,             0, 1, "RSADSI"                 },  /*  56 */
+  {            0x01,          83, 1, "PKCS"                   },  /*  57 */
+  {              0x01,        66, 1, "PKCS-1"                 },  /*  58 */
+  {                0x01,      60, 0, "rsaEncryption"          },  /*  59 */
+  {                0x02,      61, 0, "md2WithRSAEncryption"   },  /*  60 */
+  {                0x04,      62, 0, "md5WithRSAEncryption"   },  /*  61 */
+  {                0x05,      63, 0, "sha-1WithRSAEncryption" },  /*  62 */
+  {                0x0B,      64, 0, "sha256WithRSAEncryption"},  /*  63 */
+  {                0x0C,      65, 0, "sha384WithRSAEncryption"},  /*  64 */
+  {                0x0D,       0, 0, "sha512WithRSAEncryption"},  /*  65 */
+  {              0x07,        73, 1, "PKCS-7"                 },  /*  66 */
+  {                0x01,      68, 0, "data"                   },  /*  67 */
+  {                0x02,      69, 0, "signedData"             },  /*  68 */
+  {                0x03,      70, 0, "envelopedData"          },  /*  69 */
+  {                0x04,      71, 0, "signedAndEnvelopedData" },  /*  70 */
+  {                0x05,      72, 0, "digestedData"           },  /*  71 */
+  {                0x06,       0, 0, "encryptedData"          },  /*  72 */
+  {              0x09,         0, 1, "PKCS-9"                 },  /*  73 */
+  {                0x01,      75, 0, "E"                      },  /*  74 */
+  {                0x02,      76, 0, "unstructuredName"       },  /*  75 */
+  {                0x03,      77, 0, "contentType"            },  /*  76 */
+  {                0x04,      78, 0, "messageDigest"          },  /*  77 */
+  {                0x05,      79, 0, "signingTime"            },  /*  78 */
+  {                0x06,      80, 0, "counterSignature"       },  /*  79 */
+  {                0x07,      81, 0, "challengePassword"      },  /*  80 */
+  {                0x08,      82, 0, "unstructuredAddress"    },  /*  81 */
+  {                0x0E,       0, 0, "extensionRequest"       },  /*  82 */
+  {            0x02,          86, 1, "digestAlgorithm"        },  /*  83 */
+  {              0x02,        85, 0, "md2"                    },  /*  84 */
+  {              0x05,         0, 0, "md5"                    },  /*  85 */
+  {            0x03,           0, 1, "encryptionAlgorithm"    },  /*  86 */
+  {              0x07,         0, 0, "3des-ede-cbc"           },  /*  87 */
+  {0x2B,                     149, 1, ""                       },  /*  88 */
+  {  0x06,                   136, 1, "dod"                    },  /*  89 */
+  {    0x01,                   0, 1, "internet"               },  /*  90 */
+  {      0x04,               105, 1, "private"                },  /*  91 */
+  {        0x01,               0, 1, "enterprise"             },  /*  92 */
+  {          0x82,            98, 1, ""                       },  /*  93 */
+  {            0x37,           0, 1, "Microsoft"              },  /*  94 */
+  {              0x0A,         0, 1, ""                       },  /*  95 */
+  {                0x03,       0, 1, ""                       },  /*  96 */
+  {                  0x03,     0, 0, "msSGC"                  },  /*  97 */
+  {          0x89,             0, 1, ""                       },  /*  98 */
+  {            0x31,           0, 1, ""                       },  /*  99 */
+  {              0x01,         0, 1, ""                       },  /* 100 */
+  {                0x01,       0, 1, ""                       },  /* 101 */
+  {                  0x02,     0, 1, ""                       },  /* 102 */
+  {                    0x02, 104, 0, ""                       },  /* 103 */
+  {                    0x4B,   0, 0, "TCGID"                  },  /* 104 */
+  {      0x05,                 0, 1, "security"               },  /* 105 */
+  {        0x05,               0, 1, "mechanisms"             },  /* 106 */
+  {          0x07,             0, 1, "id-pkix"                },  /* 107 */
+  {            0x01,         110, 1, "id-pe"                  },  /* 108 */
+  {              0x01,         0, 0, "authorityInfoAccess"    },  /* 109 */
+  {            0x03,         120, 1, "id-kp"                  },  /* 110 */
+  {              0x01,       112, 0, "serverAuth"             },  /* 111 */
+  {              0x02,       113, 0, "clientAuth"             },  /* 112 */
+  {              0x03,       114, 0, "codeSigning"            },  /* 113 */
+  {              0x04,       115, 0, "emailProtection"        },  /* 114 */
+  {              0x05,       116, 0, "ipsecEndSystem"         },  /* 115 */
+  {              0x06,       117, 0, "ipsecTunnel"            },  /* 116 */
+  {              0x07,       118, 0, "ipsecUser"              },  /* 117 */
+  {              0x08,       119, 0, "timeStamping"           },  /* 118 */
+  {              0x09,         0, 0, "ocspSigning"            },  /* 119 */
+  {            0x08,         122, 1, "id-otherNames"          },  /* 120 */
+  {              0x05,         0, 0, "xmppAddr"               },  /* 121 */
+  {            0x0A,         127, 1, "id-aca"                 },  /* 122 */
+  {              0x01,       124, 0, "authenticationInfo"     },  /* 123 */
+  {              0x02,       125, 0, "accessIdentity"         },  /* 124 */
+  {              0x03,       126, 0, "chargingIdentity"       },  /* 125 */
+  {              0x04,         0, 0, "group"                  },  /* 126 */
+  {            0x30,           0, 1, "id-ad"                  },  /* 127 */
+  {              0x01,         0, 1, "ocsp"                   },  /* 128 */
+  {                0x01,     130, 0, "basic"                  },  /* 129 */
+  {                0x02,     131, 0, "nonce"                  },  /* 130 */
+  {                0x03,     132, 0, "crl"                    },  /* 131 */
+  {                0x04,     133, 0, "response"               },  /* 132 */
+  {                0x05,     134, 0, "noCheck"                },  /* 133 */
+  {                0x06,     135, 0, "archiveCutoff"          },  /* 134 */
+  {                0x07,       0, 0, "serviceLocator"         },  /* 135 */
+  {  0x0E,                   142, 1, "oiw"                    },  /* 136 */
+  {    0x03,                   0, 1, "secsig"                 },  /* 137 */
+  {      0x02,                 0, 1, "algorithms"             },  /* 138 */
+  {        0x07,             140, 0, "des-cbc"                },  /* 139 */
+  {        0x1A,             141, 0, "sha-1"                  },  /* 140 */
+  {        0x1D,               0, 0, "sha-1WithRSASignature"  },  /* 141 */
+  {  0x24,                     0, 1, "TeleTrusT"              },  /* 142 */
+  {    0x03,                   0, 1, "algorithm"              },  /* 143 */
+  {      0x03,                 0, 1, "signatureAlgorithm"     },  /* 144 */
+  {        0x01,               0, 1, "rsaSignature"           },  /* 145 */
+  {          0x02,           147, 0, "rsaSigWithripemd160"    },  /* 146 */
+  {          0x03,           148, 0, "rsaSigWithripemd128"    },  /* 147 */
+  {          0x04,             0, 0, "rsaSigWithripemd256"    },  /* 148 */
+  {0x60,                       0, 1, ""                       },  /* 149 */
+  {  0x86,                     0, 1, ""                       },  /* 150 */
+  {    0x48,                   0, 1, ""                       },  /* 151 */
+  {      0x01,                 0, 1, "organization"           },  /* 152 */
+  {        0x65,             160, 1, "gov"                    },  /* 153 */
+  {          0x03,             0, 1, "csor"                   },  /* 154 */
+  {            0x04,           0, 1, "nistalgorithm"          },  /* 155 */
+  {              0x02,         0, 1, "hashalgs"               },  /* 156 */
+  {                0x01,     158, 0, "id-SHA-256"             },  /* 157 */
+  {                0x02,     159, 0, "id-SHA-384"             },  /* 158 */
+  {                0x03,       0, 0, "id-SHA-512"             },  /* 159 */
+  {        0x86,               0, 1, ""                       },  /* 160 */
+  {          0xf8,             0, 1, ""                       },  /* 161 */
+  {            0x42,         171, 1, "netscape"               },  /* 162 */
+  {              0x01,       169, 1, ""                       },  /* 163 */
+  {                0x01,     165, 0, "nsCertType"             },  /* 164 */
+  {                0x03,     166, 0, "nsRevocationUrl"        },  /* 165 */
+  {                0x04,     167, 0, "nsCaRevocationUrl"      },  /* 166 */
+  {                0x08,     168, 0, "nsCaPolicyUrl"          },  /* 167 */
+  {                0x0d,       0, 0, "nsComment"              },  /* 168 */
+  {              0x04,         0, 1, "policy"                 },  /* 169 */
+  {                0x01,       0, 0, "nsSGC"                  },  /* 170 */
+  {            0x45,           0, 1, "verisign"               },  /* 171 */
+  {              0x01,         0, 1, "pki"                    },  /* 172 */
+  {                0x09,       0, 1, "attributes"             },  /* 173 */
+  {                  0x02,   175, 0, "messageType"            },  /* 174 */
+  {                  0x03,   176, 0, "pkiStatus"              },  /* 175 */
+  {                  0x04,   177, 0, "failInfo"               },  /* 176 */
+  {                  0x05,   178, 0, "senderNonce"            },  /* 177 */
+  {                  0x06,   179, 0, "recipientNonce"         },  /* 178 */
+  {                  0x07,   180, 0, "transID"                },  /* 179 */
+  {                  0x08,     0, 0, "extensionReq"           }   /* 180 */
+};
diff --git a/Source/lib/asn1-pluto/oid.h b/Source/lib/asn1-pluto/oid.h
new file mode 100644 (file)
index 0000000..4096af3
--- /dev/null
@@ -0,0 +1,75 @@
+/* Object identifiers (OIDs) used by FreeS/WAN
+ * Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * 
+ * This file has been automatically generated by the script oid.pl
+ * Do not edit manually!
+ */
+
+typedef struct {
+    u_char octet;
+    u_int  next;
+    u_int  down;
+    const u_char *name;
+} oid_t;
+
+extern const oid_t oid_names[];
+
+#define OID_UNKNOWN                    -1
+#define OID_ROLE                       35
+#define OID_SUBJECT_KEY_ID             38
+#define OID_SUBJECT_ALT_NAME           41
+#define OID_BASIC_CONSTRAINTS          43
+#define OID_CRL_REASON_CODE            44
+#define OID_CRL_DISTRIBUTION_POINTS    45
+#define OID_AUTHORITY_KEY_ID           47
+#define OID_EXTENDED_KEY_USAGE         48
+#define OID_TARGET_INFORMATION         49
+#define OID_NO_REV_AVAIL               50
+#define OID_RSA_ENCRYPTION             59
+#define OID_MD2_WITH_RSA               60
+#define OID_MD5_WITH_RSA               61
+#define OID_SHA1_WITH_RSA              62
+#define OID_SHA256_WITH_RSA            63
+#define OID_SHA384_WITH_RSA            64
+#define OID_SHA512_WITH_RSA            65
+#define OID_PKCS7_DATA                 67
+#define OID_PKCS7_SIGNED_DATA          68
+#define OID_PKCS7_ENVELOPED_DATA       69
+#define OID_PKCS7_SIGNED_ENVELOPED_DATA        70
+#define OID_PKCS7_DIGESTED_DATA                71
+#define OID_PKCS7_ENCRYPTED_DATA       72
+#define OID_PKCS9_EMAIL                        74
+#define OID_PKCS9_CONTENT_TYPE         76
+#define OID_PKCS9_MESSAGE_DIGEST       77
+#define OID_PKCS9_SIGNING_TIME         78
+#define OID_MD2                                84
+#define OID_MD5                                85
+#define OID_3DES_EDE_CBC               87
+#define OID_AUTHORITY_INFO_ACCESS      109
+#define OID_OCSP_SIGNING               119
+#define OID_XMPP_ADDR                  121
+#define OID_AUTHENTICATION_INFO                123
+#define OID_ACCESS_IDENTITY            124
+#define OID_CHARGING_IDENTITY          125
+#define OID_GROUP                      126
+#define OID_OCSP                       128
+#define OID_BASIC                      129
+#define OID_NONCE                      130
+#define OID_CRL                                131
+#define OID_RESPONSE                   132
+#define OID_NO_CHECK                   133
+#define OID_ARCHIVE_CUTOFF             134
+#define OID_SERVICE_LOCATOR            135
+#define OID_DES_CBC                    139
+#define OID_SHA1                       140
+#define OID_SHA1_WITH_RSA_OIW          141
+#define OID_NS_REVOCATION_URL          165
+#define OID_NS_CA_REVOCATION_URL       166
+#define OID_NS_CA_POLICY_URL           167
+#define OID_NS_COMMENT                 168
+#define OID_PKI_MESSAGE_TYPE           174
+#define OID_PKI_STATUS                 175
+#define OID_PKI_FAIL_INFO              176
+#define OID_PKI_SENDER_NONCE           177
+#define OID_PKI_RECIPIENT_NONCE                178
+#define OID_PKI_TRANS_ID               179
diff --git a/Source/lib/asn1-pluto/oid.pl b/Source/lib/asn1-pluto/oid.pl
new file mode 100644 (file)
index 0000000..52ac8ea
--- /dev/null
@@ -0,0 +1,123 @@
+#!/usr/bin/perl
+# Generates oid.h and oid.c out of oid.txt
+# Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+
+$copyright="Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur";
+$automatic="This file has been automatically generated by the script oid.pl";
+$warning="Do not edit manually!";
+
+print "oid.pl generating oid.h and oid.c\n";
+
+# Generate oid.h
+
+open(OID_H,  ">oid.h")
+    or die "could not open 'oid.h': $!";
+
+print OID_H "/* Object identifiers (OIDs) used by FreeS/WAN\n",
+           " * ", $copyright, "\n",
+           " * \n",
+           " * ", $automatic, "\n",
+           " * ", $warning, "\n",
+           " */\n\n",
+           "typedef struct {\n",
+           "    u_char octet;\n",
+           "    u_int  next;\n",
+           "    u_int  down;\n",
+           "    const u_char *name;\n",
+           "} oid_t;\n",
+           "\n",
+            "extern const oid_t oid_names[];\n",
+           "\n",
+           "#define OID_UNKNOWN                        -1\n";
+
+# parse oid.txt
+
+open(SRC,  "<oid.txt")
+    or die "could not open 'oid.txt': $!";
+
+$counter = 0;
+$max_name = 0;
+$max_order = 0;
+
+while ($line = <SRC>)
+{
+    $line =~ m/( *?)(0x\w{2})\s+(".*?")[ \t]*?([\w_]*?)\Z/;
+
+    @order[$counter] = length($1);
+    @octet[$counter] = $2;
+    @name[$counter] = $3;
+
+    if (length($1) > $max_order)
+    {
+       $max_order = length($1);
+    }
+    if (length($3) > $max_name)
+    {
+       $max_name = length($3);
+    }
+    if (length($4) > 0)
+    {
+       printf OID_H "#define %s%s%d\n", $4, "\t" x ((39-length($4))/8), $counter;
+    }
+    $counter++;
+}
+
+close SRC;
+close OID_H;
+
+# Generate oid.c
+
+open(OID_C, ">oid.c")
+    or die "could not open 'oid.c': $!";
+
+print OID_C "/* List of some useful object identifiers (OIDs)\n",
+            " * ", $copyright, "\n",
+           " * \n",
+           " * ", $automatic, "\n",
+           " * ", $warning, "\n",
+           " */\n",
+           "\n",
+           "#include <stdlib.h>\n",
+           "\n",
+           "#include \"oid.h\"\n",
+           "\n",
+            "const oid_t oid_names[] = {\n";
+
+for ($c = 0; $c < $counter; $c++)
+{
+    $next = 0;
+
+    for ($d = $c+1; $d < $counter && @order[$d] >= @order[$c]; $d++)
+    {
+       if (@order[$d] == @order[$c])
+       {
+           @next[$c] = $d;
+           last;
+       }
+    }
+
+    printf OID_C "  {%s%s,%s%3d, %d, %s%s}%s  /* %3d */\n"
+       ,' '  x @order[$c]
+       , @octet[$c]
+       , ' ' x (1 + $max_order - @order[$c])
+       , @next[$c]
+       , @order[$c+1] > @order[$c]
+       , @name[$c]
+       , ' ' x ($max_name - length(@name[$c]))
+       , $c != $counter-1 ? "," : " "
+       , $c;
+}
+
+print OID_C "};\n" ;
+close OID_C;
diff --git a/Source/lib/asn1-pluto/oid.txt b/Source/lib/asn1-pluto/oid.txt
new file mode 100644 (file)
index 0000000..ad05a12
--- /dev/null
@@ -0,0 +1,181 @@
+0x02                         "ITU-T Administration"
+  0x82                       ""
+    0x06                     "Germany ITU-T member"
+      0x01                   "Deutsche Telekom AG"
+        0x0A                 ""
+          0x07               ""
+            0x14             "ND"
+0x09                         "data"
+  0x92                       ""
+    0x26                     ""
+      0x89                   ""
+        0x93                 ""
+          0xF2               ""
+            0x2C             ""
+              0x64           "pilot"
+                0x01         "pilotAttributeType"
+                  0x01       "UID"
+                  0x19       "DC"
+0x55                         "X.500"
+  0x04                       "X.509"
+    0x03                     "CN"
+    0x04                     "S"
+    0x05                     "SN"
+    0x06                     "C"
+    0x07                     "L"
+    0x08                     "ST"
+    0x0A                     "O"
+    0x0B                     "OU"
+    0x0C                     "T"
+    0x0D                     "D"
+    0x24                     "userCertificate"
+    0x29                     "N"
+    0x2A                     "G"
+    0x2B                     "I"
+    0x2D                     "ID"
+    0x48                     "role"                    OID_ROLE
+  0x1D                       "id-ce"
+    0x09                     "subjectDirectoryAttrs"
+    0x0E                     "subjectKeyIdentifier"    OID_SUBJECT_KEY_ID
+    0x0F                     "keyUsage"
+    0x10                     "privateKeyUsagePeriod"
+    0x11                     "subjectAltName"          OID_SUBJECT_ALT_NAME
+    0x12                     "issuerAltName"
+    0x13                     "basicConstraints"                OID_BASIC_CONSTRAINTS
+    0x15                     "reasonCode"              OID_CRL_REASON_CODE
+    0x1F                     "crlDistributionPoints"   OID_CRL_DISTRIBUTION_POINTS
+    0x20                     "certificatePolicies"
+    0x23                     "authorityKeyIdentifier"  OID_AUTHORITY_KEY_ID
+    0x25                     "extendedKeyUsage"                OID_EXTENDED_KEY_USAGE
+    0x37                     "targetInformation"       OID_TARGET_INFORMATION
+    0x38                     "noRevAvail"              OID_NO_REV_AVAIL
+0x2A                         ""
+  0x86                       ""
+    0x48                     ""
+      0x86                   ""
+        0xF7                 ""
+          0x0D               "RSADSI"
+            0x01             "PKCS"
+              0x01           "PKCS-1"
+                0x01         "rsaEncryption"           OID_RSA_ENCRYPTION
+                0x02         "md2WithRSAEncryption"    OID_MD2_WITH_RSA
+                0x04         "md5WithRSAEncryption"    OID_MD5_WITH_RSA
+                0x05         "sha-1WithRSAEncryption"  OID_SHA1_WITH_RSA
+                0x0B         "sha256WithRSAEncryption" OID_SHA256_WITH_RSA
+                0x0C         "sha384WithRSAEncryption" OID_SHA384_WITH_RSA
+                0x0D         "sha512WithRSAEncryption" OID_SHA512_WITH_RSA
+              0x07           "PKCS-7"
+                0x01         "data"                    OID_PKCS7_DATA
+                0x02         "signedData"              OID_PKCS7_SIGNED_DATA
+                0x03         "envelopedData"           OID_PKCS7_ENVELOPED_DATA
+                0x04         "signedAndEnvelopedData"  OID_PKCS7_SIGNED_ENVELOPED_DATA
+                0x05         "digestedData"            OID_PKCS7_DIGESTED_DATA
+                0x06         "encryptedData"           OID_PKCS7_ENCRYPTED_DATA
+              0x09           "PKCS-9"
+                0x01         "E"                       OID_PKCS9_EMAIL
+                0x02         "unstructuredName"
+                0x03         "contentType"             OID_PKCS9_CONTENT_TYPE
+                0x04         "messageDigest"           OID_PKCS9_MESSAGE_DIGEST
+                0x05         "signingTime"             OID_PKCS9_SIGNING_TIME
+                0x06         "counterSignature"
+                0x07         "challengePassword"
+                0x08         "unstructuredAddress"
+                0x0E         "extensionRequest"
+            0x02             "digestAlgorithm"
+              0x02           "md2"                     OID_MD2
+              0x05           "md5"                     OID_MD5
+            0x03             "encryptionAlgorithm"
+              0x07           "3des-ede-cbc"            OID_3DES_EDE_CBC
+0x2B                         ""
+  0x06                       "dod"
+    0x01                     "internet"
+      0x04                   "private"
+        0x01                 "enterprise"
+          0x82               ""
+            0x37             "Microsoft"
+              0x0A           ""
+                0x03         ""
+                  0x03       "msSGC"
+          0x89               ""
+            0x31             ""
+              0x01           ""
+                0x01         ""
+                  0x02       ""
+                    0x02     ""
+                    0x4B     "TCGID"
+      0x05                   "security"
+        0x05                 "mechanisms"
+          0x07               "id-pkix"
+            0x01             "id-pe"
+              0x01           "authorityInfoAccess"     OID_AUTHORITY_INFO_ACCESS
+            0x03             "id-kp"
+              0x01           "serverAuth"
+              0x02           "clientAuth"
+              0x03           "codeSigning"
+              0x04           "emailProtection"
+              0x05           "ipsecEndSystem"
+              0x06           "ipsecTunnel"
+              0x07           "ipsecUser"
+              0x08           "timeStamping"
+              0x09           "ocspSigning"             OID_OCSP_SIGNING
+            0x08             "id-otherNames"
+              0x05           "xmppAddr"                        OID_XMPP_ADDR
+            0x0A             "id-aca"
+              0x01           "authenticationInfo"      OID_AUTHENTICATION_INFO
+              0x02           "accessIdentity"          OID_ACCESS_IDENTITY
+              0x03           "chargingIdentity"                OID_CHARGING_IDENTITY
+              0x04           "group"                   OID_GROUP
+            0x30             "id-ad"
+              0x01           "ocsp"                    OID_OCSP
+                0x01         "basic"                   OID_BASIC
+                0x02         "nonce"                   OID_NONCE
+                0x03         "crl"                     OID_CRL
+                0x04         "response"                        OID_RESPONSE
+                0x05         "noCheck"                 OID_NO_CHECK
+                0x06         "archiveCutoff"           OID_ARCHIVE_CUTOFF
+                0x07         "serviceLocator"          OID_SERVICE_LOCATOR
+  0x0E                       "oiw"
+    0x03                     "secsig"
+      0x02                   "algorithms"
+        0x07                 "des-cbc"                 OID_DES_CBC
+        0x1A                 "sha-1"                   OID_SHA1
+        0x1D                 "sha-1WithRSASignature"   OID_SHA1_WITH_RSA_OIW
+  0x24                       "TeleTrusT"
+    0x03                     "algorithm"
+      0x03                   "signatureAlgorithm"
+        0x01                 "rsaSignature"
+          0x02               "rsaSigWithripemd160"
+          0x03               "rsaSigWithripemd128"
+          0x04               "rsaSigWithripemd256"
+0x60                         ""
+  0x86                       ""
+    0x48                     ""
+      0x01                   "organization"
+        0x65                 "gov"
+          0x03               "csor"
+            0x04             "nistalgorithm"
+              0x02           "hashalgs"
+                0x01         "id-SHA-256"
+                0x02         "id-SHA-384"
+                0x03         "id-SHA-512"
+        0x86                 ""
+          0xf8               ""
+            0x42             "netscape"
+              0x01           ""
+                0x01         "nsCertType"
+                0x03         "nsRevocationUrl"         OID_NS_REVOCATION_URL
+                0x04         "nsCaRevocationUrl"       OID_NS_CA_REVOCATION_URL
+                0x08         "nsCaPolicyUrl"           OID_NS_CA_POLICY_URL
+                0x0d         "nsComment"               OID_NS_COMMENT
+              0x04           "policy"
+                0x01         "nsSGC"
+            0x45             "verisign"
+              0x01           "pki"
+                0x09         "attributes"
+                  0x02       "messageType"             OID_PKI_MESSAGE_TYPE
+                  0x03       "pkiStatus"               OID_PKI_STATUS
+                  0x04       "failInfo"                        OID_PKI_FAIL_INFO
+                  0x05       "senderNonce"             OID_PKI_SENDER_NONCE
+                  0x06       "recipientNonce"          OID_PKI_RECIPIENT_NONCE
+                  0x07       "transID"                 OID_PKI_TRANS_ID
+                  0x08       "extensionReq"
diff --git a/Source/lib/asn1-pluto/pem.c b/Source/lib/asn1-pluto/pem.c
new file mode 100755 (executable)
index 0000000..24c71c6
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2005 Jan Hutter, Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include "pem.h"
+#include "ttodata.h"
+
+#include <crypto/hashers/hasher.h>
+#include <crypto/crypters/crypter.h>
+
+
+/*
+ * check the presence of a pattern in a character string
+ */
+static bool present(const char* pattern, chunk_t* ch)
+{
+       u_int pattern_len = strlen(pattern);
+
+       if (ch->len >= pattern_len && strncmp(ch->ptr, pattern, pattern_len) == 0)
+       {
+               ch->ptr += pattern_len;
+               ch->len -= pattern_len;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+/*
+ * compare string with chunk
+ */
+static bool match(const char *pattern, const chunk_t *ch)
+{
+       return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
+}
+
+/*
+ * find a boundary of the form -----tag name-----
+ */
+static bool find_boundary(const char* tag, chunk_t *line)
+{
+       chunk_t name = CHUNK_INITIALIZER;
+
+       if (!present("-----", line))
+               return FALSE;
+       if (!present(tag, line))
+               return FALSE;
+       if (*line->ptr != ' ')
+               return FALSE;
+       line->ptr++;  line->len--;
+       
+       /* extract name */
+       name.ptr = line->ptr;
+       while (line->len > 0)
+       {
+               if (present("-----", line))
+               {
+                       return TRUE;
+               }
+               line->ptr++;  line->len--;  name.len++;
+       }
+       return FALSE;
+}
+
+/*
+ * eat whitespace
+ */
+static void eat_whitespace(chunk_t *src)
+{
+       while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
+       {
+               src->ptr++;  src->len--;
+       }
+}
+
+/*
+ * extracts a token ending with a given termination symbol
+ */
+static bool extract_token(chunk_t *token, char termination, chunk_t *src)
+{
+       u_char *eot = memchr(src->ptr, termination, src->len);
+       
+       /* initialize empty token */
+       *token = CHUNK_INITIALIZER;
+       
+       if (eot == NULL) /* termination symbol not found */
+       {
+               return FALSE;
+       }
+       
+       /* extract token */
+       token->ptr = src->ptr;
+       token->len = (u_int)(eot - src->ptr);
+       
+       /* advance src pointer after termination symbol */
+       src->ptr = eot + 1;
+       src->len -= (token->len + 1);
+       
+       return TRUE;
+}
+
+/*
+ * extracts a name: value pair from the PEM header
+ */
+static bool extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line)
+{
+       /* extract name */
+       if (!extract_token(name,':', line))
+       {
+               return FALSE;
+       }
+       
+       eat_whitespace(line);
+       
+       /* extract value */
+       *value = *line;
+       return TRUE;
+}
+
+/*
+ *  fetches a new line terminated by \n or \r\n
+ */
+static bool fetchline(chunk_t *src, chunk_t *line)
+{
+       if (src->len == 0) /* end of src reached */
+               return FALSE;
+
+       if (extract_token(line, '\n', src))
+       {
+               if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
+                       line->len--;  /* remove optional \r */
+       }
+       else /*last line ends without newline */
+       {
+               *line = *src;
+               src->ptr += src->len;
+               src->len = 0;
+       }
+       return TRUE;
+}
+
+/*
+ * decrypts a DES-EDE-CBC encrypted data block
+ */
+static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase)
+{
+       hasher_t *hasher;
+       crypter_t *crypter;
+       chunk_t hash;
+       chunk_t decrypted;
+       chunk_t pass = {passphrase, strlen(passphrase)};
+       chunk_t key = {alloca(24), 24};
+       u_int8_t padding, *last_padding_pos, *first_padding_pos;
+       
+       /* build key from passphrase and IV */
+       hasher = hasher_create(HASH_MD5);
+       hash.len = hasher->get_block_size(hasher);
+       hash.ptr = alloca(hash.len);
+       hasher->get_hash(hasher, pass, NULL);
+       hasher->get_hash(hasher, *iv, hash.ptr);
+       
+       memcpy(key.ptr, hash.ptr, hash.len);
+       
+       hasher->get_hash(hasher, hash, NULL);
+       hasher->get_hash(hasher, pass, NULL);
+       hasher->get_hash(hasher, *iv, hash.ptr);
+       
+       memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len);
+       
+       hasher->destroy(hasher);
+       
+       /* decrypt blob */
+       crypter = crypter_create(ENCR_3DES, 0);
+       crypter->set_key(crypter, key);
+       crypter->decrypt(crypter, *blob, *iv, &decrypted);
+       memcpy(blob->ptr, decrypted.ptr, blob->len);
+       chunk_free(&decrypted);
+       
+       /* determine amount of padding */
+       last_padding_pos = blob->ptr + blob->len - 1;
+       padding = *last_padding_pos;
+       first_padding_pos = (padding > blob->len) ? blob->ptr : last_padding_pos - padding;
+
+       /* check the padding pattern */
+       while (--last_padding_pos > first_padding_pos)
+       {
+               if (*last_padding_pos != padding)
+                       return FALSE;
+       }
+       /* remove padding */
+       blob->len -= padding;
+       return TRUE;
+}
+
+/*  Converts a PEM encoded file into its binary form
+ *
+ *  RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
+ *  RFC 934 Message Encapsulation, January 1985
+ */
+status_t pemtobin(chunk_t *blob, char *pass)
+{
+       typedef enum {
+               PEM_PRE    = 0,
+               PEM_MSG    = 1,
+               PEM_HEADER = 2,
+               PEM_BODY   = 3,
+               PEM_POST   = 4,
+               PEM_ABORT  = 5
+       } state_t;
+
+       bool encrypted = FALSE;
+
+       state_t state  = PEM_PRE;
+
+       chunk_t src    = *blob;
+       chunk_t dst    = *blob;
+       chunk_t line   = CHUNK_INITIALIZER;
+       chunk_t iv     = CHUNK_INITIALIZER;
+
+       u_char iv_buf[16]; /* MD5 digest size */
+
+       /* zero size of converted blob */
+       dst.len = 0;
+
+       /* zero size of IV */
+       iv.ptr = iv_buf;
+       iv.len = 0;
+
+       while (fetchline(&src, &line))
+       {
+               if (state == PEM_PRE)
+               {
+                       if (find_boundary("BEGIN", &line))
+                       {
+                               state = PEM_MSG;
+                       }
+                       continue;
+               }
+               else
+               {
+                       if (find_boundary("END", &line))
+                       {
+                               state = PEM_POST;
+                               break;
+                       }
+                       if (state == PEM_MSG)
+                       {
+                               state = (memchr(line.ptr, ':', line.len) == NULL) ? PEM_BODY : PEM_HEADER;
+                       }
+                       if (state == PEM_HEADER)
+                       {
+                               chunk_t name  = CHUNK_INITIALIZER;
+                               chunk_t value = CHUNK_INITIALIZER;
+
+                               /* an empty line separates HEADER and BODY */
+                               if (line.len == 0)
+                               {
+                                       state = PEM_BODY;
+                                       continue;
+                               }
+
+                               /* we are looking for a name: value pair */
+                               if (!extract_parameter(&name, &value, &line))
+                                       continue;
+
+                               if (match("Proc-Type", &name) && *value.ptr == '4')
+                                       encrypted = TRUE;
+                               else if (match("DEK-Info", &name))
+                               {
+                                       const char *ugh = NULL;
+                                       size_t len = 0;
+                                       chunk_t dek;
+
+                                       if (!extract_token(&dek, ',', &value))
+                                               dek = value;
+
+                                       /* we support DES-EDE3-CBC encrypted files, only */
+                                       if (!match("DES-EDE3-CBC", &dek))
+                                               return NOT_SUPPORTED;
+
+                                       eat_whitespace(&value);
+                                       ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len);
+                                       if (ugh)
+                                               return PARSE_ERROR;
+
+                                       iv.len = len;
+                               }
+                       }
+                       else /* state is PEM_BODY */
+                       {
+                               const char *ugh = NULL;
+                               size_t len = 0;
+                               chunk_t data;
+                               
+                               /* remove any trailing whitespace */
+                               if (!extract_token(&data ,' ', &line))
+                               {
+                                       data = line;
+                               }
+                               
+                               ugh = ttodata(data.ptr, data.len, 64, dst.ptr, blob->len - dst.len, &len);
+                               if (ugh)
+                               {
+                                       state = PEM_ABORT;
+                                       break;
+                               }
+                               else
+                               {
+                                       dst.ptr += len;
+                                       dst.len += len;
+                               }
+                       }
+               }
+       }
+       /* set length to size of binary blob */
+       blob->len = dst.len;
+
+       if (state != PEM_POST)
+               return PARSE_ERROR;
+
+       if (encrypted)
+               return pem_decrypt(blob, &iv, pass);
+       else
+               return SUCCESS;
+}
diff --git a/Source/lib/asn1-pluto/pem.h b/Source/lib/asn1-pluto/pem.h
new file mode 100755 (executable)
index 0000000..a4332fd
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PEM_H_
+#define PEM_H_
+
+#include <stdio.h>
+
+#include <types.h>
+
+status_t pemtobin(chunk_t *blob, char *pass);
+
+#endif /*PEM_H_*/
diff --git a/Source/lib/asn1-pluto/ttodata.c b/Source/lib/asn1-pluto/ttodata.c
new file mode 100644 (file)
index 0000000..3ef5acd
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * convert from text form of arbitrary data (e.g., keys) to binary
+ * Copyright (C) 2000  Henry Spencer.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+ * License for more details.
+ */
+
+#include "ttodata.h"
+
+#include <string.h>
+#include <ctype.h>
+
+/* converters and misc */
+static int unhex(const char *, char *, size_t);
+static int unb64(const char *, char *, size_t);
+static int untext(const char *, char *, size_t);
+static const char *badch(const char *, int, char *, size_t);
+
+/* internal error codes for converters */
+#define        SHORT   (-2)            /* internal buffer too short */
+#define        BADPAD  (-3)            /* bad base64 padding */
+#define        BADCH0  (-4)            /* invalid character 0 */
+#define        BADCH1  (-5)            /* invalid character 1 */
+#define        BADCH2  (-6)            /* invalid character 2 */
+#define        BADCH3  (-7)            /* invalid character 3 */
+#define        BADOFF(code) (BADCH0-(code))
+
+/*
+ - ttodatav - convert text to data, with verbose error reports
+ * If some of this looks slightly odd, it's because it has changed
+ * repeatedly (from the original atodata()) without a major rewrite.
+ */
+const char *                   /* NULL on success, else literal or errp */
+ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen, flags)
+const char *src;
+size_t srclen;                 /* 0 means apply strlen() */
+int base;                      /* 0 means figure it out */
+char *dst;                     /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp;                  /* where to record length (NULL is nowhere) */
+char *errp;                    /* error buffer */
+size_t errlen;
+unsigned int flags;
+{
+       size_t ingroup; /* number of input bytes converted at once */
+       char buf[4];            /* output from conversion */
+       int nbytes;             /* size of output */
+       int (*decode)(const char *, char *, size_t);
+       char *stop;
+       int ndone;
+       int i;
+       int underscoreok;
+       int skipSpace = 0;
+
+       if (srclen == 0)
+               srclen = strlen(src);
+       if (dstlen == 0)
+               dst = buf;      /* point it somewhere valid */
+       stop = dst + dstlen;
+
+       if (base == 0) {
+               if (srclen < 2)
+                       return "input too short to be valid";
+               if (*src++ != '0')
+                       return "input does not begin with format prefix";
+               switch (*src++) {
+               case 'x':
+               case 'X':
+                       base = 16;
+                       break;
+               case 's':
+               case 'S':
+                       base = 64;
+                       break;
+               case 't':
+               case 'T':
+                       base = 256;
+                       break;
+               default:
+                       return "unknown format prefix";
+               }
+               srclen -= 2;
+       }
+       switch (base) {
+       case 16:
+               decode = unhex;
+               underscoreok = 1;
+               ingroup = 2;
+               break;
+       case 64:
+               decode = unb64;
+               underscoreok = 0;
+               ingroup = 4;
+               if(flags & TTODATAV_IGNORESPACE) {
+                       skipSpace = 1;
+               }
+               break;
+
+       case 256:
+               decode = untext;
+               ingroup = 1;
+               underscoreok = 0;
+               break;
+       default:
+               return "unknown base";
+       }
+
+       /* proceed */
+       ndone = 0;
+       while (srclen > 0) {
+               char stage[4];  /* staging area for group */
+               size_t sl = 0;
+
+               /* Grab ingroup characters into stage,
+                * squeezing out blanks if we are supposed to ignore them.
+                */
+               for (sl = 0; sl < ingroup; src++, srclen--) {
+                       if (srclen == 0)
+                               return "input ends in mid-byte, perhaps truncated";
+                       else if (!(skipSpace && (*src == ' ' || *src == '\t')))
+                               stage[sl++] = *src;
+               }
+               
+               nbytes = (*decode)(stage, buf, sizeof(buf));
+               switch (nbytes) {
+               case BADCH0:
+               case BADCH1:
+               case BADCH2:
+               case BADCH3:
+                       return badch(stage, nbytes, errp, errlen);
+               case SHORT:
+                       return "internal buffer too short (\"can't happen\")";
+               case BADPAD:
+                       return "bad (non-zero) padding at end of base64 input";
+               }
+               if (nbytes <= 0)
+                       return "unknown internal error";
+               for (i = 0; i < nbytes; i++) {
+                       if (dst < stop)
+                               *dst++ = buf[i];
+                       ndone++;
+               }
+               while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t')){
+                       src++;
+                       srclen--;
+               }
+               if (underscoreok && srclen > 1 && *src == '_') {
+                       /* srclen > 1 means not last character */
+                       src++;
+                       srclen--;
+               }
+       }
+
+       if (ndone == 0)
+               return "no data bytes specified by input";
+       if (lenp != NULL)
+               *lenp = ndone;
+       return NULL;
+}
+
+/*
+ - ttodata - convert text to data
+ */
+const char *                   /* NULL on success, else literal */
+ttodata(src, srclen, base, dst, dstlen, lenp)
+const char *src;
+size_t srclen;                 /* 0 means apply strlen() */
+int base;                      /* 0 means figure it out */
+char *dst;                     /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp;                  /* where to record length (NULL is nowhere) */
+{
+       return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
+                       (size_t)0, TTODATAV_SPACECOUNTS);
+}
+
+/*
+ - atodata - convert ASCII to data
+ * backward-compatibility interface
+ */
+size_t                         /* 0 for failure, true length for success */
+atodata(src, srclen, dst, dstlen)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+{
+       size_t len;
+       const char *err;
+
+       err = ttodata(src, srclen, 0, dst, dstlen, &len);
+       if (err != NULL)
+               return 0;
+       return len;
+}
+
+/*
+ - atobytes - convert ASCII to data bytes
+ * another backward-compatibility interface
+ */
+const char *
+atobytes(src, srclen, dst, dstlen, lenp)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+size_t *lenp;
+{
+       return ttodata(src, srclen, 0, dst, dstlen, lenp);
+}
+
+/*
+ - unhex - convert two ASCII hex digits to byte
+ */
+static int             /* number of result bytes, or error code */
+unhex(src, dst, dstlen)
+const char *src;       /* known to be full length */
+char *dst;
+size_t dstlen;         /* not large enough is a failure */
+{
+       char *p;
+       unsigned byte;
+       static char hex[] = "0123456789abcdef";
+
+       if (dstlen < 1)
+               return SHORT;
+       
+       p = strchr(hex, *src);
+       if (p == NULL)
+               p = strchr(hex, tolower(*src));
+       if (p == NULL)
+               return BADCH0;
+       byte = (p - hex) << 4;
+       src++;
+
+       p = strchr(hex, *src);
+       if (p == NULL)
+               p = strchr(hex, tolower(*src));
+       if (p == NULL)
+               return BADCH1;
+       byte |= (p - hex);
+
+       *dst = byte;
+       return 1;
+}
+
+/*
+ - unb64 - convert four ASCII base64 digits to three bytes
+ * Note that a base64 digit group is padded out with '=' if it represents
+ * less than three bytes:  one byte is dd==, two is ddd=, three is dddd.
+ */
+static int             /* number of result bytes, or error code */
+unb64(src, dst, dstlen)
+const char *src;       /* known to be full length */
+char *dst;
+size_t dstlen;
+{
+       char *p;
+       unsigned byte1;
+       unsigned byte2;
+       static char base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+       if (dstlen < 3)
+               return SHORT;
+
+       p = strchr(base64, *src++);
+
+       if (p == NULL)
+               return BADCH0;
+       byte1 = (p - base64) << 2;      /* first six bits */
+
+       p = strchr(base64, *src++);
+       if (p == NULL) {
+               return BADCH1;
+       }
+
+       byte2 = p - base64;             /* next six:  two plus four */
+       *dst++ = byte1 | (byte2 >> 4);
+       byte1 = (byte2 & 0xf) << 4;
+
+       p = strchr(base64, *src++);
+       if (p == NULL) {
+               if (*(src-1) == '=' && *src == '=') {
+                       if (byte1 != 0)         /* bad padding */
+                               return BADPAD;
+                       return 1;
+               }
+               return BADCH2;
+       }
+
+       byte2 = p - base64;             /* next six:  four plus two */
+       *dst++ = byte1 | (byte2 >> 2);
+       byte1 = (byte2 & 0x3) << 6;
+
+       p = strchr(base64, *src++);
+       if (p == NULL) {
+               if (*(src-1) == '=') {
+                       if (byte1 != 0)         /* bad padding */
+                               return BADPAD;
+                       return 2;
+               }
+               return BADCH3;
+       }
+       byte2 = p - base64;             /* last six */
+       *dst++ = byte1 | byte2;
+
+       return 3;
+}
+
+/*
+ - untext - convert one ASCII character to byte
+ */
+static int             /* number of result bytes, or error code */
+untext(src, dst, dstlen)
+const char *src;       /* known to be full length */
+char *dst;
+size_t dstlen;         /* not large enough is a failure */
+{
+       if (dstlen < 1)
+               return SHORT;
+
+       *dst = *src;
+       return 1;
+}
+
+/*
+ - badch - produce a nice complaint about an unknown character
+ *
+ * If the compiler complains that the array bigenough[] has a negative
+ * size, that means the TTODATAV_BUF constant has been set too small.
+ */
+static const char *            /* literal or errp */
+badch(src, errcode, errp, errlen)
+const char *src;
+int errcode;
+char *errp;                    /* might be NULL */
+size_t errlen;
+{
+       static const char pre[] = "unknown character (`";
+       static const char suf[] = "') in input";
+       char buf[5];
+#      define  REQD    (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
+       struct sizecheck {
+               char bigenough[TTODATAV_BUF - REQD];    /* see above */
+       };
+       char ch;
+
+       if (errp == NULL || errlen < REQD)
+               return "unknown character in input";
+       strcpy(errp, pre);
+       ch = *(src + BADOFF(errcode));
+       if (isprint(ch)) {
+               buf[0] = ch;
+               buf[1] = '\0';
+       } else {
+               buf[0] = '\\';
+               buf[1] = ((ch & 0700) >> 6) + '0';
+               buf[2] = ((ch & 0070) >> 3) + '0';
+               buf[3] = ((ch & 0007) >> 0) + '0';
+               buf[4] = '\0';
+       }
+       strcat(errp, buf);
+       strcat(errp, suf);
+       return (const char *)errp;
+}
+
+
+
+#ifdef TTODATA_MAIN
+
+#include <stdio.h>
+
+struct artab;
+static void check(struct artab *r, char *buf, size_t n, err_t oops, int *status);
+static void regress(char *pgm);
+static void hexout(const char *s, size_t len, FILE *f);
+
+/*
+ - main - convert first argument to hex, or run regression
+ */
+int
+main(int argc, char *argv[])
+{
+       char buf[1024];
+       char buf2[1024];
+       char err[512];
+       size_t n;
+       size_t i;
+       char *p = buf;
+       char *p2 = buf2;
+       char *pgm = argv[0];
+       const char *oops;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm);
+               exit(2);
+       }
+
+       if (strcmp(argv[1], "-r") == 0) {
+               regress(pgm);   /* should not return */
+               fprintf(stderr, "%s: regress() returned?!?\n", pgm);
+               exit(1);
+       }
+
+       oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n,
+                       err, sizeof(err), TTODATAV_IGNORESPACE);
+       if (oops != NULL) {
+               fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm,
+                                                               oops, argv[1]);
+               exit(1);
+       }
+
+       if (n > sizeof(buf)) {
+               p = (char *)malloc((size_t)n);
+               if (p == NULL) {
+                       fprintf(stderr,
+                               "%s: unable to malloc %d bytes for result\n",
+                               pgm, n);
+                       exit(1);
+               }
+               oops = ttodata(argv[1], 0, 0, p, n, &n);
+               if (oops != NULL) {
+                       fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n",
+                                                               pgm, oops);
+                       exit(1);
+               }
+       }
+
+       hexout(p, n, stdout);
+       printf("\n");
+
+       i = datatot(buf, n, 'h', buf2, sizeof(buf2));
+       if (i == 0) {
+               fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm,
+                                                               argv[1]);
+               exit(1);
+       }
+
+       if (i > sizeof(buf2)) {
+               p2 = (char *)malloc((size_t)i);
+               if (p == NULL) {
+                       fprintf(stderr,
+                               "%s: unable to malloc %d bytes for result\n",
+                               pgm, i);
+                       exit(1);
+               }
+               i = datatot(buf, n, 'h', p2, i);
+               if (i == 0) {
+                       fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm);
+                       exit(1);
+               }
+       }
+
+       printf("%s\n", p2);
+
+       exit(0);
+}
+
+/*
+ - hexout - output an arbitrary-length string in hex
+ */
+static void
+hexout(s, len, f)
+const char *s;
+size_t len;
+FILE *f;
+{
+       size_t i;
+
+       fprintf(f, "0x");
+       for (i = 0; i < len; i++)
+               fprintf(f, "%02x", (unsigned char)s[i]);
+}
+
+struct artab {
+       int base;
+#          define IGNORESPACE_BIAS 1000
+       char *ascii;            /* NULL for end */
+       char *data;             /* NULL for error expected */
+} atodatatab[] = {
+       { 0, "",                        NULL, },
+       { 0, "0",                       NULL, },
+       { 0, "0x",              NULL, },
+       { 0, "0xa",             NULL, },
+       { 0, "0xab",            "\xab", },
+       { 0, "0xabc",           NULL, },
+       { 0, "0xabcd",          "\xab\xcd", },
+       { 0, "0x0123456789",    "\x01\x23\x45\x67\x89", },
+       { 0, "0x01x",           NULL, },
+       { 0, "0xabcdef",                "\xab\xcd\xef", },
+       { 0, "0xABCDEF",                "\xab\xcd\xef", },
+       { 0, "0XaBc0eEd81f",    "\xab\xc0\xee\xd8\x1f", },
+       { 0, "0XaBc0_eEd8",     "\xab\xc0\xee\xd8", },
+       { 0, "0XaBc0_",         NULL, },
+       { 0, "0X_aBc0",         NULL, },
+       { 0, "0Xa_Bc0",         NULL, },
+       { 16, "aBc0eEd8",       "\xab\xc0\xee\xd8", },
+       { 0, "0s",              NULL, },
+       { 0, "0sA",             NULL, },
+       { 0, "0sBA",            NULL, },
+       { 0, "0sCBA",           NULL, },
+       { 0, "0sDCBA",          "\x0c\x20\x40", },
+       { 0, "0SDCBA",          "\x0c\x20\x40", },
+       { 0, "0sDA==",          "\x0c", },
+       { 0, "0sDC==",          NULL, },
+       { 0, "0sDCA=",          "\x0c\x20", },
+       { 0, "0sDCB=",          NULL, },
+       { 0, "0sDCAZ",          "\x0c\x20\x19", },
+       { 0, "0sDCAa",          "\x0c\x20\x1a", },
+       { 0, "0sDCAz",          "\x0c\x20\x33", },
+       { 0, "0sDCA0",          "\x0c\x20\x34", },
+       { 0, "0sDCA9",          "\x0c\x20\x3d", },
+       { 0, "0sDCA+",          "\x0c\x20\x3e", },
+       { 0, "0sDCA/",          "\x0c\x20\x3f", },
+       { 0, "0sAbraCadabra+",  "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0s AbraCadabra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sA braCadabra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAb raCadabra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbr aCadabra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbra Cadabra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraC adabra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraCa dabra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraCad abra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraCada bra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraCadab ra+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraCadabr a+",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraCadabra +",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { IGNORESPACE_BIAS + 0, "0sAbraCadabra+ ",      "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+       { 0, "0t",              NULL, },
+       { 0, "0tabc_xyz",               "abc_xyz", },
+       { 256, "abc_xyz",               "abc_xyz", },
+       { 0, NULL,              NULL, },
+};
+
+struct drtab {
+       char *data;     /* input; NULL for end */
+       char format;
+       int buflen;     /* -1 means big buffer */
+       int outlen;     /* -1 means strlen(ascii)+1 */
+       char *ascii;    /* NULL for error expected */
+} datatoatab[] = {
+       { "",                   'x',    -1,     -1,     NULL, },
+       { "",                   'X',    -1,     -1,     NULL, },
+       { "",                   'n',    -1,     -1,     NULL, },
+       { "0",                  'x',    -1,     -1,     "0x30", },
+       { "0",                  'x',    0,      5,      "---", },
+       { "0",                  'x',    1,      5,      "", },
+       { "0",                  'x',    2,      5,      "0", },
+       { "0",                  'x',    3,      5,      "0x", },
+       { "0",                  'x',    4,      5,      "0x3", },
+       { "0",                  'x',    5,      5,      "0x30", },
+       { "0",                  'x',    6,      5,      "0x30", },
+       { "\xab\xcd",           'x',    -1,     -1,     "0xabcd", },
+       { "\x01\x23\x45\x67\x89",       'x',    -1,     -1,     "0x0123456789", },
+       { "\xab\xcd\xef",               'x',    -1,     -1,     "0xabcdef", },
+       { "\xab\xc0\xee\xd8\x1f",       'x',    -1,     -1,     "0xabc0eed81f", },
+       { "\x01\x02",           'h',    -1,     -1,     "0x0102", },
+       { "\x01\x02\x03\x04\x05\x06",   'h',    -1, -1, "0x01020304_0506", },
+       { "\xab\xc0\xee\xd8\x1f",       16,     -1,     -1,     "abc0eed81f", },
+       { "\x0c\x20\x40",               's',    -1,     -1,     "0sDCBA", },
+       { "\x0c\x20\x40",               's',    0,      7,      "---", },
+       { "\x0c\x20\x40",               's',    1,      7,      "", },
+       { "\x0c\x20\x40",               's',    2,      7,      "0", },
+       { "\x0c\x20\x40",               's',    3,      7,      "0s", },
+       { "\x0c\x20\x40",               's',    4,      7,      "0sD", },
+       { "\x0c\x20\x40",               's',    5,      7,      "0sDC", },
+       { "\x0c\x20\x40",               's',    6,      7,      "0sDCB", },
+       { "\x0c\x20\x40",               's',    7,      7,      "0sDCBA", },
+       { "\x0c\x20\x40",               's',    8,      7,      "0sDCBA", },
+       { "\x0c",                       's',    -1,     -1,     "0sDA==", },
+       { "\x0c\x20",           's',    -1,     -1,     "0sDCA=", },
+       { "\x0c\x20\x19",               's',    -1,     -1,     "0sDCAZ", },
+       { "\x0c\x20\x1a",               's',    -1,     -1,     "0sDCAa", },
+       { "\x0c\x20\x33",               's',    -1,     -1,     "0sDCAz", },
+       { "\x0c\x20\x34",               's',    -1,     -1,     "0sDCA0", },
+       { "\x0c\x20\x3d",               's',    -1,     -1,     "0sDCA9", },
+       { "\x0c\x20\x3e",               's',    -1,     -1,     "0sDCA+", },
+       { "\x0c\x20\x3f",               's',    -1,     -1,     "0sDCA/", },
+       { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", },
+       { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", },
+       { NULL,                 'x',    -1,     -1,     NULL, },
+};
+
+/*
+ - regress - regression-test ttodata() and datatot()
+ */
+static void
+check(r, buf, n, oops, status)
+struct artab *r;
+char *buf;
+size_t n;
+err_t oops;
+int *status;
+{
+       if (oops != NULL && r->data == NULL)
+               {}                      /* error expected */
+       else if (oops != NULL) {
+               printf("`%s' gave error `%s', expecting %d `", r->ascii,
+                                               oops, strlen(r->data));
+               hexout(r->data, strlen(r->data), stdout);
+               printf("'\n");
+               *status = 1;
+       } else if (r->data == NULL) {
+               printf("`%s' gave %d `", r->ascii, n);
+               hexout(buf, n, stdout);
+               printf("', expecting error\n");
+               *status = 1;
+       } else if (n != strlen(r->data)) {
+               printf("length wrong in `%s': got %d `", r->ascii, n);
+               hexout(buf, n, stdout);
+               printf("', expecting %d `", strlen(r->data));
+               hexout(r->data, strlen(r->data), stdout);
+               printf("'\n");
+               *status = 1;
+       } else if (memcmp(buf, r->data, n) != 0) {
+               printf("`%s' gave %d `", r->ascii, n);
+               hexout(buf, n, stdout);
+               printf("', expecting %d `", strlen(r->data));
+               hexout(r->data, strlen(r->data), stdout);
+               printf("'\n");
+               *status = 1;
+       }
+       fflush(stdout);
+}
+
+static void                    /* should not return at all, in fact */
+regress(pgm)
+char *pgm;
+{
+       struct artab *r;
+       struct drtab *dr;
+       char buf[100];
+       size_t n;
+       int status = 0;
+
+       for (r = atodatatab; r->ascii != NULL; r++) {
+               int base = r->base;
+               int xbase = 0;
+
+               if ((base == 0 || base == IGNORESPACE_BIAS + 0) && r->ascii[0] == '0') {
+                       switch (r->ascii[1]) {
+                       case 'x':
+                       case 'X':
+                               xbase = 16;
+                               break;
+                       case 's':
+                       case 'S':
+                               xbase = 64;
+                               break;
+                       case 't':
+                       case 'T':
+                               xbase = 256;
+                               break;
+                       }
+               }
+               
+               if (base >= IGNORESPACE_BIAS) {
+                       base = base - IGNORESPACE_BIAS;
+                       check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+                       if (xbase != 0)
+                               check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+               } else {
+                       check(r, buf, n, ttodata(r->ascii, 0, base, buf, sizeof(buf), &n), &status);
+                       if (base == 64 || xbase == 64)
+                               check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+                       if (xbase != 0) {
+                               check(r, buf, n, ttodata(r->ascii+2, 0, xbase, buf, sizeof(buf), &n), &status);
+                               if (base == 64 || xbase == 64)
+                                       check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+                       }
+               }
+       }
+       for (dr = datatoatab; dr->data != NULL; dr++) {
+               size_t should;
+
+               strcpy(buf, "---");
+               n = datatot(dr->data, strlen(dr->data), dr->format, buf,
+                               (dr->buflen == -1) ? sizeof(buf) : dr->buflen);
+               should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1;
+               if (dr->outlen != -1)
+                       should = dr->outlen;
+               if (n == 0 && dr->ascii == NULL)
+                       {}                      /* error expected */
+               else if (n == 0) {
+                       printf("`");
+                       hexout(dr->data, strlen(dr->data), stdout);
+                       printf("' %c gave error, expecting %d `%s'\n",
+                               dr->format, should, dr->ascii);
+                       status = 1;
+               } else if (dr->ascii == NULL) {
+                       printf("`");
+                       hexout(dr->data, strlen(dr->data), stdout);
+                       printf("' %c gave %d `%.*s', expecting error\n",
+                               dr->format, n, (int)n, buf);
+                       status = 1;
+               } else if (n != should) {
+                       printf("length wrong in `");
+                       hexout(dr->data, strlen(dr->data), stdout);
+                       printf("': got %d `%s'", n, buf);
+                       printf(", expecting %d `%s'\n", should, dr->ascii);
+                       status = 1;
+               } else if (strcmp(buf, dr->ascii) != 0) {
+                       printf("`");
+                       hexout(dr->data, strlen(dr->data), stdout);
+                       printf("' gave %d `%s'", n, buf);
+                       printf(", expecting %d `%s'\n", should, dr->ascii);
+                       status = 1;
+               }
+               fflush(stdout);
+       }
+       exit(status);
+}
+
+#endif /* TTODATA_MAIN */
diff --git a/Source/lib/asn1-pluto/ttodata.h b/Source/lib/asn1-pluto/ttodata.h
new file mode 100644 (file)
index 0000000..d57244e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * convert from text form of arbitrary data (e.g., keys) to binary
+ * Copyright (C) 2000  Henry Spencer.
+ * 
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/lgpl.txt>.
+ * 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+ * License for more details.
+ */
+
+#ifndef TTODATA_H_
+#define TTODATA_H_
+
+#include <types.h>
+
+#define        TTODATAV_BUF    40      /* ttodatav's largest non-literal message */
+#define TTODATAV_IGNORESPACE  (1<<1)  /* ignore spaces in base64 encodings*/
+#define TTODATAV_SPACECOUNTS  0       /* do not ignore spaces in base64   */
+
+typedef const char *err_t;     /* error message, or NULL for success */
+
+err_t ttodata(const char *src, size_t srclen, int base, char *buf, size_t buflen, size_t *needed);
+
+
+#endif /* TTODATA_H_ */
index 879cade..af09a2a 100644 (file)
@@ -28,7 +28,7 @@
 #include "rsa_private_key.h"
 
 #include <daemon.h>
-#include <asn1/der_decoder.h>
+#include <asn1-pluto/asn1-pluto.h>
 
 
 /* 
@@ -138,6 +138,8 @@ struct private_rsa_private_key_t {
        
 };
 
+#if 0 
+Not used yet, since we use plutos ASN1 stuff
 /**
  * Rules for de-/encoding of a private key from/in ASN1 
  */
@@ -154,6 +156,51 @@ static asn1_rule_t rsa_private_key_rules[] = {
        {       ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, coeff), 0},
        {ASN1_END, 0, 0, 0},
 };
+#endif
+
+struct {
+       const char *name;
+       size_t offset;
+} RSA_private_field[] = {
+       { "Modulus",         offsetof(private_rsa_private_key_t, n) },
+       { "PublicExponent",  offsetof(private_rsa_private_key_t, e) },
+       { "PrivateExponent", offsetof(private_rsa_private_key_t, d) },
+       { "Prime1",          offsetof(private_rsa_private_key_t, p) },
+       { "Prime2",          offsetof(private_rsa_private_key_t, q) },
+       { "Exponent1",       offsetof(private_rsa_private_key_t, exp1) },
+       { "Exponent2",       offsetof(private_rsa_private_key_t, exp2) },
+       { "Coefficient",     offsetof(private_rsa_private_key_t, coeff) },
+};
+
+/* ASN.1 definition of a PKCS#1 RSA private key */
+
+static const asn1Object_t privkeyObjects[] = {
+       { 0, "RSAPrivateKey",           ASN1_SEQUENCE,     ASN1_NONE }, /*  0 */
+       { 1,   "version",                       ASN1_INTEGER,      ASN1_BODY }, /*  1 */
+       { 1,   "modulus",                       ASN1_INTEGER,      ASN1_BODY }, /*  2 */
+       { 1,   "publicExponent",        ASN1_INTEGER,      ASN1_BODY }, /*  3 */
+       { 1,   "privateExponent",       ASN1_INTEGER,      ASN1_BODY }, /*  4 */
+       { 1,   "prime1",                        ASN1_INTEGER,      ASN1_BODY }, /*  5 */
+       { 1,   "prime2",                        ASN1_INTEGER,      ASN1_BODY }, /*  6 */
+       { 1,   "exponent1",                     ASN1_INTEGER,      ASN1_BODY }, /*  7 */
+       { 1,   "exponent2",                     ASN1_INTEGER,      ASN1_BODY }, /*  8 */
+       { 1,   "coefficient",           ASN1_INTEGER,      ASN1_BODY }, /*  9 */
+       { 1,   "otherPrimeInfos",       ASN1_SEQUENCE,     ASN1_OPT |
+                                                                                                  ASN1_LOOP }, /* 10 */
+       { 2,     "otherPrimeInfo",      ASN1_SEQUENCE,     ASN1_NONE }, /* 11 */
+       { 3,       "prime",                     ASN1_INTEGER,      ASN1_BODY }, /* 12 */
+       { 3,       "exponent",          ASN1_INTEGER,      ASN1_BODY }, /* 13 */
+       { 3,       "coefficient",       ASN1_INTEGER,      ASN1_BODY }, /* 14 */
+       { 1,   "end opt or loop",       ASN1_EOC,          ASN1_END  }  /* 15 */
+};
+
+#define PKCS1_PRIV_KEY_VERSION          1
+#define PKCS1_PRIV_KEY_MODULUS          2
+#define PKCS1_PRIV_KEY_PUB_EXP          3
+#define PKCS1_PRIV_KEY_COEFF            9
+#define PKCS1_PRIV_KEY_ROOF                    16
+
+
 
 static private_rsa_private_key_t *rsa_private_key_create_empty();
 
@@ -548,6 +595,9 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
        return &this->public;
 }
 
+
+#if 0 
+NOT used yet, since we use plutos ASN1 parser for now
 /*
  * see header
  */
@@ -579,6 +629,152 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t chunk)
        this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
        return &this->public;
 }
+#endif
+
+static status_t check(private_rsa_private_key_t *this)
+{
+       mpz_t t, u, q1;
+       status_t status = SUCCESS;
+       
+       /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
+        * We actually require more (for security).
+        */
+       if (this->k < 512/8)
+               return FAILED;
+       
+       /* we picked a max modulus size to simplify buffer allocation */
+       if (this->k > 8192/8)
+               return FAILED;
+       
+       mpz_init(t);
+       mpz_init(u);
+       mpz_init(q1);
+       
+       /* check that n == p * q */
+       mpz_mul(u, this->p, this->q);
+       if (mpz_cmp(u, this->n) != 0)
+       {
+               status = FAILED;
+       }
+       
+       /* check that e divides neither p-1 nor q-1 */
+       mpz_sub_ui(t, this->p, 1);
+       mpz_mod(t, t, this->e);
+       if (mpz_cmp_ui(t, 0) == 0)
+       {
+               status = FAILED;
+       }
+       
+       mpz_sub_ui(t, this->q, 1);
+       mpz_mod(t, t, this->e);
+       if (mpz_cmp_ui(t, 0) == 0)
+       {
+               status = FAILED;
+       }
+       
+       /* check that d is e^-1 (mod lcm(p-1, q-1)) */
+       /* see PKCS#1v2, aka RFC 2437, for the "lcm" */
+       mpz_sub_ui(q1, this->q, 1);
+       mpz_sub_ui(u, this->p, 1);
+       mpz_gcd(t, u, q1);              /* t := gcd(p-1, q-1) */
+       mpz_mul(u, u, q1);              /* u := (p-1) * (q-1) */
+       mpz_divexact(u, u, t);  /* u := lcm(p-1, q-1) */
+       
+       mpz_mul(t, this->d, this->e);
+       mpz_mod(t, t, u);
+       if (mpz_cmp_ui(t, 1) != 0)
+       {
+               status = FAILED;
+       }
+       
+       /* check that exp1 is d mod (p-1) */
+       mpz_sub_ui(u, this->p, 1);
+       mpz_mod(t, this->d, u);
+       if (mpz_cmp(t, this->exp1) != 0)
+       {
+               status = FAILED;
+       }
+       
+       /* check that exp2 is d mod (q-1) */
+       mpz_sub_ui(u, this->q, 1);
+       mpz_mod(t, this->d, u);
+       if (mpz_cmp(t, this->exp2) != 0)
+       {
+               status = FAILED;
+       }
+       
+       /* check that coeff is (q^-1) mod p */
+       mpz_mul(t, this->coeff, this->q);
+       mpz_mod(t, t, this->p);
+       if (mpz_cmp_ui(t, 1) != 0)
+       {
+               status = FAILED;
+       }
+       
+       mpz_clear(t);
+       mpz_clear(u);
+       mpz_clear(q1);
+       return status;
+}
+
+/*
+ *  Parses a PKCS#1 private key
+ */
+rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob)
+{
+       asn1_ctx_t ctx;
+       chunk_t object;
+       u_int level;
+       int objectID = 0;
+       private_rsa_private_key_t *this;
+       
+       this = rsa_private_key_create_empty();
+       
+       mpz_init(this->n);
+       mpz_init(this->e);
+       mpz_init(this->p);
+       mpz_init(this->q);
+       mpz_init(this->d);
+       mpz_init(this->exp1);
+       mpz_init(this->exp2);
+       mpz_init(this->coeff);
+       
+       asn1_init(&ctx, blob, 0, FALSE);
+       
+       while (objectID < PKCS1_PRIV_KEY_ROOF) 
+       {
+               if (!extract_object(privkeyObjects, &objectID, &object, &level, &ctx))
+               {
+                       return FALSE;
+               }
+               if (objectID == PKCS1_PRIV_KEY_VERSION)
+               {
+                       if (object.len > 0 && *object.ptr != 0)
+                       {
+                               destroy(this);
+                               return NULL;
+                       }
+               }
+               else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
+                                          objectID <= PKCS1_PRIV_KEY_COEFF)
+               {
+                       mpz_t *u = (mpz_t *) ((char *)this
+                                       + RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset);
+                       
+                       mpz_import(*u, object.len, 1, 1, 1, 0, object.ptr);
+               }
+               objectID++;
+       }
+       if (check(this) != SUCCESS)
+       {
+               destroy(this);
+               return NULL;
+       }
+       else
+       {
+               return &this->public;
+       }
+}
 
 /*
  * see header
index fd96b36..d75d673 100644 (file)
@@ -146,6 +146,11 @@ struct chunk_t {
 extern chunk_t CHUNK_INITIALIZER;
 
 /**
+ * Initialize a chunk to a static buffer
+ */
+#define chunk_from_buf(str) { str, sizeof(str) }
+
+/**
  * Clone chunk contents in a newly allocated chunk
  */
 chunk_t chunk_clone(chunk_t chunk);
index 1ae6bd6..c3888f8 100644 (file)
@@ -220,11 +220,11 @@ static void log_bytes(private_logger_t *this, log_level_t loglevel, char *label,
                                buffer_pos = buffer;
                                if (this->output == NULL)
                                {
-                                       syslog(LOG_INFO, "[=>] [%5d ] %s %s", line_start, buffer, ascii_buffer);        
+                                       syslog(LOG_INFO, "[=>] [%5d] %s %s", line_start, buffer, ascii_buffer); 
                                }
                                else
                                {
-                                       fprintf(this->output, "[=>] [%5d ] %s %s\n", line_start, buffer, ascii_buffer);
+                                       fprintf(this->output, "[=>] [%5d] %s %s\n", line_start, buffer, ascii_buffer);
                                }
                                memset(ascii_buffer, 0, 16);
                                line_start += 16;
@@ -257,11 +257,11 @@ static void log_bytes(private_logger_t *this, log_level_t loglevel, char *label,
                        buffer_pos = buffer;
                        if (this->output == NULL)
                        {               
-                               syslog(LOG_INFO, "[=>] [%5d ] %s %16s", line_start, buffer, ascii_buffer);
+                               syslog(LOG_INFO, "[=>] [%5d] %s %16s", line_start, buffer, ascii_buffer);
                        }
                        else
                        {
-                               fprintf(this->output, "[=>] [%5d ] %s %16s\n", line_start, buffer, ascii_buffer);
+                               fprintf(this->output, "[=>] [%5d] %s %16s\n", line_start, buffer, ascii_buffer);
                        }
                }
                pthread_mutex_unlock(&mutex);
index 18ff299..26d8b7d 100644 (file)
@@ -50,6 +50,7 @@ mapping_t logger_context_t_mappings[] = {
        {PAYLOAD, "PAYLOAD"},
        {DER_DECODER, "DER_DECODER"},
        {DER_ENCODER, "DER_ENCODER"},
+       {ASN1, "ASN1"},
        {MAPPING_END, NULL},
 };
 
@@ -77,6 +78,7 @@ struct {
        { "PAYLD", ERROR|CONTROL|AUDIT|LEVEL0,  TRUE }, /* PAYLOAD */
        { "DERDC", ERROR|CONTROL|AUDIT|LEVEL0,  TRUE }, /* DER_DECODER */
        { "DEREC", ERROR|CONTROL|AUDIT|LEVEL0,  TRUE }, /* DER_ENCODER */
+       { "ASN_1", ERROR|CONTROL|AUDIT|RAW|LEVEL3,      TRUE }, /* ASN1 */
 };
 
 
index a4daa46..712891f 100644 (file)
@@ -56,6 +56,7 @@ enum logger_context_t {
        PAYLOAD,
        DER_DECODER,
        DER_ENCODER,
+       ASN1,
        LOGGER_CONTEXT_ROOF,
 };