aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2006-04-10 14:19:10 +0000
committerMartin Willi <martin@strongswan.org>2006-04-10 14:19:10 +0000
commitb5cb0210f7b4672cd1c9e51a5ae6943fcc25331f (patch)
tree8a18498b075917f81127416cd57659444d440476 /Source
parent5113680f95e522c677cdd37072cfffbdca06831e (diff)
downloadstrongswan-b5cb0210f7b4672cd1c9e51a5ae6943fcc25331f.tar.bz2
strongswan-b5cb0210f7b4672cd1c9e51a5ae6943fcc25331f.tar.xz
- startet importing pluto ASN1 stuff
- der PKCS#1 key loading works (as it did with der_decoder)
Diffstat (limited to 'Source')
-rw-r--r--Source/Makefile2
-rw-r--r--Source/charon/network/socket.c2
-rw-r--r--Source/doc/Known-bugs.txt4
-rw-r--r--Source/doc/Todo-list.txt10
-rw-r--r--Source/lib/Makefile.lib1
-rw-r--r--Source/lib/asn1-pluto/Makefile.asn129
-rw-r--r--Source/lib/asn1-pluto/asn1-pluto.c574
-rw-r--r--Source/lib/asn1-pluto/asn1-pluto.h129
-rw-r--r--Source/lib/asn1-pluto/oid.c194
-rw-r--r--Source/lib/asn1-pluto/oid.h75
-rw-r--r--Source/lib/asn1-pluto/oid.pl123
-rw-r--r--Source/lib/asn1-pluto/oid.txt181
-rwxr-xr-xSource/lib/asn1-pluto/pem.c343
-rwxr-xr-xSource/lib/asn1-pluto/pem.h25
-rw-r--r--Source/lib/asn1-pluto/ttodata.c723
-rw-r--r--Source/lib/asn1-pluto/ttodata.h30
-rw-r--r--Source/lib/crypto/rsa/rsa_private_key.c198
-rw-r--r--Source/lib/types.h5
-rw-r--r--Source/lib/utils/logger.c8
-rw-r--r--Source/lib/utils/logger_manager.c2
-rw-r--r--Source/lib/utils/logger_manager.h1
21 files changed, 2647 insertions, 12 deletions
diff --git a/Source/Makefile b/Source/Makefile
index b202bcb4a..ceb987611 100644
--- a/Source/Makefile
+++ b/Source/Makefile
@@ -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=
diff --git a/Source/charon/network/socket.c b/Source/charon/network/socket.c
index 733071fab..79c7c421d 100644
--- a/Source/charon/network/socket.c
+++ b/Source/charon/network/socket.c
@@ -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!");
}
diff --git a/Source/doc/Known-bugs.txt b/Source/doc/Known-bugs.txt
index 079d4d0f9..e7ee0b9df 100644
--- a/Source/doc/Known-bugs.txt
+++ b/Source/doc/Known-bugs.txt
@@ -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)
diff --git a/Source/doc/Todo-list.txt b/Source/doc/Todo-list.txt
index 4915ea7c7..0942defc8 100644
--- a/Source/doc/Todo-list.txt
+++ b/Source/doc/Todo-list.txt
@@ -22,12 +22,12 @@
+ 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
diff --git a/Source/lib/Makefile.lib b/Source/lib/Makefile.lib
index 389a31b63..ff4107275 100644
--- a/Source/lib/Makefile.lib
+++ b/Source/lib/Makefile.lib
@@ -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
index 000000000..44726ffa4
--- /dev/null
+++ b/Source/lib/asn1-pluto/Makefile.asn1
@@ -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
index 000000000..46764e10e
--- /dev/null
+++ b/Source/lib/asn1-pluto/asn1-pluto.c
@@ -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
index 000000000..c7cc29eb8
--- /dev/null
+++ b/Source/lib/asn1-pluto/asn1-pluto.h
@@ -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
index 000000000..7b0135d5e
--- /dev/null
+++ b/Source/lib/asn1-pluto/oid.c
@@ -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
index 000000000..4096af357
--- /dev/null
+++ b/Source/lib/asn1-pluto/oid.h
@@ -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
index 000000000..52ac8eae0
--- /dev/null
+++ b/Source/lib/asn1-pluto/oid.pl
@@ -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
index 000000000..ad05a1270
--- /dev/null
+++ b/Source/lib/asn1-pluto/oid.txt
@@ -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
index 000000000..24c71c61f
--- /dev/null
+++ b/Source/lib/asn1-pluto/pem.c
@@ -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
index 000000000..a4332fd34
--- /dev/null
+++ b/Source/lib/asn1-pluto/pem.h
@@ -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
index 000000000..3ef5acd10
--- /dev/null
+++ b/Source/lib/asn1-pluto/ttodata.c
@@ -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
index 000000000..d57244ef5
--- /dev/null
+++ b/Source/lib/asn1-pluto/ttodata.h
@@ -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_ */
diff --git a/Source/lib/crypto/rsa/rsa_private_key.c b/Source/lib/crypto/rsa/rsa_private_key.c
index 879cade26..af09a2af5 100644
--- a/Source/lib/crypto/rsa/rsa_private_key.c
+++ b/Source/lib/crypto/rsa/rsa_private_key.c
@@ -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
diff --git a/Source/lib/types.h b/Source/lib/types.h
index fd96b361c..d75d67362 100644
--- a/Source/lib/types.h
+++ b/Source/lib/types.h
@@ -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);
diff --git a/Source/lib/utils/logger.c b/Source/lib/utils/logger.c
index 1ae6bd6f0..c3888f80f 100644
--- a/Source/lib/utils/logger.c
+++ b/Source/lib/utils/logger.c
@@ -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);
diff --git a/Source/lib/utils/logger_manager.c b/Source/lib/utils/logger_manager.c
index 18ff29906..26d8b7d87 100644
--- a/Source/lib/utils/logger_manager.c
+++ b/Source/lib/utils/logger_manager.c
@@ -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 */
};
diff --git a/Source/lib/utils/logger_manager.h b/Source/lib/utils/logger_manager.h
index a4daa46b6..712891fff 100644
--- a/Source/lib/utils/logger_manager.h
+++ b/Source/lib/utils/logger_manager.h
@@ -56,6 +56,7 @@ enum logger_context_t {
PAYLOAD,
DER_DECODER,
DER_ENCODER,
+ ASN1,
LOGGER_CONTEXT_ROOF,
};