diff options
Diffstat (limited to 'src/charon/lib')
72 files changed, 16067 insertions, 0 deletions
diff --git a/src/charon/lib/Makefile.lib b/src/charon/lib/Makefile.lib new file mode 100644 index 000000000..80a44ff69 --- /dev/null +++ b/src/charon/lib/Makefile.lib @@ -0,0 +1,31 @@ +# 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. +# + +LIB_DIR= $(MAIN_DIR)lib/ + +include $(MAIN_DIR)lib/utils/Makefile.utils +include $(MAIN_DIR)lib/crypto/Makefile.transforms +include $(MAIN_DIR)lib/asn1/Makefile.asn1 + +LIB_OBJS+= $(BUILD_DIR)types.o +$(BUILD_DIR)types.o : $(LIB_DIR)types.c $(LIB_DIR)types.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)definitions.o +$(BUILD_DIR)definitions.o : $(LIB_DIR)definitions.c $(LIB_DIR)definitions.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)library.o +$(BUILD_DIR)library.o : $(LIB_DIR)library.c $(LIB_DIR)library.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/charon/lib/asn1/Makefile.asn1 b/src/charon/lib/asn1/Makefile.asn1 new file mode 100644 index 000000000..3a5450d50 --- /dev/null +++ b/src/charon/lib/asn1/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/ + + +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.o +$(BUILD_DIR)asn1.o : $(ASN1_DIR)asn1.c $(ASN1_DIR)asn1.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/src/charon/lib/asn1/asn1.c b/src/charon/lib/asn1/asn1.c new file mode 100644 index 000000000..c847461b6 --- /dev/null +++ b/src/charon/lib/asn1/asn1.c @@ -0,0 +1,738 @@ +/* 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.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; +} + +/* + * codes ASN.1 lengths up to a size of 16'777'215 bytes + */ +void code_asn1_length(size_t length, chunk_t *code) +{ + if (length < 128) + { + code->ptr[0] = length; + code->len = 1; + } + else if (length < 256) + { + code->ptr[0] = 0x81; + code->ptr[1] = (u_char) length; + code->len = 2; + } + else if (length < 65536) + { + code->ptr[0] = 0x82; + code->ptr[1] = length >> 8; + code->ptr[2] = length & 0x00ff; + code->len = 3; + } + else + { + code->ptr[0] = 0x83; + code->ptr[1] = length >> 16; + code->ptr[2] = (length >> 8) & 0x00ff; + code->ptr[3] = length & 0x0000ff; + code->len = 4; + } +} + +/* + * build an empty asn.1 object with tag and length fields already filled in + */ +u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen) +{ + u_char length_buf[4]; + chunk_t length = { length_buf, 0 }; + u_char *pos; + + /* code the asn.1 length field */ + code_asn1_length(datalen, &length); + + /* allocate memory for the asn.1 TLV object */ + object->len = 1 + length.len + datalen; + object->ptr = malloc(object->len); + + /* set position pointer at the start of the object */ + pos = object->ptr; + + /* copy the asn.1 tag field and advance the pointer */ + *pos++ = type; + + /* copy the asn.1 length field and advance the pointer */ + memcpy(pos, length.ptr, length.len); + pos += length.len; + + return pos; +} + +/* + * build a simple ASN.1 object + */ +chunk_t asn1_simple_object(asn1_t tag, chunk_t content) +{ + chunk_t object; + + u_char *pos = build_asn1_object(&object, tag, content.len); + memcpy(pos, content.ptr, content.len); + pos += content.len; + + return object; +} + +/* Build an ASN.1 object from a variable number of individual chunks. + * Depending on the mode, chunks either are moved ('m') or copied ('c'). + */ +chunk_t asn1_wrap(asn1_t type, const char *mode, ...) +{ + chunk_t construct; + va_list chunks; + u_char *pos; + int i; + int count = strlen(mode); + + /* sum up lengths of individual chunks */ + va_start(chunks, mode); + construct.len = 0; + for (i = 0; i < count; i++) + { + chunk_t ch = va_arg(chunks, chunk_t); + construct.len += ch.len; + } + va_end(chunks); + + /* allocate needed memory for construct */ + pos = build_asn1_object(&construct, type, construct.len); + + /* copy or move the chunks */ + va_start(chunks, mode); + for (i = 0; i < count; i++) + { + chunk_t ch = va_arg(chunks, chunk_t); + + switch (*mode++) + { + case 'm': + memcpy(pos, ch.ptr, ch.len); + pos += ch.len; + free(ch.ptr); + break; + case 'c': + default: + memcpy(pos, ch.ptr, ch.len); + pos += ch.len; + } + } + va_end(chunks); + + return construct; +} + +/* + * convert a MP integer into a DER coded ASN.1 object + */ +chunk_t asn1_integer_from_mpz(const mpz_t value) +{ + size_t bits = mpz_sizeinbase(value, 2); /* size in bits */ + chunk_t n; + n.len = 1 + bits / 8; /* size in bytes */ + n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value); + + return asn1_wrap(ASN1_INTEGER, "m", n); +} + +/* + * convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format + */ +chunk_t timetoasn1(const time_t *time, asn1_t type) +{ + int offset; + const char *format; + char buf[TIMETOA_BUF]; + chunk_t formatted_time; + struct tm *t = gmtime(time); + + if (type == ASN1_GENERALIZEDTIME) + { + format = "%04d%02d%02d%02d%02d%02dZ"; + offset = 1900; + } + else /* ASN1_UTCTIME */ + { + format = "%02d%02d%02d%02d%02d%02dZ"; + offset = (t->tm_year < 100)? 0 : -100; + } + sprintf(buf, format, t->tm_year + offset, t->tm_mon + 1, t->tm_mday + , t->tm_hour, t->tm_min, t->tm_sec); + formatted_time.ptr = buf; + formatted_time.len = strlen(buf); + return asn1_simple_object(type, formatted_time); +} diff --git a/src/charon/lib/asn1/asn1.h b/src/charon/lib/asn1/asn1.h new file mode 100644 index 000000000..556bb2b05 --- /dev/null +++ b/src/charon/lib/asn1/asn1.h @@ -0,0 +1,137 @@ +/* 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> +#include <asn1/oid.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; + +#define TIMETOA_BUF 30 + +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); + +extern void code_asn1_length(size_t length, chunk_t *code); +extern u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen); +extern chunk_t asn1_integer_from_mpz(const mpz_t value); +extern chunk_t asn1_simple_object(asn1_t tag, chunk_t content); +extern chunk_t asn1_wrap(asn1_t type, const char *mode, ...); +extern chunk_t timetoasn1(const time_t *time, asn1_t type); + +#endif /* _ASN1_H */ diff --git a/src/charon/lib/asn1/oid.c b/src/charon/lib/asn1/oid.c new file mode 100644 index 000000000..4b0632de2 --- /dev/null +++ b/src/charon/lib/asn1/oid.c @@ -0,0 +1,197 @@ +/* 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, 174, 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 */ + { 0x03, 172, 1, "directory" }, /* 169 */ + { 0x01, 0, 1, "" }, /* 170 */ + { 0x03, 0, 0, "employeeNumber" }, /* 171 */ + { 0x04, 0, 1, "policy" }, /* 172 */ + { 0x01, 0, 0, "nsSGC" }, /* 173 */ + { 0x45, 0, 1, "verisign" }, /* 174 */ + { 0x01, 0, 1, "pki" }, /* 175 */ + { 0x09, 0, 1, "attributes" }, /* 176 */ + { 0x02, 178, 0, "messageType" }, /* 177 */ + { 0x03, 179, 0, "pkiStatus" }, /* 178 */ + { 0x04, 180, 0, "failInfo" }, /* 179 */ + { 0x05, 181, 0, "senderNonce" }, /* 180 */ + { 0x06, 182, 0, "recipientNonce" }, /* 181 */ + { 0x07, 183, 0, "transID" }, /* 182 */ + { 0x08, 0, 0, "extensionReq" } /* 183 */ +}; diff --git a/src/charon/lib/asn1/oid.h b/src/charon/lib/asn1/oid.h new file mode 100644 index 000000000..a9265d43f --- /dev/null +++ b/src/charon/lib/asn1/oid.h @@ -0,0 +1,80 @@ +/* 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! + */ + +#ifndef OID_H_ +#define OID_H_ + +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 177 +#define OID_PKI_STATUS 178 +#define OID_PKI_FAIL_INFO 179 +#define OID_PKI_SENDER_NONCE 180 +#define OID_PKI_RECIPIENT_NONCE 181 +#define OID_PKI_TRANS_ID 182 + +#endif /* OID_H_ */ diff --git a/src/charon/lib/asn1/oid.pl b/src/charon/lib/asn1/oid.pl new file mode 100644 index 000000000..a3725e57d --- /dev/null +++ b/src/charon/lib/asn1/oid.pl @@ -0,0 +1,127 @@ +#!/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", + "#ifndef OID_H_\n", + "#define OID_H_\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++; +} + +print OID_H "\n#endif /* OID_H_ */\n"; + +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/src/charon/lib/asn1/oid.txt b/src/charon/lib/asn1/oid.txt new file mode 100644 index 000000000..eed46d59d --- /dev/null +++ b/src/charon/lib/asn1/oid.txt @@ -0,0 +1,184 @@ +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 + 0x03 "directory" + 0x01 "" + 0x03 "employeeNumber" + 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/src/charon/lib/asn1/pem.c b/src/charon/lib/asn1/pem.c new file mode 100755 index 000000000..b02268dd9 --- /dev/null +++ b/src/charon/lib/asn1/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_hash_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/src/charon/lib/asn1/pem.h b/src/charon/lib/asn1/pem.h new file mode 100755 index 000000000..a4332fd34 --- /dev/null +++ b/src/charon/lib/asn1/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/src/charon/lib/asn1/ttodata.c b/src/charon/lib/asn1/ttodata.c new file mode 100644 index 000000000..5e8149955 --- /dev/null +++ b/src/charon/lib/asn1/ttodata.c @@ -0,0 +1,374 @@ +/* + * 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; +} diff --git a/src/charon/lib/asn1/ttodata.h b/src/charon/lib/asn1/ttodata.h new file mode 100644 index 000000000..d57244ef5 --- /dev/null +++ b/src/charon/lib/asn1/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/src/charon/lib/crypto/Makefile.transforms b/src/charon/lib/crypto/Makefile.transforms new file mode 100644 index 000000000..af0b147da --- /dev/null +++ b/src/charon/lib/crypto/Makefile.transforms @@ -0,0 +1,37 @@ +# 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. +# + +CRYPTO_DIR= $(LIB_DIR)crypto/ + +include $(CRYPTO_DIR)crypters/Makefile.crypters +include $(CRYPTO_DIR)hashers/Makefile.hashers +include $(CRYPTO_DIR)prfs/Makefile.prfs +include $(CRYPTO_DIR)signers/Makefile.signers +include $(CRYPTO_DIR)rsa/Makefile.rsa + +LIB_OBJS+= $(BUILD_DIR)diffie_hellman.o +$(BUILD_DIR)diffie_hellman.o : $(CRYPTO_DIR)diffie_hellman.c $(CRYPTO_DIR)diffie_hellman.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)hmac.o +$(BUILD_DIR)hmac.o : $(CRYPTO_DIR)hmac.c $(CRYPTO_DIR)hmac.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)prf_plus.o +$(BUILD_DIR)prf_plus.o : $(CRYPTO_DIR)prf_plus.c $(CRYPTO_DIR)prf_plus.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)x509.o +$(BUILD_DIR)x509.o : $(CRYPTO_DIR)x509.c $(CRYPTO_DIR)x509.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/charon/lib/crypto/crypters/Makefile.crypters b/src/charon/lib/crypto/crypters/Makefile.crypters new file mode 100644 index 000000000..612477de8 --- /dev/null +++ b/src/charon/lib/crypto/crypters/Makefile.crypters @@ -0,0 +1,23 @@ +# 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. +# + +CRYPTERS_DIR= $(CRYPTO_DIR)crypters/ + +LIB_OBJS+= $(BUILD_DIR)crypter.o +$(BUILD_DIR)crypter.o : $(CRYPTERS_DIR)crypter.c $(CRYPTERS_DIR)crypter.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)aes_cbc_crypter.o +$(BUILD_DIR)aes_cbc_crypter.o : $(CRYPTERS_DIR)aes_cbc_crypter.c $(CRYPTERS_DIR)aes_cbc_crypter.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/charon/lib/crypto/crypters/aes_cbc_crypter.c b/src/charon/lib/crypto/crypters/aes_cbc_crypter.c new file mode 100644 index 000000000..9b7b07c62 --- /dev/null +++ b/src/charon/lib/crypto/crypters/aes_cbc_crypter.c @@ -0,0 +1,1627 @@ +/** + * @file aes_cbc_crypter.c + * + * @brief Implementation of aes_cbc_crypter_t + * + */ + + /* + * Copyright (C) 2001 Dr B. R. Gladman <brg@gladman.uk.net> + * 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 "aes_cbc_crypter.h" + + + +/* + * The number of key schedule words for different block and key lengths + * allowing for method of computation which requires the length to be a + * multiple of the key length. This version of AES implementation supports + * all three keylengths 16, 24 and 32 bytes! + * + * Nk = 4 6 8 + * ------------- + * Nb = 4 | 60 60 64 + * 6 | 96 90 96 + * 8 | 120 120 120 + */ +#define AES_KS_LENGTH 120 +#define AES_RC_LENGTH 29 + +#define AES_BLOCK_SIZE 16 + +typedef struct private_aes_cbc_crypter_t private_aes_cbc_crypter_t; + +/** + * @brief Class implementing the AES symmetric encryption algorithm. + * + * @ingroup crypters + */ +struct private_aes_cbc_crypter_t { + + /** + * Public part of this class. + */ + aes_cbc_crypter_t public; + + /** + * Number of words in the key input block. + */ + u_int32_t aes_Nkey; + + /** + * The number of cipher rounds. + */ + u_int32_t aes_Nrnd; + + /** + * The encryption key schedule. + */ + u_int32_t aes_e_key[AES_KS_LENGTH]; + + /** + * The decryption key schedule. + */ + u_int32_t aes_d_key[AES_KS_LENGTH]; + + /** + * The number of columns in the cipher state. + */ + u_int32_t aes_Ncol; + + /** + * Key size of this AES cypher object. + */ + u_int32_t key_size; + + /** + * Decrypts a block. + * + * No memory gets allocated. + * + * @param this calling object + * @param[in] in_blk block to decrypt + * @param[out] out_blk decrypted data are written to this location + */ + void (*decrypt_block) (const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); + + /** + * Encrypts a block. + * + * No memory gets allocated. + * + * @param this calling object + * @param[in] in_blk block to encrypt + * @param[out] out_blk encrypted data are written to this location + */ + void (*encrypt_block) (const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]); +}; + + +/* ugly macro stuff */ + +/* 1. Define UNROLL for full loop unrolling in encryption and decryption. + * 2. Define PARTIAL_UNROLL to unroll two loops in encryption and decryption. + * 3. Define FIXED_TABLES for compiled rather than dynamic tables. + * 4. Define FF_TABLES to use tables for field multiplies and inverses. + * Do not enable this without understanding stack space requirements. + * 5. Define ARRAYS to use arrays to hold the local state block. If this + * is not defined, individually declared 32-bit words are used. + * 6. Define FAST_VARIABLE if a high speed variable block implementation + * is needed (essentially three separate fixed block size code sequences) + * 7. Define either ONE_TABLE or FOUR_TABLES for a fast table driven + * version using 1 table (2 kbytes of table space) or 4 tables (8 + * kbytes of table space) for higher speed. + * 8. Define either ONE_LR_TABLE or FOUR_LR_TABLES for a further speed + * increase by using tables for the last rounds but with more table + * space (2 or 8 kbytes extra). + * 9. If neither ONE_TABLE nor FOUR_TABLES is defined, a compact but + * slower version is provided. + * 10. If fast decryption key scheduling is needed define ONE_IM_TABLE + * or FOUR_IM_TABLES for higher speed (2 or 8 kbytes extra). + */ + +#define UNROLL +//#define PARTIAL_UNROLL + +#define FIXED_TABLES +//#define FF_TABLES +//#define ARRAYS +#define FAST_VARIABLE + +//#define ONE_TABLE +#define FOUR_TABLES + +//#define ONE_LR_TABLE +#define FOUR_LR_TABLES + +//#define ONE_IM_TABLE +#define FOUR_IM_TABLES + +#if defined(UNROLL) && defined (PARTIAL_UNROLL) +#error both UNROLL and PARTIAL_UNROLL are defined +#endif + +#if defined(ONE_TABLE) && defined (FOUR_TABLES) +#error both ONE_TABLE and FOUR_TABLES are defined +#endif + +#if defined(ONE_LR_TABLE) && defined (FOUR_LR_TABLES) +#error both ONE_LR_TABLE and FOUR_LR_TABLES are defined +#endif + +#if defined(ONE_IM_TABLE) && defined (FOUR_IM_TABLES) +#error both ONE_IM_TABLE and FOUR_IM_TABLES are defined +#endif + +#if defined(AES_BLOCK_SIZE) && AES_BLOCK_SIZE != 16 && AES_BLOCK_SIZE != 24 && AES_BLOCK_SIZE != 32 +#error an illegal block size has been specified +#endif + +/** + * Rotates bytes within words by n positions, moving bytes + * to higher index positions with wrap around into low positions. + */ +#define upr(x,n) (((x) << 8 * (n)) | ((x) >> (32 - 8 * (n)))) +/** + * Moves bytes by n positions to higher index positions in + * words but without wrap around. + */ +#define ups(x,n) ((x) << 8 * (n)) + +/** + * Extracts a byte from a word. + */ +#define bval(x,n) ((unsigned char)((x) >> 8 * (n))) +#define bytes2word(b0, b1, b2, b3) \ + ((u_int32_t)(b3) << 24 | (u_int32_t)(b2) << 16 | (u_int32_t)(b1) << 8 | (b0)) + + +/* little endian processor without data alignment restrictions: AES_LE_OK */ +/* original code: i386 */ +#if defined(i386) || defined(_I386) || defined(__i386__) || defined(__i386) +#define AES_LE_OK 1 +/* added (tested): alpha --jjo */ +#elif defined(__alpha__)|| defined (__alpha) +#define AES_LE_OK 1 +/* added (tested): ia64 --jjo */ +#elif defined(__ia64__)|| defined (__ia64) +#define AES_LE_OK 1 +#endif + +#ifdef AES_LE_OK +/* little endian processor without data alignment restrictions */ +#define word_in(x) *(u_int32_t*)(x) +#define const_word_in(x) *(const u_int32_t*)(x) +#define word_out(x,v) *(u_int32_t*)(x) = (v) +#define const_word_out(x,v) *(const u_int32_t*)(x) = (v) +#else +/* slower but generic big endian or with data alignment restrictions */ +/* some additional "const" touches to stop "gcc -Wcast-qual" complains --jjo */ +#define word_in(x) ((u_int32_t)(((unsigned char *)(x))[0])|((u_int32_t)(((unsigned char *)(x))[1])<<8)|((u_int32_t)(((unsigned char *)(x))[2])<<16)|((u_int32_t)(((unsigned char *)(x))[3])<<24)) +#define const_word_in(x) ((const u_int32_t)(((const unsigned char *)(x))[0])|((const u_int32_t)(((const unsigned char *)(x))[1])<<8)|((const u_int32_t)(((const unsigned char *)(x))[2])<<16)|((const u_int32_t)(((const unsigned char *)(x))[3])<<24)) +#define word_out(x,v) ((unsigned char *)(x))[0]=(v),((unsigned char *)(x))[1]=((v)>>8),((unsigned char *)(x))[2]=((v)>>16),((unsigned char *)(x))[3]=((v)>>24) +#define const_word_out(x,v) ((const unsigned char *)(x))[0]=(v),((const unsigned char *)(x))[1]=((v)>>8),((const unsigned char *)(x))[2]=((v)>>16),((const unsigned char *)(x))[3]=((v)>>24) +#endif + +// Disable at least some poor combinations of options + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) +#define FIXED_TABLES +#undef UNROLL +#undef ONE_LR_TABLE +#undef FOUR_LR_TABLES +#undef ONE_IM_TABLE +#undef FOUR_IM_TABLES +#elif !defined(FOUR_TABLES) +#ifdef FOUR_LR_TABLES +#undef FOUR_LR_TABLES +#define ONE_LR_TABLE +#endif +#ifdef FOUR_IM_TABLES +#undef FOUR_IM_TABLES +#define ONE_IM_TABLE +#endif +#elif !defined(AES_BLOCK_SIZE) +#if defined(UNROLL) +#define PARTIAL_UNROLL +#undef UNROLL +#endif +#endif + +// the finite field modular polynomial and elements + +#define ff_poly 0x011b +#define ff_hi 0x80 + +// multiply four bytes in GF(2^8) by 'x' {02} in parallel + +#define m1 0x80808080 +#define m2 0x7f7f7f7f +#define m3 0x0000001b +#define FFmulX(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * m3)) + +// The following defines provide alternative definitions of FFmulX that might +// give improved performance if a fast 32-bit multiply is not available. Note +// that a temporary variable u needs to be defined where FFmulX is used. + +// #define FFmulX(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) +// #define m4 0x1b1b1b1b +// #define FFmulX(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) + +// perform column mix operation on four bytes in parallel + +#define fwd_mcol(x) (f2 = FFmulX(x), f2 ^ upr(x ^ f2,3) ^ upr(x,2) ^ upr(x,1)) + +#if defined(FIXED_TABLES) + +// the S-Box table + +static const unsigned char s_box[256] = +{ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +// the inverse S-Box table + +static const unsigned char inv_s_box[256] = +{ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +#define w0(p) 0x000000##p + +// Number of elements required in this table for different +// block and key lengths is: +// +// Nk = 4 6 8 +// ---------- +// Nb = 4 | 10 8 7 +// 6 | 19 12 11 +// 8 | 29 19 14 +// +// this table can be a table of bytes if the key schedule +// code is adjusted accordingly + +static const u_int32_t rcon_tab[29] = +{ + w0(01), w0(02), w0(04), w0(08), + w0(10), w0(20), w0(40), w0(80), + w0(1b), w0(36), w0(6c), w0(d8), + w0(ab), w0(4d), w0(9a), w0(2f), + w0(5e), w0(bc), w0(63), w0(c6), + w0(97), w0(35), w0(6a), w0(d4), + w0(b3), w0(7d), w0(fa), w0(ef), + w0(c5) +}; + +#undef w0 + +#define r0(p,q,r,s) 0x##p##q##r##s +#define r1(p,q,r,s) 0x##q##r##s##p +#define r2(p,q,r,s) 0x##r##s##p##q +#define r3(p,q,r,s) 0x##s##p##q##r +#define w0(p) 0x000000##p +#define w1(p) 0x0000##p##00 +#define w2(p) 0x00##p##0000 +#define w3(p) 0x##p##000000 + +#if defined(FIXED_TABLES) && (defined(ONE_TABLE) || defined(FOUR_TABLES)) + +// data for forward tables (other than last round) + +#define f_table \ + r(a5,63,63,c6), r(84,7c,7c,f8), r(99,77,77,ee), r(8d,7b,7b,f6),\ + r(0d,f2,f2,ff), r(bd,6b,6b,d6), r(b1,6f,6f,de), r(54,c5,c5,91),\ + r(50,30,30,60), r(03,01,01,02), r(a9,67,67,ce), r(7d,2b,2b,56),\ + r(19,fe,fe,e7), r(62,d7,d7,b5), r(e6,ab,ab,4d), r(9a,76,76,ec),\ + r(45,ca,ca,8f), r(9d,82,82,1f), r(40,c9,c9,89), r(87,7d,7d,fa),\ + r(15,fa,fa,ef), r(eb,59,59,b2), r(c9,47,47,8e), r(0b,f0,f0,fb),\ + r(ec,ad,ad,41), r(67,d4,d4,b3), r(fd,a2,a2,5f), r(ea,af,af,45),\ + r(bf,9c,9c,23), r(f7,a4,a4,53), r(96,72,72,e4), r(5b,c0,c0,9b),\ + r(c2,b7,b7,75), r(1c,fd,fd,e1), r(ae,93,93,3d), r(6a,26,26,4c),\ + r(5a,36,36,6c), r(41,3f,3f,7e), r(02,f7,f7,f5), r(4f,cc,cc,83),\ + r(5c,34,34,68), r(f4,a5,a5,51), r(34,e5,e5,d1), r(08,f1,f1,f9),\ + r(93,71,71,e2), r(73,d8,d8,ab), r(53,31,31,62), r(3f,15,15,2a),\ + r(0c,04,04,08), r(52,c7,c7,95), r(65,23,23,46), r(5e,c3,c3,9d),\ + r(28,18,18,30), r(a1,96,96,37), r(0f,05,05,0a), r(b5,9a,9a,2f),\ + r(09,07,07,0e), r(36,12,12,24), r(9b,80,80,1b), r(3d,e2,e2,df),\ + r(26,eb,eb,cd), r(69,27,27,4e), r(cd,b2,b2,7f), r(9f,75,75,ea),\ + r(1b,09,09,12), r(9e,83,83,1d), r(74,2c,2c,58), r(2e,1a,1a,34),\ + r(2d,1b,1b,36), r(b2,6e,6e,dc), r(ee,5a,5a,b4), r(fb,a0,a0,5b),\ + r(f6,52,52,a4), r(4d,3b,3b,76), r(61,d6,d6,b7), r(ce,b3,b3,7d),\ + r(7b,29,29,52), r(3e,e3,e3,dd), r(71,2f,2f,5e), r(97,84,84,13),\ + r(f5,53,53,a6), r(68,d1,d1,b9), r(00,00,00,00), r(2c,ed,ed,c1),\ + r(60,20,20,40), r(1f,fc,fc,e3), r(c8,b1,b1,79), r(ed,5b,5b,b6),\ + r(be,6a,6a,d4), r(46,cb,cb,8d), r(d9,be,be,67), r(4b,39,39,72),\ + r(de,4a,4a,94), r(d4,4c,4c,98), r(e8,58,58,b0), r(4a,cf,cf,85),\ + r(6b,d0,d0,bb), r(2a,ef,ef,c5), r(e5,aa,aa,4f), r(16,fb,fb,ed),\ + r(c5,43,43,86), r(d7,4d,4d,9a), r(55,33,33,66), r(94,85,85,11),\ + r(cf,45,45,8a), r(10,f9,f9,e9), r(06,02,02,04), r(81,7f,7f,fe),\ + r(f0,50,50,a0), r(44,3c,3c,78), r(ba,9f,9f,25), r(e3,a8,a8,4b),\ + r(f3,51,51,a2), r(fe,a3,a3,5d), r(c0,40,40,80), r(8a,8f,8f,05),\ + r(ad,92,92,3f), r(bc,9d,9d,21), r(48,38,38,70), r(04,f5,f5,f1),\ + r(df,bc,bc,63), r(c1,b6,b6,77), r(75,da,da,af), r(63,21,21,42),\ + r(30,10,10,20), r(1a,ff,ff,e5), r(0e,f3,f3,fd), r(6d,d2,d2,bf),\ + r(4c,cd,cd,81), r(14,0c,0c,18), r(35,13,13,26), r(2f,ec,ec,c3),\ + r(e1,5f,5f,be), r(a2,97,97,35), r(cc,44,44,88), r(39,17,17,2e),\ + r(57,c4,c4,93), r(f2,a7,a7,55), r(82,7e,7e,fc), r(47,3d,3d,7a),\ + r(ac,64,64,c8), r(e7,5d,5d,ba), r(2b,19,19,32), r(95,73,73,e6),\ + r(a0,60,60,c0), r(98,81,81,19), r(d1,4f,4f,9e), r(7f,dc,dc,a3),\ + r(66,22,22,44), r(7e,2a,2a,54), r(ab,90,90,3b), r(83,88,88,0b),\ + r(ca,46,46,8c), r(29,ee,ee,c7), r(d3,b8,b8,6b), r(3c,14,14,28),\ + r(79,de,de,a7), r(e2,5e,5e,bc), r(1d,0b,0b,16), r(76,db,db,ad),\ + r(3b,e0,e0,db), r(56,32,32,64), r(4e,3a,3a,74), r(1e,0a,0a,14),\ + r(db,49,49,92), r(0a,06,06,0c), r(6c,24,24,48), r(e4,5c,5c,b8),\ + r(5d,c2,c2,9f), r(6e,d3,d3,bd), r(ef,ac,ac,43), r(a6,62,62,c4),\ + r(a8,91,91,39), r(a4,95,95,31), r(37,e4,e4,d3), r(8b,79,79,f2),\ + r(32,e7,e7,d5), r(43,c8,c8,8b), r(59,37,37,6e), r(b7,6d,6d,da),\ + r(8c,8d,8d,01), r(64,d5,d5,b1), r(d2,4e,4e,9c), r(e0,a9,a9,49),\ + r(b4,6c,6c,d8), r(fa,56,56,ac), r(07,f4,f4,f3), r(25,ea,ea,cf),\ + r(af,65,65,ca), r(8e,7a,7a,f4), r(e9,ae,ae,47), r(18,08,08,10),\ + r(d5,ba,ba,6f), r(88,78,78,f0), r(6f,25,25,4a), r(72,2e,2e,5c),\ + r(24,1c,1c,38), r(f1,a6,a6,57), r(c7,b4,b4,73), r(51,c6,c6,97),\ + r(23,e8,e8,cb), r(7c,dd,dd,a1), r(9c,74,74,e8), r(21,1f,1f,3e),\ + r(dd,4b,4b,96), r(dc,bd,bd,61), r(86,8b,8b,0d), r(85,8a,8a,0f),\ + r(90,70,70,e0), r(42,3e,3e,7c), r(c4,b5,b5,71), r(aa,66,66,cc),\ + r(d8,48,48,90), r(05,03,03,06), r(01,f6,f6,f7), r(12,0e,0e,1c),\ + r(a3,61,61,c2), r(5f,35,35,6a), r(f9,57,57,ae), r(d0,b9,b9,69),\ + r(91,86,86,17), r(58,c1,c1,99), r(27,1d,1d,3a), r(b9,9e,9e,27),\ + r(38,e1,e1,d9), r(13,f8,f8,eb), r(b3,98,98,2b), r(33,11,11,22),\ + r(bb,69,69,d2), r(70,d9,d9,a9), r(89,8e,8e,07), r(a7,94,94,33),\ + r(b6,9b,9b,2d), r(22,1e,1e,3c), r(92,87,87,15), r(20,e9,e9,c9),\ + r(49,ce,ce,87), r(ff,55,55,aa), r(78,28,28,50), r(7a,df,df,a5),\ + r(8f,8c,8c,03), r(f8,a1,a1,59), r(80,89,89,09), r(17,0d,0d,1a),\ + r(da,bf,bf,65), r(31,e6,e6,d7), r(c6,42,42,84), r(b8,68,68,d0),\ + r(c3,41,41,82), r(b0,99,99,29), r(77,2d,2d,5a), r(11,0f,0f,1e),\ + r(cb,b0,b0,7b), r(fc,54,54,a8), r(d6,bb,bb,6d), r(3a,16,16,2c) + +// data for inverse tables (other than last round) + +#define i_table \ + r(50,a7,f4,51), r(53,65,41,7e), r(c3,a4,17,1a), r(96,5e,27,3a),\ + r(cb,6b,ab,3b), r(f1,45,9d,1f), r(ab,58,fa,ac), r(93,03,e3,4b),\ + r(55,fa,30,20), r(f6,6d,76,ad), r(91,76,cc,88), r(25,4c,02,f5),\ + r(fc,d7,e5,4f), r(d7,cb,2a,c5), r(80,44,35,26), r(8f,a3,62,b5),\ + r(49,5a,b1,de), r(67,1b,ba,25), r(98,0e,ea,45), r(e1,c0,fe,5d),\ + r(02,75,2f,c3), r(12,f0,4c,81), r(a3,97,46,8d), r(c6,f9,d3,6b),\ + r(e7,5f,8f,03), r(95,9c,92,15), r(eb,7a,6d,bf), r(da,59,52,95),\ + r(2d,83,be,d4), r(d3,21,74,58), r(29,69,e0,49), r(44,c8,c9,8e),\ + r(6a,89,c2,75), r(78,79,8e,f4), r(6b,3e,58,99), r(dd,71,b9,27),\ + r(b6,4f,e1,be), r(17,ad,88,f0), r(66,ac,20,c9), r(b4,3a,ce,7d),\ + r(18,4a,df,63), r(82,31,1a,e5), r(60,33,51,97), r(45,7f,53,62),\ + r(e0,77,64,b1), r(84,ae,6b,bb), r(1c,a0,81,fe), r(94,2b,08,f9),\ + r(58,68,48,70), r(19,fd,45,8f), r(87,6c,de,94), r(b7,f8,7b,52),\ + r(23,d3,73,ab), r(e2,02,4b,72), r(57,8f,1f,e3), r(2a,ab,55,66),\ + r(07,28,eb,b2), r(03,c2,b5,2f), r(9a,7b,c5,86), r(a5,08,37,d3),\ + r(f2,87,28,30), r(b2,a5,bf,23), r(ba,6a,03,02), r(5c,82,16,ed),\ + r(2b,1c,cf,8a), r(92,b4,79,a7), r(f0,f2,07,f3), r(a1,e2,69,4e),\ + r(cd,f4,da,65), r(d5,be,05,06), r(1f,62,34,d1), r(8a,fe,a6,c4),\ + r(9d,53,2e,34), r(a0,55,f3,a2), r(32,e1,8a,05), r(75,eb,f6,a4),\ + r(39,ec,83,0b), r(aa,ef,60,40), r(06,9f,71,5e), r(51,10,6e,bd),\ + r(f9,8a,21,3e), r(3d,06,dd,96), r(ae,05,3e,dd), r(46,bd,e6,4d),\ + r(b5,8d,54,91), r(05,5d,c4,71), r(6f,d4,06,04), r(ff,15,50,60),\ + r(24,fb,98,19), r(97,e9,bd,d6), r(cc,43,40,89), r(77,9e,d9,67),\ + r(bd,42,e8,b0), r(88,8b,89,07), r(38,5b,19,e7), r(db,ee,c8,79),\ + r(47,0a,7c,a1), r(e9,0f,42,7c), r(c9,1e,84,f8), r(00,00,00,00),\ + r(83,86,80,09), r(48,ed,2b,32), r(ac,70,11,1e), r(4e,72,5a,6c),\ + r(fb,ff,0e,fd), r(56,38,85,0f), r(1e,d5,ae,3d), r(27,39,2d,36),\ + r(64,d9,0f,0a), r(21,a6,5c,68), r(d1,54,5b,9b), r(3a,2e,36,24),\ + r(b1,67,0a,0c), r(0f,e7,57,93), r(d2,96,ee,b4), r(9e,91,9b,1b),\ + r(4f,c5,c0,80), r(a2,20,dc,61), r(69,4b,77,5a), r(16,1a,12,1c),\ + r(0a,ba,93,e2), r(e5,2a,a0,c0), r(43,e0,22,3c), r(1d,17,1b,12),\ + r(0b,0d,09,0e), r(ad,c7,8b,f2), r(b9,a8,b6,2d), r(c8,a9,1e,14),\ + r(85,19,f1,57), r(4c,07,75,af), r(bb,dd,99,ee), r(fd,60,7f,a3),\ + r(9f,26,01,f7), r(bc,f5,72,5c), r(c5,3b,66,44), r(34,7e,fb,5b),\ + r(76,29,43,8b), r(dc,c6,23,cb), r(68,fc,ed,b6), r(63,f1,e4,b8),\ + r(ca,dc,31,d7), r(10,85,63,42), r(40,22,97,13), r(20,11,c6,84),\ + r(7d,24,4a,85), r(f8,3d,bb,d2), r(11,32,f9,ae), r(6d,a1,29,c7),\ + r(4b,2f,9e,1d), r(f3,30,b2,dc), r(ec,52,86,0d), r(d0,e3,c1,77),\ + r(6c,16,b3,2b), r(99,b9,70,a9), r(fa,48,94,11), r(22,64,e9,47),\ + r(c4,8c,fc,a8), r(1a,3f,f0,a0), r(d8,2c,7d,56), r(ef,90,33,22),\ + r(c7,4e,49,87), r(c1,d1,38,d9), r(fe,a2,ca,8c), r(36,0b,d4,98),\ + r(cf,81,f5,a6), r(28,de,7a,a5), r(26,8e,b7,da), r(a4,bf,ad,3f),\ + r(e4,9d,3a,2c), r(0d,92,78,50), r(9b,cc,5f,6a), r(62,46,7e,54),\ + r(c2,13,8d,f6), r(e8,b8,d8,90), r(5e,f7,39,2e), r(f5,af,c3,82),\ + r(be,80,5d,9f), r(7c,93,d0,69), r(a9,2d,d5,6f), r(b3,12,25,cf),\ + r(3b,99,ac,c8), r(a7,7d,18,10), r(6e,63,9c,e8), r(7b,bb,3b,db),\ + r(09,78,26,cd), r(f4,18,59,6e), r(01,b7,9a,ec), r(a8,9a,4f,83),\ + r(65,6e,95,e6), r(7e,e6,ff,aa), r(08,cf,bc,21), r(e6,e8,15,ef),\ + r(d9,9b,e7,ba), r(ce,36,6f,4a), r(d4,09,9f,ea), r(d6,7c,b0,29),\ + r(af,b2,a4,31), r(31,23,3f,2a), r(30,94,a5,c6), r(c0,66,a2,35),\ + r(37,bc,4e,74), r(a6,ca,82,fc), r(b0,d0,90,e0), r(15,d8,a7,33),\ + r(4a,98,04,f1), r(f7,da,ec,41), r(0e,50,cd,7f), r(2f,f6,91,17),\ + r(8d,d6,4d,76), r(4d,b0,ef,43), r(54,4d,aa,cc), r(df,04,96,e4),\ + r(e3,b5,d1,9e), r(1b,88,6a,4c), r(b8,1f,2c,c1), r(7f,51,65,46),\ + r(04,ea,5e,9d), r(5d,35,8c,01), r(73,74,87,fa), r(2e,41,0b,fb),\ + r(5a,1d,67,b3), r(52,d2,db,92), r(33,56,10,e9), r(13,47,d6,6d),\ + r(8c,61,d7,9a), r(7a,0c,a1,37), r(8e,14,f8,59), r(89,3c,13,eb),\ + r(ee,27,a9,ce), r(35,c9,61,b7), r(ed,e5,1c,e1), r(3c,b1,47,7a),\ + r(59,df,d2,9c), r(3f,73,f2,55), r(79,ce,14,18), r(bf,37,c7,73),\ + r(ea,cd,f7,53), r(5b,aa,fd,5f), r(14,6f,3d,df), r(86,db,44,78),\ + r(81,f3,af,ca), r(3e,c4,68,b9), r(2c,34,24,38), r(5f,40,a3,c2),\ + r(72,c3,1d,16), r(0c,25,e2,bc), r(8b,49,3c,28), r(41,95,0d,ff),\ + r(71,01,a8,39), r(de,b3,0c,08), r(9c,e4,b4,d8), r(90,c1,56,64),\ + r(61,84,cb,7b), r(70,b6,32,d5), r(74,5c,6c,48), r(42,57,b8,d0) + +// generate the required tables in the desired endian format + +#undef r +#define r r0 + +#if defined(ONE_TABLE) +static const u_int32_t ft_tab[256] = + { f_table }; +#elif defined(FOUR_TABLES) +static const u_int32_t ft_tab[4][256] = +{ { f_table }, +#undef r +#define r r1 + { f_table }, +#undef r +#define r r2 + { f_table }, +#undef r +#define r r3 + { f_table } +}; +#endif + +#undef r +#define r r0 +#if defined(ONE_TABLE) +static const u_int32_t it_tab[256] = + { i_table }; +#elif defined(FOUR_TABLES) +static const u_int32_t it_tab[4][256] = +{ { i_table }, +#undef r +#define r r1 + { i_table }, +#undef r +#define r r2 + { i_table }, +#undef r +#define r r3 + { i_table } +}; +#endif + +#endif + +#if defined(FIXED_TABLES) && (defined(ONE_LR_TABLE) || defined(FOUR_LR_TABLES)) + +// data for inverse tables (last round) + +#define li_table \ + w(52), w(09), w(6a), w(d5), w(30), w(36), w(a5), w(38),\ + w(bf), w(40), w(a3), w(9e), w(81), w(f3), w(d7), w(fb),\ + w(7c), w(e3), w(39), w(82), w(9b), w(2f), w(ff), w(87),\ + w(34), w(8e), w(43), w(44), w(c4), w(de), w(e9), w(cb),\ + w(54), w(7b), w(94), w(32), w(a6), w(c2), w(23), w(3d),\ + w(ee), w(4c), w(95), w(0b), w(42), w(fa), w(c3), w(4e),\ + w(08), w(2e), w(a1), w(66), w(28), w(d9), w(24), w(b2),\ + w(76), w(5b), w(a2), w(49), w(6d), w(8b), w(d1), w(25),\ + w(72), w(f8), w(f6), w(64), w(86), w(68), w(98), w(16),\ + w(d4), w(a4), w(5c), w(cc), w(5d), w(65), w(b6), w(92),\ + w(6c), w(70), w(48), w(50), w(fd), w(ed), w(b9), w(da),\ + w(5e), w(15), w(46), w(57), w(a7), w(8d), w(9d), w(84),\ + w(90), w(d8), w(ab), w(00), w(8c), w(bc), w(d3), w(0a),\ + w(f7), w(e4), w(58), w(05), w(b8), w(b3), w(45), w(06),\ + w(d0), w(2c), w(1e), w(8f), w(ca), w(3f), w(0f), w(02),\ + w(c1), w(af), w(bd), w(03), w(01), w(13), w(8a), w(6b),\ + w(3a), w(91), w(11), w(41), w(4f), w(67), w(dc), w(ea),\ + w(97), w(f2), w(cf), w(ce), w(f0), w(b4), w(e6), w(73),\ + w(96), w(ac), w(74), w(22), w(e7), w(ad), w(35), w(85),\ + w(e2), w(f9), w(37), w(e8), w(1c), w(75), w(df), w(6e),\ + w(47), w(f1), w(1a), w(71), w(1d), w(29), w(c5), w(89),\ + w(6f), w(b7), w(62), w(0e), w(aa), w(18), w(be), w(1b),\ + w(fc), w(56), w(3e), w(4b), w(c6), w(d2), w(79), w(20),\ + w(9a), w(db), w(c0), w(fe), w(78), w(cd), w(5a), w(f4),\ + w(1f), w(dd), w(a8), w(33), w(88), w(07), w(c7), w(31),\ + w(b1), w(12), w(10), w(59), w(27), w(80), w(ec), w(5f),\ + w(60), w(51), w(7f), w(a9), w(19), w(b5), w(4a), w(0d),\ + w(2d), w(e5), w(7a), w(9f), w(93), w(c9), w(9c), w(ef),\ + w(a0), w(e0), w(3b), w(4d), w(ae), w(2a), w(f5), w(b0),\ + w(c8), w(eb), w(bb), w(3c), w(83), w(53), w(99), w(61),\ + w(17), w(2b), w(04), w(7e), w(ba), w(77), w(d6), w(26),\ + w(e1), w(69), w(14), w(63), w(55), w(21), w(0c), w(7d), + +// generate the required tables in the desired endian format + +#undef r +#define r(p,q,r,s) w0(q) +#if defined(ONE_LR_TABLE) +static const u_int32_t fl_tab[256] = + { f_table }; +#elif defined(FOUR_LR_TABLES) +static const u_int32_t fl_tab[4][256] = +{ { f_table }, +#undef r +#define r(p,q,r,s) w1(q) + { f_table }, +#undef r +#define r(p,q,r,s) w2(q) + { f_table }, +#undef r +#define r(p,q,r,s) w3(q) + { f_table } +}; +#endif + +#undef w +#define w w0 +#if defined(ONE_LR_TABLE) +static const u_int32_t il_tab[256] = + { li_table }; +#elif defined(FOUR_LR_TABLES) +static const u_int32_t il_tab[4][256] = +{ { li_table }, +#undef w +#define w w1 + { li_table }, +#undef w +#define w w2 + { li_table }, +#undef w +#define w w3 + { li_table } +}; +#endif + +#endif + +#if defined(FIXED_TABLES) && (defined(ONE_IM_TABLE) || defined(FOUR_IM_TABLES)) + +#define m_table \ + r(00,00,00,00), r(0b,0d,09,0e), r(16,1a,12,1c), r(1d,17,1b,12),\ + r(2c,34,24,38), r(27,39,2d,36), r(3a,2e,36,24), r(31,23,3f,2a),\ + r(58,68,48,70), r(53,65,41,7e), r(4e,72,5a,6c), r(45,7f,53,62),\ + r(74,5c,6c,48), r(7f,51,65,46), r(62,46,7e,54), r(69,4b,77,5a),\ + r(b0,d0,90,e0), r(bb,dd,99,ee), r(a6,ca,82,fc), r(ad,c7,8b,f2),\ + r(9c,e4,b4,d8), r(97,e9,bd,d6), r(8a,fe,a6,c4), r(81,f3,af,ca),\ + r(e8,b8,d8,90), r(e3,b5,d1,9e), r(fe,a2,ca,8c), r(f5,af,c3,82),\ + r(c4,8c,fc,a8), r(cf,81,f5,a6), r(d2,96,ee,b4), r(d9,9b,e7,ba),\ + r(7b,bb,3b,db), r(70,b6,32,d5), r(6d,a1,29,c7), r(66,ac,20,c9),\ + r(57,8f,1f,e3), r(5c,82,16,ed), r(41,95,0d,ff), r(4a,98,04,f1),\ + r(23,d3,73,ab), r(28,de,7a,a5), r(35,c9,61,b7), r(3e,c4,68,b9),\ + r(0f,e7,57,93), r(04,ea,5e,9d), r(19,fd,45,8f), r(12,f0,4c,81),\ + r(cb,6b,ab,3b), r(c0,66,a2,35), r(dd,71,b9,27), r(d6,7c,b0,29),\ + r(e7,5f,8f,03), r(ec,52,86,0d), r(f1,45,9d,1f), r(fa,48,94,11),\ + r(93,03,e3,4b), r(98,0e,ea,45), r(85,19,f1,57), r(8e,14,f8,59),\ + r(bf,37,c7,73), r(b4,3a,ce,7d), r(a9,2d,d5,6f), r(a2,20,dc,61),\ + r(f6,6d,76,ad), r(fd,60,7f,a3), r(e0,77,64,b1), r(eb,7a,6d,bf),\ + r(da,59,52,95), r(d1,54,5b,9b), r(cc,43,40,89), r(c7,4e,49,87),\ + r(ae,05,3e,dd), r(a5,08,37,d3), r(b8,1f,2c,c1), r(b3,12,25,cf),\ + r(82,31,1a,e5), r(89,3c,13,eb), r(94,2b,08,f9), r(9f,26,01,f7),\ + r(46,bd,e6,4d), r(4d,b0,ef,43), r(50,a7,f4,51), r(5b,aa,fd,5f),\ + r(6a,89,c2,75), r(61,84,cb,7b), r(7c,93,d0,69), r(77,9e,d9,67),\ + r(1e,d5,ae,3d), r(15,d8,a7,33), r(08,cf,bc,21), r(03,c2,b5,2f),\ + r(32,e1,8a,05), r(39,ec,83,0b), r(24,fb,98,19), r(2f,f6,91,17),\ + r(8d,d6,4d,76), r(86,db,44,78), r(9b,cc,5f,6a), r(90,c1,56,64),\ + r(a1,e2,69,4e), r(aa,ef,60,40), r(b7,f8,7b,52), r(bc,f5,72,5c),\ + r(d5,be,05,06), r(de,b3,0c,08), r(c3,a4,17,1a), r(c8,a9,1e,14),\ + r(f9,8a,21,3e), r(f2,87,28,30), r(ef,90,33,22), r(e4,9d,3a,2c),\ + r(3d,06,dd,96), r(36,0b,d4,98), r(2b,1c,cf,8a), r(20,11,c6,84),\ + r(11,32,f9,ae), r(1a,3f,f0,a0), r(07,28,eb,b2), r(0c,25,e2,bc),\ + r(65,6e,95,e6), r(6e,63,9c,e8), r(73,74,87,fa), r(78,79,8e,f4),\ + r(49,5a,b1,de), r(42,57,b8,d0), r(5f,40,a3,c2), r(54,4d,aa,cc),\ + r(f7,da,ec,41), r(fc,d7,e5,4f), r(e1,c0,fe,5d), r(ea,cd,f7,53),\ + r(db,ee,c8,79), r(d0,e3,c1,77), r(cd,f4,da,65), r(c6,f9,d3,6b),\ + r(af,b2,a4,31), r(a4,bf,ad,3f), r(b9,a8,b6,2d), r(b2,a5,bf,23),\ + r(83,86,80,09), r(88,8b,89,07), r(95,9c,92,15), r(9e,91,9b,1b),\ + r(47,0a,7c,a1), r(4c,07,75,af), r(51,10,6e,bd), r(5a,1d,67,b3),\ + r(6b,3e,58,99), r(60,33,51,97), r(7d,24,4a,85), r(76,29,43,8b),\ + r(1f,62,34,d1), r(14,6f,3d,df), r(09,78,26,cd), r(02,75,2f,c3),\ + r(33,56,10,e9), r(38,5b,19,e7), r(25,4c,02,f5), r(2e,41,0b,fb),\ + r(8c,61,d7,9a), r(87,6c,de,94), r(9a,7b,c5,86), r(91,76,cc,88),\ + r(a0,55,f3,a2), r(ab,58,fa,ac), r(b6,4f,e1,be), r(bd,42,e8,b0),\ + r(d4,09,9f,ea), r(df,04,96,e4), r(c2,13,8d,f6), r(c9,1e,84,f8),\ + r(f8,3d,bb,d2), r(f3,30,b2,dc), r(ee,27,a9,ce), r(e5,2a,a0,c0),\ + r(3c,b1,47,7a), r(37,bc,4e,74), r(2a,ab,55,66), r(21,a6,5c,68),\ + r(10,85,63,42), r(1b,88,6a,4c), r(06,9f,71,5e), r(0d,92,78,50),\ + r(64,d9,0f,0a), r(6f,d4,06,04), r(72,c3,1d,16), r(79,ce,14,18),\ + r(48,ed,2b,32), r(43,e0,22,3c), r(5e,f7,39,2e), r(55,fa,30,20),\ + r(01,b7,9a,ec), r(0a,ba,93,e2), r(17,ad,88,f0), r(1c,a0,81,fe),\ + r(2d,83,be,d4), r(26,8e,b7,da), r(3b,99,ac,c8), r(30,94,a5,c6),\ + r(59,df,d2,9c), r(52,d2,db,92), r(4f,c5,c0,80), r(44,c8,c9,8e),\ + r(75,eb,f6,a4), r(7e,e6,ff,aa), r(63,f1,e4,b8), r(68,fc,ed,b6),\ + r(b1,67,0a,0c), r(ba,6a,03,02), r(a7,7d,18,10), r(ac,70,11,1e),\ + r(9d,53,2e,34), r(96,5e,27,3a), r(8b,49,3c,28), r(80,44,35,26),\ + r(e9,0f,42,7c), r(e2,02,4b,72), r(ff,15,50,60), r(f4,18,59,6e),\ + r(c5,3b,66,44), r(ce,36,6f,4a), r(d3,21,74,58), r(d8,2c,7d,56),\ + r(7a,0c,a1,37), r(71,01,a8,39), r(6c,16,b3,2b), r(67,1b,ba,25),\ + r(56,38,85,0f), r(5d,35,8c,01), r(40,22,97,13), r(4b,2f,9e,1d),\ + r(22,64,e9,47), r(29,69,e0,49), r(34,7e,fb,5b), r(3f,73,f2,55),\ + r(0e,50,cd,7f), r(05,5d,c4,71), r(18,4a,df,63), r(13,47,d6,6d),\ + r(ca,dc,31,d7), r(c1,d1,38,d9), r(dc,c6,23,cb), r(d7,cb,2a,c5),\ + r(e6,e8,15,ef), r(ed,e5,1c,e1), r(f0,f2,07,f3), r(fb,ff,0e,fd),\ + r(92,b4,79,a7), r(99,b9,70,a9), r(84,ae,6b,bb), r(8f,a3,62,b5),\ + r(be,80,5d,9f), r(b5,8d,54,91), r(a8,9a,4f,83), r(a3,97,46,8d) + +#undef r +#define r r0 + +#if defined(ONE_IM_TABLE) +static const u_int32_t im_tab[256] = + { m_table }; +#elif defined(FOUR_IM_TABLES) +static const u_int32_t im_tab[4][256] = +{ { m_table }, +#undef r +#define r r1 + { m_table }, +#undef r +#define r r2 + { m_table }, +#undef r +#define r r3 + { m_table } +}; +#endif + +#endif + +#else + +static int tab_gen = 0; + +static unsigned char s_box[256]; // the S box +static unsigned char inv_s_box[256]; // the inverse S box +static u_int32_t rcon_tab[AES_RC_LENGTH]; // table of round constants + +#if defined(ONE_TABLE) +static u_int32_t ft_tab[256]; +static u_int32_t it_tab[256]; +#elif defined(FOUR_TABLES) +static u_int32_t ft_tab[4][256]; +static u_int32_t it_tab[4][256]; +#endif + +#if defined(ONE_LR_TABLE) +static u_int32_t fl_tab[256]; +static u_int32_t il_tab[256]; +#elif defined(FOUR_LR_TABLES) +static u_int32_t fl_tab[4][256]; +static u_int32_t il_tab[4][256]; +#endif + +#if defined(ONE_IM_TABLE) +static u_int32_t im_tab[256]; +#elif defined(FOUR_IM_TABLES) +static u_int32_t im_tab[4][256]; +#endif + +// Generate the tables for the dynamic table option + +#if !defined(FF_TABLES) + +// It will generally be sensible to use tables to compute finite +// field multiplies and inverses but where memory is scarse this +// code might sometimes be better. + +// return 2 ^ (n - 1) where n is the bit number of the highest bit +// set in x with x in the range 1 < x < 0x00000200. This form is +// used so that locals within FFinv can be bytes rather than words + +static unsigned char hibit(const u_int32_t x) +{ unsigned char r = (unsigned char)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +// return the inverse of the finite field element x + +static unsigned char FFinv(const unsigned char x) +{ unsigned char p1 = x, p2 = 0x1b, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) return x; + + for(;;) + { + if(!n1) return v1; + + while(n2 >= n1) + { + n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); + } + + if(!n2) return v2; + + while(n1 >= n2) + { + n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); + } + } +} + +// define the finite field multiplies required for Rijndael + +#define FFmul02(x) ((((x) & 0x7f) << 1) ^ ((x) & 0x80 ? 0x1b : 0)) +#define FFmul03(x) ((x) ^ FFmul02(x)) +#define FFmul09(x) ((x) ^ FFmul02(FFmul02(FFmul02(x)))) +#define FFmul0b(x) ((x) ^ FFmul02((x) ^ FFmul02(FFmul02(x)))) +#define FFmul0d(x) ((x) ^ FFmul02(FFmul02((x) ^ FFmul02(x)))) +#define FFmul0e(x) FFmul02((x) ^ FFmul02((x) ^ FFmul02(x))) + +#else + +#define FFinv(x) ((x) ? pow[255 - log[x]]: 0) + +#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0) +#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0) +#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0) +#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0) +#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0) +#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0) + +#endif + +// The forward and inverse affine transformations used in the S-box + +#define fwd_affine(x) \ + (w = (u_int32_t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(unsigned char)(w^(w>>8))) + +#define inv_affine(x) \ + (w = (u_int32_t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(unsigned char)(w^(w>>8))) + +static void gen_tabs(void) +{ u_int32_t i, w; + +#if defined(FF_TABLES) + + unsigned char pow[512], log[256]; + + // log and power tables for GF(2^8) finite field with + // 0x011b as modular polynomial - the simplest primitive + // root is 0x03, used here to generate the tables + + i = 0; w = 1; + do + { + pow[i] = (unsigned char)w; + pow[i + 255] = (unsigned char)w; + log[w] = (unsigned char)i++; + w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } + while (w != 1); + +#endif + + for(i = 0, w = 1; i < AES_RC_LENGTH; ++i) + { + rcon_tab[i] = bytes2word(w, 0, 0, 0); + w = (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } + + for(i = 0; i < 256; ++i) + { unsigned char b; + + s_box[i] = b = fwd_affine(FFinv((unsigned char)i)); + + w = bytes2word(b, 0, 0, 0); +#if defined(ONE_LR_TABLE) + fl_tab[i] = w; +#elif defined(FOUR_LR_TABLES) + fl_tab[0][i] = w; + fl_tab[1][i] = upr(w,1); + fl_tab[2][i] = upr(w,2); + fl_tab[3][i] = upr(w,3); +#endif + w = bytes2word(FFmul02(b), b, b, FFmul03(b)); +#if defined(ONE_TABLE) + ft_tab[i] = w; +#elif defined(FOUR_TABLES) + ft_tab[0][i] = w; + ft_tab[1][i] = upr(w,1); + ft_tab[2][i] = upr(w,2); + ft_tab[3][i] = upr(w,3); +#endif + inv_s_box[i] = b = FFinv(inv_affine((unsigned char)i)); + + w = bytes2word(b, 0, 0, 0); +#if defined(ONE_LR_TABLE) + il_tab[i] = w; +#elif defined(FOUR_LR_TABLES) + il_tab[0][i] = w; + il_tab[1][i] = upr(w,1); + il_tab[2][i] = upr(w,2); + il_tab[3][i] = upr(w,3); +#endif + w = bytes2word(FFmul0e(b), FFmul09(b), FFmul0d(b), FFmul0b(b)); +#if defined(ONE_TABLE) + it_tab[i] = w; +#elif defined(FOUR_TABLES) + it_tab[0][i] = w; + it_tab[1][i] = upr(w,1); + it_tab[2][i] = upr(w,2); + it_tab[3][i] = upr(w,3); +#endif +#if defined(ONE_IM_TABLE) + im_tab[b] = w; +#elif defined(FOUR_IM_TABLES) + im_tab[0][b] = w; + im_tab[1][b] = upr(w,1); + im_tab[2][b] = upr(w,2); + im_tab[3][b] = upr(w,3); +#endif + + } +} + +#endif + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((r-c)&3) + +#if defined(FOUR_LR_TABLES) +#define ls_box(x,c) four_tables(x,fl_tab,vf1,rf2,c) +#elif defined(ONE_LR_TABLE) +#define ls_box(x,c) one_table(x,upr,fl_tab,vf1,rf2,c) +#else +#define ls_box(x,c) no_table(x,s_box,vf1,rf2,c) +#endif + +#if defined(FOUR_IM_TABLES) +#define inv_mcol(x) four_tables(x,im_tab,vf1,rf1,0) +#elif defined(ONE_IM_TABLE) +#define inv_mcol(x) one_table(x,upr,im_tab,vf1,rf1,0) +#else +#define inv_mcol(x) \ + (f9 = (x),f2 = FFmulX(f9), f4 = FFmulX(f2), f8 = FFmulX(f4), f9 ^= f8, \ + f2 ^= f4 ^ f8 ^ upr(f2 ^ f9,3) ^ upr(f4 ^ f9,2) ^ upr(f9,1)) +#endif + +#define nc (this->aes_Ncol) + +// Initialise the key schedule from the user supplied key. The key +// length is now specified in bytes - 16, 24 or 32 as appropriate. +// This corresponds to bit lengths of 128, 192 and 256 bits, and +// to Nk values of 4, 6 and 8 respectively. + +#define mx(t,f) (*t++ = inv_mcol(*f),f++) +#define cp(t,f) *t++ = *f++ + +#if AES_BLOCK_SIZE == 16 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s) +#elif AES_BLOCK_SIZE == 24 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s) +#elif AES_BLOCK_SIZE == 32 +#define cpy(d,s) cp(d,s); cp(d,s); cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s); cp(d,s); cp(d,s) +#define mix(d,s) mx(d,s); mx(d,s); mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s); mx(d,s); mx(d,s) +#else + +#define cpy(d,s) \ +switch(nc) \ +{ case 8: cp(d,s); cp(d,s); \ + case 6: cp(d,s); cp(d,s); \ + case 4: cp(d,s); cp(d,s); \ + cp(d,s); cp(d,s); \ +} + +#define mix(d,s) \ +switch(nc) \ +{ case 8: mx(d,s); mx(d,s); \ + case 6: mx(d,s); mx(d,s); \ + case 4: mx(d,s); mx(d,s); \ + mx(d,s); mx(d,s); \ +} + +#endif + +// y = output word, x = input word, r = row, c = column +// for r = 0, 1, 2 and 3 = column accessed for row r + +#if defined(ARRAYS) +#define s(x,c) x[c] +#else +#define s(x,c) x##c +#endif + +// I am grateful to Frank Yellin for the following constructions +// which, given the column (c) of the output state variable that +// is being computed, return the input state variables which are +// needed for each row (r) of the state + +// For the fixed block size options, compilers reduce these two +// expressions to fixed variable references. For variable block +// size code conditional clauses will sometimes be returned + +#define unused 77 // Sunset Strip + +#define fwd_var(x,r,c) \ + ( r==0 ? \ + ( c==0 ? s(x,0) \ + : c==1 ? s(x,1) \ + : c==2 ? s(x,2) \ + : c==3 ? s(x,3) \ + : c==4 ? s(x,4) \ + : c==5 ? s(x,5) \ + : c==6 ? s(x,6) \ + : s(x,7)) \ + : r==1 ? \ + ( c==0 ? s(x,1) \ + : c==1 ? s(x,2) \ + : c==2 ? s(x,3) \ + : c==3 ? nc==4 ? s(x,0) : s(x,4) \ + : c==4 ? s(x,5) \ + : c==5 ? nc==8 ? s(x,6) : s(x,0) \ + : c==6 ? s(x,7) \ + : s(x,0)) \ + : r==2 ? \ + ( c==0 ? nc==8 ? s(x,3) : s(x,2) \ + : c==1 ? nc==8 ? s(x,4) : s(x,3) \ + : c==2 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ + : c==3 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ + : c==4 ? nc==8 ? s(x,7) : s(x,0) \ + : c==5 ? nc==8 ? s(x,0) : s(x,1) \ + : c==6 ? s(x,1) \ + : s(x,2)) \ + : \ + ( c==0 ? nc==8 ? s(x,4) : s(x,3) \ + : c==1 ? nc==4 ? s(x,0) : nc==8 ? s(x,5) : s(x,4) \ + : c==2 ? nc==4 ? s(x,1) : nc==8 ? s(x,6) : s(x,5) \ + : c==3 ? nc==4 ? s(x,2) : nc==8 ? s(x,7) : s(x,0) \ + : c==4 ? nc==8 ? s(x,0) : s(x,1) \ + : c==5 ? nc==8 ? s(x,1) : s(x,2) \ + : c==6 ? s(x,2) \ + : s(x,3))) + +#define inv_var(x,r,c) \ + ( r==0 ? \ + ( c==0 ? s(x,0) \ + : c==1 ? s(x,1) \ + : c==2 ? s(x,2) \ + : c==3 ? s(x,3) \ + : c==4 ? s(x,4) \ + : c==5 ? s(x,5) \ + : c==6 ? s(x,6) \ + : s(x,7)) \ + : r==1 ? \ + ( c==0 ? nc==4 ? s(x,3) : nc==8 ? s(x,7) : s(x,5) \ + : c==1 ? s(x,0) \ + : c==2 ? s(x,1) \ + : c==3 ? s(x,2) \ + : c==4 ? s(x,3) \ + : c==5 ? s(x,4) \ + : c==6 ? s(x,5) \ + : s(x,6)) \ + : r==2 ? \ + ( c==0 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ + : c==1 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ + : c==2 ? nc==8 ? s(x,7) : s(x,0) \ + : c==3 ? nc==8 ? s(x,0) : s(x,1) \ + : c==4 ? nc==8 ? s(x,1) : s(x,2) \ + : c==5 ? nc==8 ? s(x,2) : s(x,3) \ + : c==6 ? s(x,3) \ + : s(x,4)) \ + : \ + ( c==0 ? nc==4 ? s(x,1) : nc==8 ? s(x,4) : s(x,3) \ + : c==1 ? nc==4 ? s(x,2) : nc==8 ? s(x,5) : s(x,4) \ + : c==2 ? nc==4 ? s(x,3) : nc==8 ? s(x,6) : s(x,5) \ + : c==3 ? nc==8 ? s(x,7) : s(x,0) \ + : c==4 ? nc==8 ? s(x,0) : s(x,1) \ + : c==5 ? nc==8 ? s(x,1) : s(x,2) \ + : c==6 ? s(x,2) \ + : s(x,3))) + +#define si(y,x,k,c) s(y,c) = const_word_in(x + 4 * c) ^ k[c] +#define so(y,x,c) word_out(y + 4 * c, s(x,c)) + +#if defined(FOUR_TABLES) +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,ft_tab,fwd_var,rf1,c) +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,it_tab,inv_var,rf1,c) +#elif defined(ONE_TABLE) +#define fwd_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,ft_tab,fwd_var,rf1,c) +#define inv_rnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,upr,it_tab,inv_var,rf1,c) +#else +#define fwd_rnd(y,x,k,c) s(y,c) = fwd_mcol(no_table(x,s_box,fwd_var,rf1,c)) ^ (k)[c] +#define inv_rnd(y,x,k,c) s(y,c) = inv_mcol(no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c]) +#endif + +#if defined(FOUR_LR_TABLES) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,fl_tab,fwd_var,rf1,c) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ four_tables(x,il_tab,inv_var,rf1,c) +#elif defined(ONE_LR_TABLE) +#define fwd_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,fl_tab,fwd_var,rf1,c) +#define inv_lrnd(y,x,k,c) s(y,c)= (k)[c] ^ one_table(x,ups,il_tab,inv_var,rf1,c) +#else +#define fwd_lrnd(y,x,k,c) s(y,c) = no_table(x,s_box,fwd_var,rf1,c) ^ (k)[c] +#define inv_lrnd(y,x,k,c) s(y,c) = no_table(x,inv_s_box,inv_var,rf1,c) ^ (k)[c] +#endif + +#if AES_BLOCK_SIZE == 16 + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 +// the following defines prevent the compiler requiring the declaration +// of generated but unused variables in the fwd_var and inv_var macros +#define b04 unused +#define b05 unused +#define b06 unused +#define b07 unused +#define b14 unused +#define b15 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#elif AES_BLOCK_SIZE == 24 + +#if defined(ARRAYS) +#define locals(y,x) x[6],y[6] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5, \ + y##0,y##1,y##2,y##3,y##4,y##5 +#define b06 unused +#define b07 unused +#define b16 unused +#define b17 unused +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); \ + si(y,x,k,3); si(y,x,k,4); si(y,x,k,5) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); \ + so(y,x,3); so(y,x,4); so(y,x,5) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); \ + rm(y,x,k,3); rm(y,x,k,4); rm(y,x,k,5) +#else + +#if defined(ARRAYS) +#define locals(y,x) x[8],y[8] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,x##4,x##5,x##6,x##7, \ + y##0,y##1,y##2,y##3,y##4,y##5,y##6,y##7 +#endif +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); \ + s(y,4) = s(x,4); s(y,5) = s(x,5); \ + s(y,6) = s(x,6); s(y,7) = s(x,7); + +#if AES_BLOCK_SIZE == 32 + +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3); \ + si(y,x,k,4); si(y,x,k,5); si(y,x,k,6); si(y,x,k,7) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3); \ + so(y,x,4); so(y,x,5); so(y,x,6); so(y,x,7) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3); \ + rm(y,x,k,4); rm(y,x,k,5); rm(y,x,k,6); rm(y,x,k,7) +#else + +#define state_in(y,x,k) \ +switch(nc) \ +{ case 8: si(y,x,k,7); si(y,x,k,6); \ + case 6: si(y,x,k,5); si(y,x,k,4); \ + case 4: si(y,x,k,3); si(y,x,k,2); \ + si(y,x,k,1); si(y,x,k,0); \ +} + +#define state_out(y,x) \ +switch(nc) \ +{ case 8: so(y,x,7); so(y,x,6); \ + case 6: so(y,x,5); so(y,x,4); \ + case 4: so(y,x,3); so(y,x,2); \ + so(y,x,1); so(y,x,0); \ +} + +#if defined(FAST_VARIABLE) + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ + break; \ +} +#else + +#define round(rm,y,x,k) \ +switch(nc) \ +{ case 8: rm(y,x,k,7); rm(y,x,k,6); \ + case 6: rm(y,x,k,5); rm(y,x,k,4); \ + case 4: rm(y,x,k,3); rm(y,x,k,2); \ + rm(y,x,k,1); rm(y,x,k,0); \ +} + +#endif + +#endif +#endif + +/** + * Implementation of private_aes_cbc_crypter_t.encrypt_block. + */ +static void encrypt_block(const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) +{ u_int32_t locals(b0, b1); + const u_int32_t *kp = this->aes_e_key; + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) + u_int32_t f2; +#endif + + state_in(b0, in_blk, kp); kp += nc; + +#if defined(UNROLL) + + switch(this->aes_Nrnd) + { + case 14: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 12: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 10: round(fwd_rnd, b1, b0, kp ); + round(fwd_rnd, b0, b1, kp + nc); + round(fwd_rnd, b1, b0, kp + 2 * nc); + round(fwd_rnd, b0, b1, kp + 3 * nc); + round(fwd_rnd, b1, b0, kp + 4 * nc); + round(fwd_rnd, b0, b1, kp + 5 * nc); + round(fwd_rnd, b1, b0, kp + 6 * nc); + round(fwd_rnd, b0, b1, kp + 7 * nc); + round(fwd_rnd, b1, b0, kp + 8 * nc); + round(fwd_lrnd, b0, b1, kp + 9 * nc); + } + +#elif defined(PARTIAL_UNROLL) + { u_int32_t rnd; + + for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) + { + round(fwd_rnd, b1, b0, kp); + round(fwd_rnd, b0, b1, kp + nc); kp += 2 * nc; + } + + round(fwd_rnd, b1, b0, kp); + round(fwd_lrnd, b0, b1, kp + nc); + } +#else + { u_int32_t rnd; + + for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) + { + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); kp += nc; + } + + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +} + +/** + * Implementation of private_aes_cbc_crypter_t.decrypt_block. + */ +static void decrypt_block(const private_aes_cbc_crypter_t *this, const unsigned char in_blk[], unsigned char out_blk[]) +{ u_int32_t locals(b0, b1); + const u_int32_t *kp = this->aes_d_key; + +#if !defined(ONE_TABLE) && !defined(FOUR_TABLES) + u_int32_t f2, f4, f8, f9; +#endif + + state_in(b0, in_blk, kp); kp += nc; + +#if defined(UNROLL) + + switch(this->aes_Nrnd) + { + case 14: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 12: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc ); kp += 2 * nc; + case 10: round(inv_rnd, b1, b0, kp ); + round(inv_rnd, b0, b1, kp + nc); + round(inv_rnd, b1, b0, kp + 2 * nc); + round(inv_rnd, b0, b1, kp + 3 * nc); + round(inv_rnd, b1, b0, kp + 4 * nc); + round(inv_rnd, b0, b1, kp + 5 * nc); + round(inv_rnd, b1, b0, kp + 6 * nc); + round(inv_rnd, b0, b1, kp + 7 * nc); + round(inv_rnd, b1, b0, kp + 8 * nc); + round(inv_lrnd, b0, b1, kp + 9 * nc); + } + +#elif defined(PARTIAL_UNROLL) + { u_int32_t rnd; + + for(rnd = 0; rnd < (this->aes_Nrnd >> 1) - 1; ++rnd) + { + round(inv_rnd, b1, b0, kp); + round(inv_rnd, b0, b1, kp + nc); kp += 2 * nc; + } + + round(inv_rnd, b1, b0, kp); + round(inv_lrnd, b0, b1, kp + nc); + } +#else + { u_int32_t rnd; + + for(rnd = 0; rnd < this->aes_Nrnd - 1; ++rnd) + { + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); kp += nc; + } + + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out_blk, b0); +} + +/** + * Implementation of crypter_t.decrypt. + */ +static status_t decrypt (private_aes_cbc_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) +{ + int ret, pos; + const u_int32_t *iv_i; + u_int8_t *in, *out; + + ret = data.len; + if (((data.len) % 16) != 0) + { + /* data length must be padded to a multiple of blocksize */ + return INVALID_ARG; + } + + decrypted->ptr = malloc(data.len); + if (decrypted->ptr == NULL) + { + return OUT_OF_RES; + } + decrypted->len = data.len; + + in = data.ptr; + out = decrypted->ptr; + + pos=data.len-16; + in+=pos; + out+=pos; + while(pos>=0) { + this->decrypt_block(this,in,out); + if (pos==0) + iv_i=(const u_int32_t*) (iv.ptr); + else + iv_i=(const u_int32_t*) (in-16); + *((u_int32_t *)(&out[ 0])) ^= iv_i[0]; + *((u_int32_t *)(&out[ 4])) ^= iv_i[1]; + *((u_int32_t *)(&out[ 8])) ^= iv_i[2]; + *((u_int32_t *)(&out[12])) ^= iv_i[3]; + in-=16; + out-=16; + pos-=16; + } + + return SUCCESS; +} + + +/** + * Implementation of crypter_t.decrypt. + */ +static status_t encrypt (private_aes_cbc_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) +{ + int ret, pos; + const u_int32_t *iv_i; + u_int8_t *in, *out; + + ret = data.len; + if (((data.len) % 16) != 0) + { + /* data length must be padded to a multiple of blocksize */ + return INVALID_ARG; + } + + encrypted->ptr = malloc(data.len); + if (encrypted->ptr == NULL) + { + return OUT_OF_RES; + } + encrypted->len = data.len; + + in = data.ptr; + out = encrypted->ptr; + + pos=0; + while(pos<data.len) + { + if (pos==0) + iv_i=(const u_int32_t*) iv.ptr; + else + iv_i=(const u_int32_t*) (out-16); + *((u_int32_t *)(&out[ 0])) = iv_i[0]^*((const u_int32_t *)(&in[ 0])); + *((u_int32_t *)(&out[ 4])) = iv_i[1]^*((const u_int32_t *)(&in[ 4])); + *((u_int32_t *)(&out[ 8])) = iv_i[2]^*((const u_int32_t *)(&in[ 8])); + *((u_int32_t *)(&out[12])) = iv_i[3]^*((const u_int32_t *)(&in[12])); + this->encrypt_block(this,out,out); + in+=16; + out+=16; + pos+=16; + } + return SUCCESS; +} + +/** + * Implementation of crypter_t.get_block_size. + */ +static size_t get_block_size (private_aes_cbc_crypter_t *this) +{ + return AES_BLOCK_SIZE; +} + +/** + * Implementation of crypter_t.get_key_size. + */ +static size_t get_key_size (private_aes_cbc_crypter_t *this) +{ + return this->key_size; +} + +/** + * Implementation of crypter_t.set_key. + */ +static status_t set_key (private_aes_cbc_crypter_t *this, chunk_t key) +{ + u_int32_t *kf, *kt, rci, f = 0; + u_int8_t *in_key = key.ptr; + + if (key.len != this->key_size) + { + return INVALID_ARG; + } + + this->aes_Nrnd = (this->aes_Nkey > (this->aes_Ncol) ? this->aes_Nkey : (this->aes_Ncol)) + 6; + + this->aes_e_key[0] = const_word_in(in_key ); + this->aes_e_key[1] = const_word_in(in_key + 4); + this->aes_e_key[2] = const_word_in(in_key + 8); + this->aes_e_key[3] = const_word_in(in_key + 12); + + kf = this->aes_e_key; + kt = kf + nc * (this->aes_Nrnd + 1) - this->aes_Nkey; + rci = 0; + + switch(this->aes_Nkey) + { + case 4: do + { kf[4] = kf[0] ^ ls_box(kf[3],3) ^ rcon_tab[rci++]; + kf[5] = kf[1] ^ kf[4]; + kf[6] = kf[2] ^ kf[5]; + kf[7] = kf[3] ^ kf[6]; + kf += 4; + } + while(kf < kt); + break; + + case 6: this->aes_e_key[4] = const_word_in(in_key + 16); + this->aes_e_key[5] = const_word_in(in_key + 20); + do + { kf[ 6] = kf[0] ^ ls_box(kf[5],3) ^ rcon_tab[rci++]; + kf[ 7] = kf[1] ^ kf[ 6]; + kf[ 8] = kf[2] ^ kf[ 7]; + kf[ 9] = kf[3] ^ kf[ 8]; + kf[10] = kf[4] ^ kf[ 9]; + kf[11] = kf[5] ^ kf[10]; + kf += 6; + } + while(kf < kt); + break; + + case 8: this->aes_e_key[4] = const_word_in(in_key + 16); + this->aes_e_key[5] = const_word_in(in_key + 20); + this->aes_e_key[6] = const_word_in(in_key + 24); + this->aes_e_key[7] = const_word_in(in_key + 28); + do + { kf[ 8] = kf[0] ^ ls_box(kf[7],3) ^ rcon_tab[rci++]; + kf[ 9] = kf[1] ^ kf[ 8]; + kf[10] = kf[2] ^ kf[ 9]; + kf[11] = kf[3] ^ kf[10]; + kf[12] = kf[4] ^ ls_box(kf[11],0); + kf[13] = kf[5] ^ kf[12]; + kf[14] = kf[6] ^ kf[13]; + kf[15] = kf[7] ^ kf[14]; + kf += 8; + } + while (kf < kt); + break; + } + + if(!f) + { + u_int32_t i; + + kt = this->aes_d_key + nc * this->aes_Nrnd; + kf = this->aes_e_key; + + cpy(kt, kf); kt -= 2 * nc; + + for(i = 1; i < this->aes_Nrnd; ++i) + { +#if defined(ONE_TABLE) || defined(FOUR_TABLES) +#if !defined(ONE_IM_TABLE) && !defined(FOUR_IM_TABLES) + u_int32_t f2, f4, f8, f9; +#endif + mix(kt, kf); +#else + cpy(kt, kf); +#endif + kt -= 2 * nc; + } + cpy(kt, kf); + } + + return SUCCESS; +} + +/** + * Implementation of crypter_t.destroy and aes_cbc_crypter_t.destroy. + */ +static void destroy (private_aes_cbc_crypter_t *this) +{ + free(this); +} + +/* + * Described in header + */ +aes_cbc_crypter_t *aes_cbc_crypter_create(size_t key_size) +{ + private_aes_cbc_crypter_t *this = malloc_thing(private_aes_cbc_crypter_t); + + #if !defined(FIXED_TABLES) + if(!tab_gen) { gen_tabs(); tab_gen = 1; } + #endif + + this->key_size = key_size; + switch(key_size) { + case 32: /* bytes */ + this->aes_Ncol = 8; + this->aes_Nkey = 8; + break; + case 24: /* bytes */ + this->aes_Ncol = 6; + this->aes_Nkey = 6; + break; + case 16: /* bytes */ + this->aes_Ncol = 4; + this->aes_Nkey = 4; + break; + default: + free(this); + return NULL; + } + + /* functions of crypter_t interface */ + this->public.crypter_interface.encrypt = (status_t (*) (crypter_t *, chunk_t,chunk_t, chunk_t *)) encrypt; + this->public.crypter_interface.decrypt = (status_t (*) (crypter_t *, chunk_t , chunk_t, chunk_t *)) decrypt; + this->public.crypter_interface.get_block_size = (size_t (*) (crypter_t *)) get_block_size; + this->public.crypter_interface.get_key_size = (size_t (*) (crypter_t *)) get_key_size; + this->public.crypter_interface.set_key = (status_t (*) (crypter_t *,chunk_t)) set_key; + this->public.crypter_interface.destroy = (void (*) (crypter_t *)) destroy; + + /* private functions */ + this->decrypt_block = decrypt_block; + this->encrypt_block = encrypt_block; + + return &(this->public); +} diff --git a/src/charon/lib/crypto/crypters/aes_cbc_crypter.h b/src/charon/lib/crypto/crypters/aes_cbc_crypter.h new file mode 100644 index 000000000..d7a3c0f5b --- /dev/null +++ b/src/charon/lib/crypto/crypters/aes_cbc_crypter.h @@ -0,0 +1,61 @@ +/** + * @file aes_cbc_crypter.h + * + * @brief Interface of aes_cbc_crypter_t + * + */ + +/* + * Copyright (C) 2001 Dr B. R. Gladman <brg@gladman.uk.net> + * 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. + */ + +#ifndef AES_CBC_CRYPTER_H_ +#define AES_CBC_CRYPTER_H_ + +#include <crypto/crypters/crypter.h> + + +typedef struct aes_cbc_crypter_t aes_cbc_crypter_t; + +/** + * @brief Class implementing the AES symmetric encryption algorithm. + * + * @b Constructors: + * - aes_cbc_crypter_create() + * + * @ingroup crypters + */ +struct aes_cbc_crypter_t { + + /** + * The crypter_t interface. + */ + crypter_t crypter_interface; +}; + +/** + * @brief Constructor to create aes_cbc_crypter_t objects. + * + * Supported key sizes are: 16, 24 or 32. + * + * @param key_size key size in bytes + * @return + * - aes_cbc_crypter_t object + * - NULL if key size not supported + */ +aes_cbc_crypter_t *aes_cbc_crypter_create(size_t key_size); + + +#endif /* AES_CBC_CRYPTER_H_ */ diff --git a/src/charon/lib/crypto/crypters/crypter.c b/src/charon/lib/crypto/crypters/crypter.c new file mode 100644 index 000000000..827d10228 --- /dev/null +++ b/src/charon/lib/crypto/crypters/crypter.c @@ -0,0 +1,63 @@ +/** + * @file crypter.c + * + * @brief Generic constructor for crypter_t. + * + */ + +/* + * 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 "crypter.h" + +#include <crypto/crypters/aes_cbc_crypter.h> + + +/** + * String mappings for encryption_algorithm_t. + */ +mapping_t encryption_algorithm_m[] = { +{ENCR_UNDEFINED, "ENCR_UNDEFINED"}, +{ENCR_DES_IV64, "ENCR_DES_IV64"}, +{ENCR_DES, "ENCR_DES"}, +{ENCR_3DES, "ENCR_3DES"}, +{ENCR_RC5, "ENCR_RC5"}, +{ENCR_IDEA, "ENCR_IDEA"}, +{ENCR_CAST, "ENCR_CAST"}, +{ENCR_BLOWFISH, "ENCR_BLOWFISH"}, +{ENCR_3IDEA, "ENCR_3IDEA"}, +{ENCR_DES_IV32, "ENCR_DES_IV32"}, +{ENCR_NULL, "ENCR_NULL"}, +{ENCR_AES_CBC, "ENCR_AES_CBC"}, +{ENCR_AES_CTR, "ENCR_AES_CTR"}, +{MAPPING_END, NULL} +}; + +/* + * Described in header. + */ +crypter_t *crypter_create(encryption_algorithm_t encryption_algorithm, size_t key_size) +{ + switch (encryption_algorithm) + { + case ENCR_AES_CBC: + { + return (crypter_t*)aes_cbc_crypter_create(key_size); + } + default: + return NULL; + } +} diff --git a/src/charon/lib/crypto/crypters/crypter.h b/src/charon/lib/crypto/crypters/crypter.h new file mode 100644 index 000000000..9c219f5cc --- /dev/null +++ b/src/charon/lib/crypto/crypters/crypter.h @@ -0,0 +1,153 @@ +/** + * @file crypter.h + * + * @brief Interface crypter_t + * + */ + +/* + * 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. + */ + +#ifndef CRYPTER_H_ +#define CRYPTER_H_ + +#include <types.h> + +typedef enum encryption_algorithm_t encryption_algorithm_t; + +/** + * @brief Encryption algorithm, as in IKEv2 RFC 3.3.2. + * + * Currently only the following algorithms are implemented and therefore supported: + * - ENCR_AES_CBC + * + * @todo Implement more enryption algorithms, such as 3DES + * + * @ingroup crypters + */ +enum encryption_algorithm_t { + ENCR_UNDEFINED = 1024, + ENCR_DES_IV64 = 1, + ENCR_DES = 2, + ENCR_3DES = 3, + ENCR_RC5 = 4, + ENCR_IDEA = 5, + ENCR_CAST = 6, + ENCR_BLOWFISH = 7, + ENCR_3IDEA = 8, + ENCR_DES_IV32 = 9, + ENCR_NULL = 11, + /** + * Implemented in class aes_cbc_crypter_t. + */ + ENCR_AES_CBC = 12, + ENCR_AES_CTR = 13 +}; + +/** + * String mappings for encryption_algorithm_t. + */ +extern mapping_t encryption_algorithm_m[]; + + +typedef struct crypter_t crypter_t; + +/** + * @brief Generic interface for symmetric encryption algorithms. + * + * @b Constructors: + * - crypter_create() + * + * @ingroup crypters + */ +struct crypter_t { + /** + * @brief Encrypt a chunk of data and allocate space for the encrypted value. + * + * @param this calling object + * @param data data to encrypt + * @param iv initializing vector + * @param[out] encrypted pointer where the encrypted bytes will be written + * @return + * - SUCCESS + * - INVALID_ARG if data size not a multiple of block size + */ + status_t (*encrypt) (crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted); + + /** + * @brief Decrypt a chunk of data and allocate space for the decrypted value. + * + * @param this calling object + * @param data data to decrypt + * @param iv initializing vector + * @param[out] encrypted pointer where the decrypted bytes will be written + * @return + * - SUCCESS + * - INVALID_ARG if data size not a multiple of block size + */ + status_t (*decrypt) (crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted); + + /** + * @brief Get the block size of this crypter_t object. + * + * @param this calling object + * @return block size in bytes + */ + size_t (*get_block_size) (crypter_t *this); + + /** + * @brief Get the key size of this crypter_t object. + * + * @param this calling object + * @return key size in bytes + */ + size_t (*get_key_size) (crypter_t *this); + + /** + * @brief Set the key for this crypter_t object. + * + * @param this calling object + * @param key key to set + * @return + * - SUCCESS + * - INVALID_ARG if key length invalid + */ + status_t (*set_key) (crypter_t *this, chunk_t key); + + /** + * @brief Destroys a crypter_t object. + * + * @param this calling object + */ + void (*destroy) (crypter_t *this); +}; + +/** + * @brief Generic constructor for crypter_t objects. + * + * Currently only the following algorithms are implemented and therefore supported: + * - ENCR_AES_CBC + * + * The key_size is ignored for algorithms with fixed key size. + * + * @param encryption_algorithm Algorithm to use for crypter + * @param key_size size of the key in bytes + * @return + * - crypter_t object + * - NULL if encryption algorithm/key_size is not supported + */ +crypter_t *crypter_create(encryption_algorithm_t encryption_algorithm, size_t key_size); + +#endif /*CRYPTER_H_*/ diff --git a/src/charon/lib/crypto/diffie_hellman.c b/src/charon/lib/crypto/diffie_hellman.c new file mode 100644 index 000000000..e458fb80f --- /dev/null +++ b/src/charon/lib/crypto/diffie_hellman.c @@ -0,0 +1,615 @@ +/** + * @file diffie_hellman.c + * + * @brief Implementation of diffie_hellman_t. + * + */ + +/* + * Copyright (C) 1998-2002 D. Hugh Redelmeier. + * Copyright (C) 1999, 2000, 2001 Henry Spencer. + * 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 <gmp.h> +#include <stdio.h> + +#include "diffie_hellman.h" + +#include <daemon.h> +#include <utils/randomizer.h> + + +/** + * String mappings for diffie_hellman_group_t. + */ +mapping_t diffie_hellman_group_m[] = { + {MODP_UNDEFINED, "MODP_UNDEFINED"}, + {MODP_768_BIT, "MODP_768_BIT"}, + {MODP_1024_BIT, "MODP_1024_BIT"}, + {MODP_1536_BIT, "MODP_1536_BIT"}, + {MODP_2048_BIT, "MODP_2048_BIT"}, + {MODP_3072_BIT, "MODP_3072_BIT"}, + {MODP_4096_BIT, "MODP_4096_BIT"}, + {MODP_6144_BIT, "MODP_6144_BIT"}, + {MODP_8192_BIT, "MODP_8192_BIT"}, + {MAPPING_END, NULL} +}; + + +/** + * Modulus of Group 1 (MODP_768_BIT). + */ +static u_int8_t group1_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x3A,0x36,0x20,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 2 (MODP_1024_BIT). + */ +static u_int8_t group2_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 5 (MODP_1536_BIT). + */ +static u_int8_t group5_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; +/** + * Modulus of Group 14 (MODP_2048_BIT). + */ +static u_int8_t group14_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 15 (MODP_3072_BIT). + */ +static u_int8_t group15_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 16 (MODP_4096_BIT). + */ +static u_int8_t group16_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF, + 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F, + 0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 17 (MODP_6144_BIT). + */ +static u_int8_t group17_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF, + 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F, + 0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, + 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, + 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, + 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, + 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, + 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, + 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, + 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, + 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, + 0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C, + 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68, + 0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6, + 0xE6,0x94,0xF9,0x1E,0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/** + * Modulus of Group 18 (MODP_8192_BIT). + */ +static u_int8_t group18_modulus[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, + 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, + 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, + 0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, + 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6, + 0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05, + 0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, + 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB, + 0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04, + 0xF1,0x74,0x6C,0x08,0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B, + 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F, + 0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10, + 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,0x33, + 0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A, + 0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7, + 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,0x4A,0x25,0x61,0x9D, + 0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64, + 0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C, + 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2, + 0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E, + 0x4B,0x82,0xD1,0x20,0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7, + 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,0x6A,0xF4,0xE2,0x3C, + 0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8, + 0xDB,0xBB,0xC2,0xDB,0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6, + 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,0xA0,0x90,0xC3,0xA2, + 0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF, + 0xB8,0x1B,0xDD,0x76,0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9, + 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,0x90,0xA6,0xC0,0x8F, + 0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26, + 0xC1,0xD4,0xDC,0xB2,0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD, + 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,0x41,0x30,0x01,0xAE, + 0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18, + 0xDA,0x3E,0xDB,0xEB,0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B, + 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,0x2B,0xD7,0xAF,0x42, + 0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC, + 0xF0,0x32,0xEA,0x15,0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6, + 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,0x90,0x0B,0x1C,0x9E, + 0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE, + 0x0F,0x1D,0x45,0xB7,0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA, + 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,0x0F,0x80,0x37,0xE0, + 0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76, + 0xF5,0x50,0xAA,0x3D,0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C, + 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,0x6E,0x3C,0x04,0x68, + 0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6, + 0xE6,0x94,0xF9,0x1E,0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4, + 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,0x73,0xB9,0x31,0xBA, + 0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED, + 0x25,0x76,0xF6,0x93,0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68, + 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,0xE3,0x9D,0x65,0x2D, + 0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07, + 0x13,0xEB,0x57,0xA8,0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B, + 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,0xA2,0xC0,0x87,0xE8, + 0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6, + 0x6D,0x2A,0x13,0xF8,0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36, + 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,0x08,0x46,0x85,0x1D, + 0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73, + 0xFA,0xF3,0x6B,0xC3,0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92, + 0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,0xD5,0xEE,0x38,0x2B, + 0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA, + 0x9E,0x30,0x50,0xE2,0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71, + 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +}; + +typedef struct modulus_info_entry_t modulus_info_entry_t; + +/** + * Entry of the modulus list. + */ +struct modulus_info_entry_t { + /** + * Group number as it is defined in file transform_substructure.h. + */ + diffie_hellman_group_t group; + + /** + * Pointer to first byte of modulus (network order). + */ + u_int8_t *modulus; + + /* + * Length of modulus in bytes. + */ + size_t modulus_length; + + /* + * Generator value. + */ + u_int16_t generator; +}; + + +/** + * All supported modulus values. + */ +static modulus_info_entry_t modulus_info_entries[] = { + {MODP_768_BIT,group1_modulus,sizeof(group1_modulus),2}, + {MODP_1024_BIT,group2_modulus,sizeof(group2_modulus),2}, + {MODP_1536_BIT,group5_modulus,sizeof(group5_modulus),2}, + {MODP_2048_BIT,group14_modulus,sizeof(group14_modulus),2}, + {MODP_3072_BIT,group15_modulus,sizeof(group15_modulus),2}, + {MODP_4096_BIT,group16_modulus,sizeof(group16_modulus),2}, + {MODP_6144_BIT,group17_modulus,sizeof(group17_modulus),2}, + {MODP_8192_BIT,group18_modulus,sizeof(group18_modulus),2}, +}; + +typedef struct private_diffie_hellman_t private_diffie_hellman_t; + +/** + * Private data of an diffie_hellman_t object. + * + */ +struct private_diffie_hellman_t { + /** + * Public diffie_hellman_t interface. + */ + diffie_hellman_t public; + + /** + * Diffie Hellman group number. + */ + u_int16_t dh_group_number; + + /** + * Modulus. + */ + mpz_t modulus; + + /** + * Modulus length. + */ + size_t modulus_length; + + /* + * Generator value. + */ + u_int16_t generator; + + /** + * My private value . + */ + mpz_t my_private_value; + + /** + * My public value. + */ + mpz_t my_public_value; + + /** + * Other public value. + */ + mpz_t other_public_value; + + /** + * Shared secret. + */ + mpz_t shared_secret; + + /** + * True if shared secret is computed and stored in my_public_value. + */ + bool shared_secret_is_computed; + + /** + * Sets the modulus for a specific diffie hellman group. + * + * @param this calling object + * @return + * SUCCESS if modulus could be found + * NOT_FOUND if modulus not supported + */ + status_t (*set_modulus) (private_diffie_hellman_t *this); + + /** + * Makes sure my public value is computed. + * + * @param this calling object + */ + void (*compute_public_value) (private_diffie_hellman_t *this); + + /** + * Computes shared secret (other public value must be available). + * + * @param this calling object + */ + void (*compute_shared_secret) (private_diffie_hellman_t *this); +}; + +/** + * Implementation of private_diffie_hellman_t.set_modulus. + */ +static status_t set_modulus(private_diffie_hellman_t *this) +{ + int i; + status_t status = NOT_FOUND; + + for (i = 0; i < (sizeof(modulus_info_entries) / sizeof(modulus_info_entry_t)); i++) + { + if (modulus_info_entries[i].group == this->dh_group_number) + { + chunk_t modulus_chunk; + modulus_chunk.ptr = modulus_info_entries[i].modulus; + modulus_chunk.len = modulus_info_entries[i].modulus_length; + mpz_import(this->modulus, modulus_chunk.len, 1, 1, 1, 0, modulus_chunk.ptr); + this->modulus_length = modulus_chunk.len; + this->generator = modulus_info_entries[i].generator; + status = SUCCESS; + break; + } + } + return status; +} + +/** + * Implementation of diffie_hellman_t.set_other_public_value. + */ +static void set_other_public_value(private_diffie_hellman_t *this,chunk_t public_value) +{ + mpz_import(this->other_public_value, public_value.len, 1, 1, 1, 0, public_value.ptr); + this->compute_shared_secret(this); +} + +/** + * Implementation of diffie_hellman_t.get_other_public_value. + */ +static status_t get_other_public_value(private_diffie_hellman_t *this,chunk_t *public_value) +{ + if (!this->shared_secret_is_computed) + { + return FAILED; + } + public_value->len = this->modulus_length; + public_value->ptr = mpz_export(NULL, NULL, 1, public_value->len, 1, 0, this->other_public_value); + return SUCCESS; +} + +/** + * Implementation of private_diffie_hellman_t.compute_shared_secret. + */ +static void compute_shared_secret (private_diffie_hellman_t *this) +{ + /* initialize my public value */ + mpz_init(this->shared_secret); + /* calculate my public value */ + mpz_powm(this->shared_secret,this->other_public_value,this->my_private_value,this->modulus); + + this->shared_secret_is_computed = TRUE; +} + +/** + * Implementation of private_diffie_hellman_t.compute_public_value. + */ +static void compute_public_value (private_diffie_hellman_t *this) +{ + mpz_t generator; + /* initialize generator and set it*/ + mpz_init_set_ui (generator,this->generator); + /* initialize my public value */ + mpz_init(this->my_public_value); + /* calculate my public value */ + mpz_powm(this->my_public_value,generator,this->my_private_value,this->modulus); + /* generator not used anymore */ + mpz_clear(generator); +} + +/** + * Implementation of diffie_hellman_t.get_my_public_value. + */ +static void get_my_public_value(private_diffie_hellman_t *this,chunk_t *public_value) +{ + public_value->len = this->modulus_length; + public_value->ptr = mpz_export(NULL, NULL, 1, public_value->len, 1, 0, this->my_public_value); +} + +/** + * Implementation of diffie_hellman_t.get_shared_secret. + */ +static status_t get_shared_secret(private_diffie_hellman_t *this,chunk_t *secret) +{ + if (!this->shared_secret_is_computed) + { + return FAILED; + } + secret->len = this->modulus_length; + secret->ptr = mpz_export(NULL, NULL, 1, secret->len, 1, 0, this->shared_secret); + return SUCCESS; +} + +/** + * Implementation of diffie_hellman_t.get_dh_group. + */ +static diffie_hellman_group_t get_dh_group(private_diffie_hellman_t *this) +{ + return this->dh_group_number; +} + +/** + * Implementation of diffie_hellman_t.destroy. + */ +static void destroy(private_diffie_hellman_t *this) +{ + mpz_clear(this->modulus); + mpz_clear(this->my_private_value); + mpz_clear(this->my_public_value); + mpz_clear(this->other_public_value); + + if (this->shared_secret_is_computed) + { + /* other public value gets initialized together with shared secret */ + mpz_clear(this->shared_secret); + } + free(this); +} + +/* + * Described in header. + */ +diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number) +{ + private_diffie_hellman_t *this = malloc_thing(private_diffie_hellman_t); + randomizer_t *randomizer; + chunk_t random_bytes; + + /* public functions */ + this->public.get_shared_secret = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_shared_secret; + this->public.set_other_public_value = (void (*)(diffie_hellman_t *, chunk_t )) set_other_public_value; + this->public.get_other_public_value = (status_t (*)(diffie_hellman_t *, chunk_t *)) get_other_public_value; + this->public.get_my_public_value = (void (*)(diffie_hellman_t *, chunk_t *)) get_my_public_value; + this->public.get_dh_group = (diffie_hellman_group_t (*)(diffie_hellman_t *)) get_dh_group; + this->public.destroy = (void (*)(diffie_hellman_t *)) destroy; + + /* private functions */ + this->set_modulus = set_modulus; + this->compute_public_value = compute_public_value; + this->compute_shared_secret = compute_shared_secret; + + /* private variables */ + this->dh_group_number = dh_group_number; + mpz_init(this->modulus); + mpz_init(this->other_public_value); + mpz_init(this->my_private_value); + + /* set this->modulus */ + if (this->set_modulus(this) != SUCCESS) + { + free(this); + return NULL; + } + randomizer = randomizer_create(); + if (randomizer == NULL) + { + free(this); + return NULL; + } + if (randomizer->allocate_pseudo_random_bytes(randomizer, this->modulus_length, &random_bytes) != SUCCESS) + { + randomizer->destroy(randomizer); + free(this); + return NULL; + } + + mpz_import(this->my_private_value, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); + chunk_free(&random_bytes); + + randomizer->destroy(randomizer); + + this->compute_public_value(this); + + this->shared_secret_is_computed = FALSE; + + return &(this->public); +} diff --git a/src/charon/lib/crypto/diffie_hellman.h b/src/charon/lib/crypto/diffie_hellman.h new file mode 100644 index 000000000..48a165557 --- /dev/null +++ b/src/charon/lib/crypto/diffie_hellman.h @@ -0,0 +1,149 @@ +/** + * @file diffie_hellman.h + * + * @brief Interface of diffie_hellman_t. + * + */ + +/* + * 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. + */ + +#ifndef DIFFIE_HELLMAN_H_ +#define DIFFIE_HELLMAN_H_ + +#include <types.h> + + +typedef enum diffie_hellman_group_t diffie_hellman_group_t; + +/** + * @brief Diffie-Hellman group. + * + * The modulus (or group) to use for a Diffie-Hellman calculation. + * + * See IKEv2 RFC 3.3.2 and RFC 3526. + * + * @ingroup transforms + */ +enum diffie_hellman_group_t { + MODP_UNDEFINED = 1024, + MODP_768_BIT = 1, + MODP_1024_BIT = 2, + MODP_1536_BIT = 5, + MODP_2048_BIT = 14, + MODP_3072_BIT = 15, + MODP_4096_BIT = 16, + MODP_6144_BIT = 17, + MODP_8192_BIT = 18 +}; + +/** + * String mappings for diffie_hellman_group_t. + */ +extern mapping_t diffie_hellman_group_m[]; + + +typedef struct diffie_hellman_t diffie_hellman_t; + +/** + * @brief Implementation of the widely used Diffie-Hellman algorithm. + * + * @b Constructors: + * - diffie_hellman_create() + * + * @ingroup transforms + */ +struct diffie_hellman_t { + + /** + * @brief Returns the shared secret of this diffie hellman exchange. + * + * @warning Space for returned secret is allocated and must be + * freed by the caller. + * + * @param this calling diffie_hellman_t object + * @param[out] secret shared secret will be written into this chunk + * @return + * - SUCCESS + * - FAILED if not both DH values are set + */ + status_t (*get_shared_secret) (diffie_hellman_t *this, chunk_t *secret); + + /** + * @brief Sets the public value of partner. + * + * chunk gets cloned and can be destroyed afterwards. + * + * @param this calling diffie_hellman_t object + * @param public_value public value of partner + */ + void (*set_other_public_value) (diffie_hellman_t *this, chunk_t public_value); + + /** + * @brief Gets the public value of partner. + * + * @warning Space for returned chunk is allocated and must be + * freed by the caller. + * + * @param this calling diffie_hellman_t object + * @param[out] public_value public value of partner is stored at this location + * @return + * - SUCCESS + * - FAILED if other public value not set + */ + status_t (*get_other_public_value) (diffie_hellman_t *this, chunk_t *public_value); + + /** + * @brief Gets the public value of caller + * + * @warning Space for returned chunk is allocated and must be + * freed by the caller. + * + * @param this calling diffie_hellman_t object + * @param[out] public_value public value of caller is stored at this location + */ + void (*get_my_public_value) (diffie_hellman_t *this, chunk_t *public_value); + + /** + * @brief Get the DH group used. + * + * @param this calling diffie_hellman_t object + * @return DH group set in construction + */ + diffie_hellman_group_t (*get_dh_group) (diffie_hellman_t *this); + + /** + * @brief Destroys an diffie_hellman_t object. + * + * @param this diffie_hellman_t object to destroy + */ + void (*destroy) (diffie_hellman_t *this); +}; + +/** + * @brief Creates a new diffie_hellman_t object. + * + * The first diffie hellman public value gets automatically created. + * + * @param dh_group_number Diffie Hellman group number to use + * @return + * - diffie_hellman_t object + * - NULL if dh group not supported + * + * @ingroup transforms + */ +diffie_hellman_t *diffie_hellman_create(diffie_hellman_group_t dh_group_number); + +#endif /*DIFFIE_HELLMAN_H_*/ diff --git a/src/charon/lib/crypto/hashers/Makefile.hashers b/src/charon/lib/crypto/hashers/Makefile.hashers new file mode 100644 index 000000000..e05d41af3 --- /dev/null +++ b/src/charon/lib/crypto/hashers/Makefile.hashers @@ -0,0 +1,27 @@ +# 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. +# + +HASHERS_DIR= $(CRYPTO_DIR)hashers/ + +LIB_OBJS+= $(BUILD_DIR)hasher.o +$(BUILD_DIR)hasher.o : $(HASHERS_DIR)hasher.c $(HASHERS_DIR)hasher.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)sha1_hasher.o +$(BUILD_DIR)sha1_hasher.o : $(HASHERS_DIR)sha1_hasher.c $(HASHERS_DIR)sha1_hasher.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)md5_hasher.o +$(BUILD_DIR)md5_hasher.o : $(HASHERS_DIR)md5_hasher.c $(HASHERS_DIR)md5_hasher.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/charon/lib/crypto/hashers/hasher.c b/src/charon/lib/crypto/hashers/hasher.c new file mode 100644 index 000000000..c15f41804 --- /dev/null +++ b/src/charon/lib/crypto/hashers/hasher.c @@ -0,0 +1,60 @@ +/** + * @file hasher.c + * + * @brief Generic constructor for hasher_t. + * + */ + +/* + * 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 "hasher.h" + +#include <crypto/hashers/sha1_hasher.h> +#include <crypto/hashers/md5_hasher.h> + +/** + * String mappings for hash_algorithm_t. + */ +mapping_t hash_algorithm_m[] = { + {HASH_MD2,"HASH_MD2"}, + {HASH_MD5,"HASH_MD5"}, + {HASH_SHA1,"HASH_SHA1"}, + {HASH_SHA256,"HASH_SHA256"}, + {HASH_SHA384,"HASH_SHA384"}, + {HASH_SHA512,"HASH_SHA512"}, + {MAPPING_END, NULL} +}; + +/* + * Described in header. + */ +hasher_t *hasher_create(hash_algorithm_t hash_algorithm) +{ + switch (hash_algorithm) + { + case HASH_SHA1: + { + return (hasher_t*)sha1_hasher_create(); + } + case HASH_MD5: + { + return (hasher_t*)md5_hasher_create(); + } + default: + return NULL; + } +} diff --git a/src/charon/lib/crypto/hashers/hasher.h b/src/charon/lib/crypto/hashers/hasher.h new file mode 100644 index 000000000..24683c01b --- /dev/null +++ b/src/charon/lib/crypto/hashers/hasher.h @@ -0,0 +1,147 @@ +/** + * @file hasher.h + * + * @brief Interface hasher_t. + * + */ + +/* + * 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. + */ + +#ifndef HASHER_H_ +#define HASHER_H_ + + +#include <types.h> + + +typedef enum hash_algorithm_t hash_algorithm_t; + +/** + * @brief Algorithms to use for hashing. + * + * Currently only the following algorithms are implemented and therefore supported: + * - HASH_MD5 + * - HASH_SHA1 + * + * @ingroup hashers + * + */ +enum hash_algorithm_t { + HASH_MD2, + /** + * Implemented in class md5_hasher_t. + */ + HASH_MD5, + /** + * Implemented in class sha1_hasher_t. + */ + HASH_SHA1, + HASH_SHA256, + HASH_SHA384, + HASH_SHA512, +}; + +/** + * String mappings for hash_algorithm_t. + */ +extern mapping_t hash_algorithm_m[]; + + +typedef struct hasher_t hasher_t; + +/** + * @brief Generic interface for all hash functions. + * + * @b Constructors: + * - hasher_create() + * - md5_hasher_create() + * - sha1_hasher_create() + * + * @see + * - md5_hasher_t + * - sha1_hasher_t + * + * @todo Implement more hash algorithms + * + * @ingroup hashers + */ +struct hasher_t { + /** + * @brief Hash data and write it in the buffer. + * + * If the parameter hash is NULL, no result is written back + * an more data can be appended to already hashed data. + * If not, the result is written back and the hasher is reseted. + * + * @warning: the hash output parameter must hold at least + * hash_t.get_block_size bytes. + * + * @param this calling object + * @param data data to hash + * @param[out] hash pointer where the hash will be written + */ + void (*get_hash) (hasher_t *this, chunk_t data, u_int8_t *hash); + + /** + * @brief Hash data and allocate space for the hash. + * + * If the parameter hash is NULL, no result is written back + * an more data can be appended to already hashed data. + * If not, the result is written back and the hasher is reseted. + * + * @param this calling object + * @param data chunk with data to hash + * @param[out] hash chunk which will hold allocated hash + */ + void (*allocate_hash) (hasher_t *this, chunk_t data, chunk_t *hash); + + /** + * @brief Get the size of the resulting hash. + * + * @param this calling object + * @return hash size in bytes + */ + size_t (*get_hash_size) (hasher_t *this); + + /** + * @brief Resets the hashers state, which allows + * computation of a completely new hash. + * + * @param this calling object + */ + void (*reset) (hasher_t *this); + + /** + * @brief Destroys a hasher object. + * + * @param this calling object + */ + void (*destroy) (hasher_t *this); +}; + +/** + * @brief Generic interface to create a hasher_t. + * + * @param hash_algorithm Algorithm to use for hashing + * @return + * - hasher_t object + * - NULL if algorithm not supported + * + * @ingroup hashers + */ +hasher_t *hasher_create(hash_algorithm_t hash_algorithm); + +#endif /*HASHER_H_*/ diff --git a/src/charon/lib/crypto/hashers/md5_hasher.c b/src/charon/lib/crypto/hashers/md5_hasher.c new file mode 100644 index 000000000..bd3ab0c62 --- /dev/null +++ b/src/charon/lib/crypto/hashers/md5_hasher.c @@ -0,0 +1,394 @@ +/** + * @file md5_hasher.c + * + * @brief Implementation of md5_hasher_t. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * Copyright (C) 1991-1992, RSA Data Security, Inc. Created 1991. + * All rights reserved. + * + * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. + * Ported to fulfill hasher_t interface. + * + * 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 <string.h> + +#include "md5_hasher.h" + +#include <definitions.h> + +#define BLOCK_SIZE_MD5 16 + + +/* Constants for MD5Transform routine. */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static u_int8_t PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * ugly macro stuff + */ +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + + +typedef struct private_md5_hasher_t private_md5_hasher_t; + +/** + * Private data structure with hasing context. + */ +struct private_md5_hasher_t { + /** + * Public interface for this hasher. + */ + md5_hasher_t public; + + /* + * State of the hasher. + */ + u_int32_t state[5]; + u_int32_t count[2]; + u_int8_t buffer[64]; +}; + + +#if BYTE_ORDER != LITTLE_ENDIAN + +/* Encodes input (u_int32_t) into output (u_int8_t). Assumes len is + * a multiple of 4. + */ +static void Encode (u_int8_t *output, u_int32_t *input, size_t *len) +{ + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (u_int8_t)(input[i] & 0xff); + output[j+1] = (u_int8_t)((input[i] >> 8) & 0xff); + output[j+2] = (u_int8_t)((input[i] >> 16) & 0xff); + output[j+3] = (u_int8_t)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (u_int8_t) into output (u_int32_t). Assumes len is + * a multiple of 4. + */ +static void Decode(u_int32_t *output, u_int8_t *input, size_t len) +{ + size_t i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[i] = ((u_int32_t)input[j]) | (((u_int32_t)input[j+1]) << 8) | + (((u_int32_t)input[j+2]) << 16) | (((u_int32_t)input[j+3]) << 24); + } +} + +#elif BYTE_ORDER == LITTLE_ENDIAN + #define Encode memcpy + #define Decode memcpy +#endif + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform(u_int32_t state[4], u_int8_t block[64]) +{ + u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} + +/* MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +static void MD5Update(private_md5_hasher_t *this, u_int8_t *input, size_t inputLen) +{ + u_int32_t i; + size_t index, partLen; + + /* Compute number of bytes mod 64 */ + index = (u_int8_t)((this->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((this->count[0] += (inputLen << 3)) < (inputLen << 3)) + { + this->count[1]++; + } + this->count[1] += (inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) + { + memcpy(&this->buffer[index], input, partLen); + MD5Transform (this->state, this->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + { + MD5Transform (this->state, &input[i]); + } + index = 0; + } + else + { + i = 0; + } + + /* Buffer remaining input */ + memcpy(&this->buffer[index], &input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ +static void MD5Final (private_md5_hasher_t *this, u_int8_t digest[16]) +{ + u_int8_t bits[8]; + size_t index, padLen; + + /* Save number of bits */ + Encode (bits, this->count, 8); + + /* Pad out to 56 mod 64. */ + index = (size_t)((this->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (this, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (this, bits, 8); + + if (digest != NULL) /* Bill Simpson's padding */ + { + /* store state in digest */ + Encode (digest, this->state, 16); + } +} + + + +/** + * Implementation of hasher_t.get_hash. + */ +static void get_hash(private_md5_hasher_t *this, chunk_t chunk, u_int8_t *buffer) +{ + MD5Update(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + MD5Final(this, buffer); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + + +/** + * Implementation of hasher_t.allocate_hash. + */ +static void allocate_hash(private_md5_hasher_t *this, chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + MD5Update(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + allocated_hash.ptr = malloc(BLOCK_SIZE_MD5); + allocated_hash.len = BLOCK_SIZE_MD5; + + MD5Final(this, allocated_hash.ptr); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.get_hash_size. + */ +static size_t get_hash_size(private_md5_hasher_t *this) +{ + return BLOCK_SIZE_MD5; +} + +/** + * Implementation of hasher_t.reset. + */ +static void reset(private_md5_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xefcdab89; + this->state[2] = 0x98badcfe; + this->state[3] = 0x10325476; + this->count[0] = 0; + this->count[1] = 0; +} + +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(private_md5_hasher_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +md5_hasher_t *md5_hasher_create() +{ + private_md5_hasher_t *this = malloc_thing(private_md5_hasher_t); + + this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; + this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; + this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; + this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; + + /* initialize */ + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + + return &(this->public); +} diff --git a/src/charon/lib/crypto/hashers/md5_hasher.h b/src/charon/lib/crypto/hashers/md5_hasher.h new file mode 100644 index 000000000..1e6d95d19 --- /dev/null +++ b/src/charon/lib/crypto/hashers/md5_hasher.h @@ -0,0 +1,60 @@ +/** + * @file md5_hasher.h + * + * @brief Interface for md5_hasher_t. + * + */ + +/* + * 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. + */ + +#ifndef MD5_HASHER_H_ +#define MD5_HASHER_H_ + +#include <crypto/hashers/hasher.h> + + +typedef struct md5_hasher_t md5_hasher_t; + +/** + * @brief Implementation of hasher_t interface using the + * MD5 algorithm. + * + * @b Constructors: + * - hasher_create() using HASH_MD5 as algorithm + * - md5_hasher_create() + * + * @see hasher_t + * + * @ingroup hashers + */ +struct md5_hasher_t { + + /** + * Generic hasher_t interface for this hasher. + */ + hasher_t hasher_interface; +}; + +/** + * @brief Creates a new md5_hasher_t. + * + * @return md5_hasher_t object + * + * @ingroup hashers + */ +md5_hasher_t *md5_hasher_create(); + +#endif /*MD5_HASHER_H_*/ diff --git a/src/charon/lib/crypto/hashers/sha1_hasher.c b/src/charon/lib/crypto/hashers/sha1_hasher.c new file mode 100644 index 000000000..2b82ef4ba --- /dev/null +++ b/src/charon/lib/crypto/hashers/sha1_hasher.c @@ -0,0 +1,269 @@ +/** + * @file sha1_hasher.c + * + * @brief Implementation of hasher_sha_t. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * Ported from Steve Reid's <steve@edmweb.com> implementation + * "SHA1 in C" found in strongSwan. + * + * 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 <string.h> + +#include "sha1_hasher.h" + +#include <definitions.h> + +#define BLOCK_SIZE_SHA1 20 + +/* + * ugly macro stuff + */ +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#if BYTE_ORDER == LITTLE_ENDIAN + #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN + #define blk0(i) block->l[i] +#else + #error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +typedef struct private_sha1_hasher_t private_sha1_hasher_t; + +/** + * Private data structure with hasing context. + */ +struct private_sha1_hasher_t { + /** + * Public interface for this hasher. + */ + sha1_hasher_t public; + + /* + * State of the hasher. + */ + u_int32_t state[5]; + u_int32_t count[2]; + u_int8_t buffer[64]; +}; + +/* + * Hash a single 512-bit block. This is the core of the algorithm. * + */ +static void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) +{ + u_int32_t a, b, c, d, e; + typedef union { + u_int8_t c[64]; + u_int32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + memcpy(block, buffer, 64); + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; + memset(block, '\0', sizeof(block)); +} + +/* + * Run your data through this. + */ +static void SHA1Update(private_sha1_hasher_t* this, u_int8_t *data, u_int32_t len) +{ + u_int32_t i; + u_int32_t j; + + j = this->count[0]; + if ((this->count[0] += len << 3) < j) + { + this->count[1]++; + } + this->count[1] += (len>>29); + j = (j >> 3) & 63; + if ((j + len) > 63) + { + memcpy(&this->buffer[j], data, (i = 64-j)); + SHA1Transform(this->state, this->buffer); + for ( ; i + 63 < len; i += 64) + { + SHA1Transform(this->state, &data[i]); + } + j = 0; + } + else + { + i = 0; + } + memcpy(&this->buffer[j], &data[i], len - i); +} + + +/* + * Add padding and return the message digest. + */ +static void SHA1Final(private_sha1_hasher_t *this, u_int8_t *digest) +{ + u_int32_t i; + u_int8_t finalcount[8]; + u_int8_t c; + + for (i = 0; i < 8; i++) + { + finalcount[i] = (u_int8_t)((this->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + c = 0200; + SHA1Update(this, &c, 1); + while ((this->count[0] & 504) != 448) + { + c = 0000; + SHA1Update(this, &c, 1); + } + SHA1Update(this, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) + { + digest[i] = (u_int8_t)((this->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } +} + + +/** + * Implementation of hasher_t.get_hash. + */ +static void get_hash(private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer) +{ + SHA1Update(this, chunk.ptr, chunk.len); + if (buffer != NULL) + { + SHA1Final(this, buffer); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + } +} + + +/** + * Implementation of hasher_t.allocate_hash. + */ +static void allocate_hash(private_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash) +{ + chunk_t allocated_hash; + + SHA1Update(this, chunk.ptr, chunk.len); + if (hash != NULL) + { + allocated_hash.ptr = malloc(BLOCK_SIZE_SHA1); + allocated_hash.len = BLOCK_SIZE_SHA1; + + SHA1Final(this, allocated_hash.ptr); + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + + *hash = allocated_hash; + } +} + +/** + * Implementation of hasher_t.get_hash_size. + */ +static size_t get_hash_size(private_sha1_hasher_t *this) +{ + return BLOCK_SIZE_SHA1; +} + +/** + * Implementation of hasher_t.reset. + */ +static void reset(private_sha1_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xEFCDAB89; + this->state[2] = 0x98BADCFE; + this->state[3] = 0x10325476; + this->state[4] = 0xC3D2E1F0; + this->count[0] = 0; + this->count[1] = 0; +} +/** + * Implementation of hasher_t.destroy. + */ +static void destroy(private_sha1_hasher_t *this) +{ + free(this); +} + + +/* + * Described in header. + */ +sha1_hasher_t *sha1_hasher_create() +{ + private_sha1_hasher_t *this = malloc_thing(private_sha1_hasher_t); + + this->public.hasher_interface.get_hash = (void (*) (hasher_t*, chunk_t, u_int8_t*))get_hash; + this->public.hasher_interface.allocate_hash = (void (*) (hasher_t*, chunk_t, chunk_t*))allocate_hash; + this->public.hasher_interface.get_hash_size = (size_t (*) (hasher_t*))get_hash_size; + this->public.hasher_interface.reset = (void (*) (hasher_t*))reset; + this->public.hasher_interface.destroy = (void (*) (hasher_t*))destroy; + + /* initialize */ + this->public.hasher_interface.reset(&(this->public.hasher_interface)); + + return &(this->public); +} diff --git a/src/charon/lib/crypto/hashers/sha1_hasher.h b/src/charon/lib/crypto/hashers/sha1_hasher.h new file mode 100644 index 000000000..5124ea1a8 --- /dev/null +++ b/src/charon/lib/crypto/hashers/sha1_hasher.h @@ -0,0 +1,60 @@ +/** + * @file sha1_hasher.h + * + * @brief Interface of sha1_hasher_t + * + */ + +/* + * 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. + */ + +#ifndef SHA1_HASHER_H_ +#define SHA1_HASHER_H_ + +#include <crypto/hashers/hasher.h> + + +typedef struct sha1_hasher_t sha1_hasher_t; + +/** + * @brief Implementation of hasher_t interface using the + * SHA1 algorithm. + * + * @b Constructors: + * - hasher_create() using HASH_SHA1 as algorithm + * - sha1_hasher_create() + * + * @see hasher_t + * + * @ingroup hashers + */ +struct sha1_hasher_t { + + /** + * Generic hasher_t interface for this hasher. + */ + hasher_t hasher_interface; +}; + +/** + * @brief Creates a new sha1_hasher_t. + * + * @return sha1_hasher_t object + * + * @ingroup hashers + */ +sha1_hasher_t *sha1_hasher_create(); + +#endif /*SHA1_HASHER_H_*/ diff --git a/src/charon/lib/crypto/hmac.c b/src/charon/lib/crypto/hmac.c new file mode 100644 index 000000000..bb8880770 --- /dev/null +++ b/src/charon/lib/crypto/hmac.c @@ -0,0 +1,209 @@ +/** + * @file hmac.c + * + * @brief Implementation of hmac_t. + */ + +/* + * 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 hmac 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 hmac License + * for more details. + */ + +#include <string.h> + +#include "hmac.h" + + +typedef struct private_hmac_t private_hmac_t; + +/** + * Private data of a hmac_t object. + * + * The variable names are the same as in the RFC. + */ +struct private_hmac_t { + /** + * Public hmac_t interface. + */ + hmac_t hmac; + + /** + * Block size, as in RFC. + */ + u_int8_t b; + + /** + * Hash function. + */ + hasher_t *h; + + /** + * Previously xor'ed key using opad. + */ + chunk_t opaded_key; + + /** + * Previously xor'ed key using ipad. + */ + chunk_t ipaded_key; +}; + +/** + * Implementation of hmac_t.get_mac. + */ +static void get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out) +{ + /* H(K XOR opad, H(K XOR ipad, text)) + * + * if out is NULL, we append text to the inner hash. + * else, we complete the inner and do the outer. + * + */ + + u_int8_t buffer[this->h->get_hash_size(this->h)]; + chunk_t inner; + + if (out == NULL) + { + /* append data to inner */ + this->h->get_hash(this->h, data, NULL); + } + else + { + /* append and do outer hash */ + inner.ptr = buffer; + inner.len = this->h->get_hash_size(this->h); + + /* complete inner */ + this->h->get_hash(this->h, data, buffer); + + /* do outer */ + this->h->get_hash(this->h, this->opaded_key, NULL); + this->h->get_hash(this->h, inner, out); + + /* reinit for next call */ + this->h->get_hash(this->h, this->ipaded_key, NULL); + } +} + +/** + * Implementation of hmac_t.allocate_mac. + */ +static void allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out) +{ + /* allocate space and use get_mac */ + if (out == NULL) + { + /* append mode */ + this->hmac.get_mac(&(this->hmac), data, NULL); + } + else + { + out->len = this->h->get_hash_size(this->h); + out->ptr = malloc(out->len); + this->hmac.get_mac(&(this->hmac), data, out->ptr); + } +} + +/** + * Implementation of hmac_t.get_block_size. + */ +static size_t get_block_size(private_hmac_t *this) +{ + return this->h->get_hash_size(this->h); +} + +/** + * Implementation of hmac_t.set_key. + */ +static void set_key(private_hmac_t *this, chunk_t key) +{ + int i; + u_int8_t buffer[this->b]; + + memset(buffer, 0, this->b); + + if (key.len > this->b) + { + /* if key is too long, it will be hashed */ + this->h->get_hash(this->h, key, buffer); + } + else + { + /* if not, just copy it in our pre-padded k */ + memcpy(buffer, key.ptr, key.len); + } + + /* apply ipad and opad to key */ + for (i = 0; i < this->b; i++) + { + this->ipaded_key.ptr[i] = buffer[i] ^ 0x36; + this->opaded_key.ptr[i] = buffer[i] ^ 0x5C; + } + + /* begin hashing of inner pad */ + this->h->reset(this->h); + this->h->get_hash(this->h, this->ipaded_key, NULL); +} + +/** + * Implementation of hmac_t.destroy. + */ +static void destroy(private_hmac_t *this) +{ + this->h->destroy(this->h); + free(this->opaded_key.ptr); + free(this->ipaded_key.ptr); + free(this); +} + +/* + * Described in header + */ +hmac_t *hmac_create(hash_algorithm_t hash_algorithm) +{ + private_hmac_t *this; + + this = malloc_thing(private_hmac_t); + + /* set hmac_t methods */ + this->hmac.get_mac = (void (*)(hmac_t *,chunk_t,u_int8_t*))get_mac; + this->hmac.allocate_mac = (void (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac; + this->hmac.get_block_size = (size_t (*)(hmac_t *))get_block_size; + this->hmac.set_key = (void (*)(hmac_t *,chunk_t))set_key; + this->hmac.destroy = (void (*)(hmac_t *))destroy; + + /* set b, according to hasher */ + switch (hash_algorithm) + { + case HASH_SHA1: + case HASH_MD5: + this->b = 64; + break; + default: + free(this); + return NULL; + } + + /* build the hasher */ + this->h = hasher_create(hash_algorithm); + + /* build ipad and opad */ + this->opaded_key.ptr = malloc(this->b); + this->opaded_key.len = this->b; + + this->ipaded_key.ptr = malloc(this->b); + this->ipaded_key.len = this->b; + + return &(this->hmac); +} diff --git a/src/charon/lib/crypto/hmac.h b/src/charon/lib/crypto/hmac.h new file mode 100644 index 000000000..8945fc1fc --- /dev/null +++ b/src/charon/lib/crypto/hmac.h @@ -0,0 +1,118 @@ +/** + * @file hmac.h + * + * @brief Interface of hmac_t. + */ + +/* + * 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. + */ + +#ifndef HMAC_H_ +#define HMAC_H_ + +#include <crypto/hashers/hasher.h> +#include <definitions.h> + + +typedef struct hmac_t hmac_t; + +/** + * @brief Message authentication using hash functions. + * + * This class implements the message authenticaion algorithm + * described in RFC2104. It uses a hash function, wich must + * be implemented as a hasher_t class. + * + * See http://www.faqs.org/rfcs/rfc2104.html for RFC. + * @see + * - hasher_t + * - prf_hmac_t + * + * @b Constructors: + * - hmac_create() + * + * @ingroup transforms + */ +struct hmac_t { + /** + * @brief Generate message authentication code. + * + * If buffer is NULL, no result is given back. A next call will + * append the data to already supplied data. If buffer is not NULL, + * the mac of all apended data is calculated, returned and the + * state of the hmac_t is reseted. + * + * @param this calling object + * @param data chunk of data to authenticate + * @param[out] buffer pointer where the generated bytes will be written + */ + void (*get_mac) (hmac_t *this, chunk_t data, u_int8_t *buffer); + + /** + * @brief Generates message authentication code and + * allocate space for them. + * + * If chunk is NULL, no result is given back. A next call will + * append the data to already supplied. If chunk is not NULL, + * the mac of all apended data is calculated, returned and the + * state of the hmac_t reset; + * + * @param this calling object + * @param data chunk of data to authenticate + * @param[out] chunk chunk which will hold generated bytes + */ + void (*allocate_mac) (hmac_t *this, chunk_t data, chunk_t *chunk); + + /** + * @brief Get the block size of this hmac_t object. + * + * @param this calling object + * @return block size in bytes + */ + size_t (*get_block_size) (hmac_t *this); + + /** + * @brief Set the key for this hmac_t object. + * + * Any key length is accepted. + * + * @param this calling object + * @param key key to set + */ + void (*set_key) (hmac_t *this, chunk_t key); + + /** + * @brief Destroys a hmac_t object. + * + * @param this calling object + */ + void (*destroy) (hmac_t *this); +}; + +/** + * @brief Creates a new hmac_t object. + * + * Creates a hasher_t object internally. + * + * @param hash_algorithm hash algorithm to use + * @return + * - hmac_t object + * - NULL if hash algorithm is not supported + * + * @ingroup transforms + */ +hmac_t *hmac_create(hash_algorithm_t hash_algorithm); + +#endif /*HMAC_H_*/ diff --git a/src/charon/lib/crypto/prf_plus.c b/src/charon/lib/crypto/prf_plus.c new file mode 100644 index 000000000..d408d0517 --- /dev/null +++ b/src/charon/lib/crypto/prf_plus.c @@ -0,0 +1,157 @@ +/** + * @file prf_plus.c + * + * @brief Implementation of prf_plus_t. + * + */ + +/* + * 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 <string.h> + +#include "prf_plus.h" + +#include <definitions.h> + +typedef struct private_prf_plus_t private_prf_plus_t; + +/** + * Private data of an prf_plus_t object. + * + */ +struct private_prf_plus_t { + /** + * Public interface of prf_plus_t. + */ + prf_plus_t public; + + /** + * PRF to use. + */ + prf_t *prf; + + /** + * Initial seed. + */ + chunk_t seed; + + /** + * Buffer to store current PRF result. + */ + chunk_t buffer; + + /** + * Already given out bytes in current buffer. + */ + size_t given_out; + + /** + * Octet which will be appended to the seed. + */ + u_int8_t appending_octet; +}; + +/** + * Implementation of prf_plus_t.get_bytes. + */ +static void get_bytes(private_prf_plus_t *this, size_t length, u_int8_t *buffer) +{ + chunk_t appending_chunk; + size_t bytes_in_round; + size_t total_bytes_written = 0; + + appending_chunk.ptr = &(this->appending_octet); + appending_chunk.len = 1; + + while (length > 0) + { /* still more to do... */ + if (this->buffer.len == this->given_out) + { /* no bytes left in buffer, get next*/ + this->prf->get_bytes(this->prf, this->buffer, NULL); + this->prf->get_bytes(this->prf, this->seed, NULL); + this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); + this->given_out = 0; + this->appending_octet++; + } + /* how many bytes can we write in this round ? */ + bytes_in_round = min(length, this->buffer.len - this->given_out); + /* copy bytes from buffer with offset */ + memcpy(buffer + total_bytes_written, this->buffer.ptr + this->given_out, bytes_in_round); + + length -= bytes_in_round; + this->given_out += bytes_in_round; + total_bytes_written += bytes_in_round; + } +} + +/** + * Implementation of prf_plus_t.allocate_bytes. + */ +static void allocate_bytes(private_prf_plus_t *this, size_t length, chunk_t *chunk) +{ + chunk->ptr = malloc(length); + chunk->len = length; + this->public.get_bytes(&(this->public), length, chunk->ptr); +} + +/** + * Implementation of prf_plus_t.destroy. + */ +static void destroy(private_prf_plus_t *this) +{ + free(this->buffer.ptr); + free(this->seed.ptr); + free(this); +} + +/* + * Description in header. + */ +prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed) +{ + private_prf_plus_t *this; + chunk_t appending_chunk; + + this = malloc_thing(private_prf_plus_t); + + /* set public methods */ + this->public.get_bytes = (void (*)(prf_plus_t *,size_t,u_int8_t*))get_bytes; + this->public.allocate_bytes = (void (*)(prf_plus_t *,size_t,chunk_t*))allocate_bytes; + this->public.destroy = (void (*)(prf_plus_t *))destroy; + + /* take over prf */ + this->prf = prf; + + /* allocate buffer for prf output */ + this->buffer.len = prf->get_block_size(prf); + this->buffer.ptr = malloc(this->buffer.len); + + this->appending_octet = 0x01; + + /* clone seed */ + this->seed.ptr = clalloc(seed.ptr, seed.len); + this->seed.len = seed.len; + + /* do the first run */ + appending_chunk.ptr = &(this->appending_octet); + appending_chunk.len = 1; + this->prf->get_bytes(this->prf, this->seed, NULL); + this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); + this->given_out = 0; + this->appending_octet++; + + return &(this->public); +} diff --git a/src/charon/lib/crypto/prf_plus.h b/src/charon/lib/crypto/prf_plus.h new file mode 100644 index 000000000..bdcd01966 --- /dev/null +++ b/src/charon/lib/crypto/prf_plus.h @@ -0,0 +1,93 @@ +/** + * @file prf_plus.h + * + * @brief Interface for prf_plus.h. + * + */ + +/* + * 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. + */ + +#ifndef PRF_PLUS_H_ +#define PRF_PLUS_H_ + + +#include <crypto/prfs/prf.h> + + +typedef struct prf_plus_t prf_plus_t; + +/** + * @brief Implementation of the prf+ function described in IKEv2 RFC. + * + * This class implements the prf+ algorithm. Internally it uses a pseudo random + * function, which implements the prf_t interface. + * + * See IKEv2 RFC 2.13. + * + * @b Constructors: + * - prf_plus_create() + * + * @ingroup transforms + */ +struct prf_plus_t { + /** + * @brief Get pseudo random bytes. + * + * Get the next few bytes of the prf+ output. Space + * must be allocated by the caller. + * + * @param this calling object + * @param length number of bytes to get + * @param[out] buffer pointer where the generated bytes will be written + */ + void (*get_bytes) (prf_plus_t *this, size_t length, u_int8_t *buffer); + + /** + * @brief Allocate pseudo random bytes. + * + * Get the next few bytes of the prf+ output. This function + * will allocate the required space. + * + * @param this calling object + * @param length number of bytes to get + * @param[out] chunk chunk which will hold generated bytes + */ + void (*allocate_bytes) (prf_plus_t *this, size_t length, chunk_t *chunk); + + /** + * @brief Destroys a prf_plus_t object. + * + * @param this calling object + */ + void (*destroy) (prf_plus_t *this); +}; + +/** + * @brief Creates a new prf_plus_t object. + * + * Seed will be cloned. prf will + * not be cloned, must be destroyed outside after + * prf_plus_t usage. + * + * @param prf prf object to use + * @param seed input seed for prf + * @return prf_plus_t object + * + * @ingroup transforms + */ +prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed); + +#endif /*PRF_PLUS_H_*/ diff --git a/src/charon/lib/crypto/prfs/Makefile.prfs b/src/charon/lib/crypto/prfs/Makefile.prfs new file mode 100644 index 000000000..a98894346 --- /dev/null +++ b/src/charon/lib/crypto/prfs/Makefile.prfs @@ -0,0 +1,23 @@ +# 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. +# + +PRFS_DIR= $(CRYPTO_DIR)prfs/ + +LIB_OBJS+= $(BUILD_DIR)prf.o +$(BUILD_DIR)prf.o : $(PRFS_DIR)prf.c $(PRFS_DIR)prf.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)hmac_prf.o +$(BUILD_DIR)hmac_prf.o : $(PRFS_DIR)hmac_prf.c $(PRFS_DIR)hmac_prf.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/charon/lib/crypto/prfs/hmac_prf.c b/src/charon/lib/crypto/prfs/hmac_prf.c new file mode 100644 index 000000000..2a7d34a3a --- /dev/null +++ b/src/charon/lib/crypto/prfs/hmac_prf.c @@ -0,0 +1,117 @@ +/** + * @file hmac_prf.c + * + * @brief Implementation for hmac_prf_t. + * + */ + +/* + * 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 "hmac_prf.h" + +#include <crypto/hmac.h> + + +typedef struct private_hmac_prf_t private_hmac_prf_t; + +/** + * Private data of a hma_prf_t object. + */ +struct private_hmac_prf_t { + /** + * Public hmac_prf_t interface. + */ + hmac_prf_t public; + + /** + * Hmac to use for generation. + */ + hmac_t *hmac; +}; + +/** + * Implementation of prf_t.get_bytes. + */ +static void get_bytes(private_hmac_prf_t *this, chunk_t seed, u_int8_t *buffer) +{ + this->hmac->get_mac(this->hmac, seed, buffer); +} + +/** + * Implementation of prf_t.allocate_bytes. + */ +static void allocate_bytes(private_hmac_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + this->hmac->allocate_mac(this->hmac, seed, chunk); +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_block_size(private_hmac_prf_t *this) +{ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of prf_t.get_block_size. + */ +static size_t get_key_size(private_hmac_prf_t *this) +{ + /* for HMAC prfs, IKEv2 uses block size as key size */ + return this->hmac->get_block_size(this->hmac); +} + +/** + * Implementation of prf_t.set_key. + */ +static void set_key(private_hmac_prf_t *this, chunk_t key) +{ + this->hmac->set_key(this->hmac, key); +} + +/** + * Implementation of prf_t.destroy. + */ +static void destroy(private_hmac_prf_t *this) +{ + free(this); + this->hmac->destroy(this->hmac); +} + +/* + * Described in header. + */ +hmac_prf_t *hmac_prf_create(hash_algorithm_t hash_algorithm) +{ + private_hmac_prf_t *this = malloc_thing(private_hmac_prf_t); + + this->public.prf_interface.get_bytes = (void (*) (prf_t *,chunk_t,u_int8_t*))get_bytes; + this->public.prf_interface.allocate_bytes = (void (*) (prf_t*,chunk_t,chunk_t*))allocate_bytes; + this->public.prf_interface.get_block_size = (size_t (*) (prf_t*))get_block_size; + this->public.prf_interface.get_key_size = (size_t (*) (prf_t*))get_key_size; + this->public.prf_interface.set_key = (void (*) (prf_t *,chunk_t))set_key; + this->public.prf_interface.destroy = (void (*) (prf_t *))destroy; + + this->hmac = hmac_create(hash_algorithm); + if (this->hmac == NULL) + { + free(this); + return NULL; + } + + return &(this->public); +} diff --git a/src/charon/lib/crypto/prfs/hmac_prf.h b/src/charon/lib/crypto/prfs/hmac_prf.h new file mode 100644 index 000000000..3a68960f7 --- /dev/null +++ b/src/charon/lib/crypto/prfs/hmac_prf.h @@ -0,0 +1,64 @@ +/** + * @file hmac_prf.h + * + * @brief Interface of hmac_prf_t. + * + */ + +/* + * 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. + */ + +#ifndef PRF_HMAC_H_ +#define PRF_HMAC_H_ + +#include <types.h> +#include <crypto/prfs/prf.h> +#include <crypto/hashers/hasher.h> + +typedef struct hmac_prf_t hmac_prf_t; + +/** + * @brief Implementation of prf_t interface using the + * HMAC algorithm. + * + * This simply wraps a hmac_t in a prf_t. More a question of + * interface matching. + * + * @b Constructors: + * - hmac_prf_create() + * + * @ingroup prfs + */ +struct hmac_prf_t { + + /** + * Generic prf_t interface for this hmac_prf_t class. + */ + prf_t prf_interface; +}; + +/** + * @brief Creates a new hmac_prf_t object. + * + * @param hash_algorithm hmac's hash algorithm + * @return + * - hmac_prf_t object + * - NULL if hash not supported + * + * @ingroup prfs + */ +hmac_prf_t *hmac_prf_create(hash_algorithm_t hash_algorithm); + +#endif /*PRF_HMAC_SHA1_H_*/ diff --git a/src/charon/lib/crypto/prfs/prf.c b/src/charon/lib/crypto/prfs/prf.c new file mode 100644 index 000000000..bb7015e64 --- /dev/null +++ b/src/charon/lib/crypto/prfs/prf.c @@ -0,0 +1,67 @@ +/** + * @file prf.c + * + * @brief Generic constructor for all prf_t + * + */ + +/* + * 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 "prf.h" + +#include <crypto/hashers/hasher.h> +#include <crypto/prfs/hmac_prf.h> + + +/** + * String mappings for encryption_algorithm_t. + */ +mapping_t pseudo_random_function_m[] = { +{PRF_UNDEFINED, "PRF_UNDEFINED"}, +{PRF_HMAC_MD5, "PRF_HMAC_MD5"}, +{PRF_HMAC_SHA1, "PRF_HMAC_SHA1"}, +{PRF_HMAC_TIGER, "PRF_HMAC_TIGER"}, +{PRF_AES128_CBC, "PRF_AES128_CBC"}, +{MAPPING_END, NULL} +}; + +/* + * Described in header. + */ +prf_t *prf_create(pseudo_random_function_t pseudo_random_function) +{ + switch (pseudo_random_function) + { + case PRF_HMAC_SHA1: + { + return (prf_t*)hmac_prf_create(HASH_SHA1); + } + case PRF_HMAC_MD5: + { + return (prf_t*)hmac_prf_create(HASH_MD5); + } + case PRF_HMAC_TIGER: + case PRF_AES128_CBC: + default: + return NULL; + } +} + + + + + diff --git a/src/charon/lib/crypto/prfs/prf.h b/src/charon/lib/crypto/prfs/prf.h new file mode 100644 index 000000000..b1c1e6a66 --- /dev/null +++ b/src/charon/lib/crypto/prfs/prf.h @@ -0,0 +1,136 @@ +/** + * @file prf.h + * + * @brief Interface prf_t. + * + */ + +/* + * 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. + */ + +#ifndef PRF_H_ +#define PRF_H_ + +#include <types.h> + +typedef enum pseudo_random_function_t pseudo_random_function_t; + +/** + * @brief Pseudo random function, as in IKEv2 RFC 3.3.2. + * + * Currently only the following algorithms are implemented and therefore supported: + * - PRF_HMAC_MD5 + * - PRF_HMAC_SHA1 + * + * @ingroup prfs + */ +enum pseudo_random_function_t { + PRF_UNDEFINED = 1024, + /** + * Implemented in class hmac_prf_t. + */ + PRF_HMAC_MD5 = 1, + /** + * Implemented in class hmac_prf_t. + */ + PRF_HMAC_SHA1 = 2, + PRF_HMAC_TIGER = 3, + PRF_AES128_CBC = 4 +}; + +/** + * String mappings for encryption_algorithm_t. + */ +extern mapping_t pseudo_random_function_m[]; + + +typedef struct prf_t prf_t; + +/** + * @brief Generic interface for pseudo-random-functions. + * + * @b Constructors: + * - prf_create() + * - hmac_prf_create() + * + * @todo Implement more prf algorithms + * + * @ingroup prfs + */ +struct prf_t { + /** + * @brief Generates pseudo random bytes and writes them + * in the buffer. + * + * @param this calling object + * @param seed a chunk containing the seed for the next bytes + * @param[out] buffer pointer where the generated bytes will be written + */ + void (*get_bytes) (prf_t *this, chunk_t seed, u_int8_t *buffer); + + /** + * @brief Generates pseudo random bytes and allocate space for them. + * + * @param this calling object + * @param seed a chunk containing the seed for the next bytes + * @param[out] chunk chunk which will hold generated bytes + */ + void (*allocate_bytes) (prf_t *this, chunk_t seed, chunk_t *chunk); + + /** + * @brief Get the block size of this prf_t object. + * + * @param this calling object + * @return block size in bytes + */ + size_t (*get_block_size) (prf_t *this); + + /** + * @brief Get the key size of this prf_t object. + * + * @param this calling object + * @return key size in bytes + */ + size_t (*get_key_size) (prf_t *this); + + /** + * @brief Set the key for this prf_t object. + * + * @param this calling object + * @param key key to set + */ + void (*set_key) (prf_t *this, chunk_t key); + + /** + * @brief Destroys a prf object. + * + * @param this calling object + */ + void (*destroy) (prf_t *this); +}; + +/** + * @brief Generic constructor for a prf_t oject. + * + * @param pseudo_random_function Algorithm to use + * @return + * - prf_t object + * - NULL if prf algorithm not supported + * + * @ingroup prfs + */ +prf_t *prf_create(pseudo_random_function_t pseudo_random_function); + +#endif /*PRF_H_*/ diff --git a/src/charon/lib/crypto/rsa/Makefile.rsa b/src/charon/lib/crypto/rsa/Makefile.rsa new file mode 100644 index 000000000..1a0204c83 --- /dev/null +++ b/src/charon/lib/crypto/rsa/Makefile.rsa @@ -0,0 +1,23 @@ +# 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. +# + +RSA_DIR= $(CRYPTO_DIR)rsa/ + +LIB_OBJS+= $(BUILD_DIR)rsa_private_key.o +$(BUILD_DIR)rsa_private_key.o : $(RSA_DIR)rsa_private_key.c $(RSA_DIR)rsa_private_key.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)rsa_public_key.o +$(BUILD_DIR)rsa_public_key.o : $(RSA_DIR)rsa_public_key.c $(RSA_DIR)rsa_public_key.h + $(CC) $(CFLAGS) -c -o $@ $<
\ No newline at end of file diff --git a/src/charon/lib/crypto/rsa/rsa_private_key.c b/src/charon/lib/crypto/rsa/rsa_private_key.c new file mode 100644 index 000000000..358653f0e --- /dev/null +++ b/src/charon/lib/crypto/rsa/rsa_private_key.c @@ -0,0 +1,772 @@ +/** + * @file rsa_private_key.c + * + * @brief Implementation of rsa_private_key_t. + * + */ + +/* + * 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 <gmp.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include "rsa_private_key.h" + +#include <daemon.h> +#include <asn1/asn1.h> + +/* + * Oids for hash algorithms are defined in + * rsa_public_key.c. + */ +extern u_int8_t md2_oid[18]; +extern u_int8_t md5_oid[18]; +extern u_int8_t sha1_oid[15]; +extern u_int8_t sha256_oid[19]; +extern u_int8_t sha384_oid[19]; +extern u_int8_t sha512_oid[19]; + + +/** + * Public exponent to use for key generation. + */ +#define PUBLIC_EXPONENT 0x10001 + + +typedef struct private_rsa_private_key_t private_rsa_private_key_t; + +/** + * Private data of a rsa_private_key_t object. + */ +struct private_rsa_private_key_t { + /** + * Public interface for this signer. + */ + rsa_private_key_t public; + + /** + * Version of key, as encoded in PKCS#1 + */ + u_int version; + + /** + * Public modulus. + */ + mpz_t n; + + /** + * Public exponent. + */ + mpz_t e; + + /** + * Private prime 1. + */ + mpz_t p; + + /** + * Private Prime 2. + */ + mpz_t q; + + /** + * Private exponent. + */ + mpz_t d; + + /** + * Private exponent 1. + */ + mpz_t exp1; + + /** + * Private exponent 2. + */ + mpz_t exp2; + + /** + * Private coefficient. + */ + mpz_t coeff; + + /** + * Keysize in bytes. + */ + size_t k; + + /** + * @brief Implements the RSADP algorithm specified in PKCS#1. + * + * @param this calling object + * @param data data to process + * @return processed data + */ + chunk_t (*rsadp) (private_rsa_private_key_t *this, chunk_t data); + + /** + * @brief Implements the RSASP1 algorithm specified in PKCS#1. + * @param this calling object + * @param data data to process + * @return processed data + */ + chunk_t (*rsasp1) (private_rsa_private_key_t *this, chunk_t data); + + /** + * @brief Generate a prime value. + * + * @param this calling object + * @param prime_size size of the prime, in bytes + * @param[out] prime uninitialized mpz + */ + status_t (*compute_prime) (private_rsa_private_key_t *this, size_t prime_size, mpz_t *prime); + +}; + +/* ASN.1 definition of a PKCS#1 RSA private key */ +static const asn1Object_t privkey_objects[] = { + { 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 PRIV_KEY_VERSION 1 +#define PRIV_KEY_MODULUS 2 +#define PRIV_KEY_PUB_EXP 3 +#define PRIV_KEY_PRIV_EXP 4 +#define PRIV_KEY_PRIME1 5 +#define PRIV_KEY_PRIME2 6 +#define PRIV_KEY_EXP1 7 +#define PRIV_KEY_EXP2 8 +#define PRIV_KEY_COEFF 9 +#define PRIV_KEY_ROOF 16 + +static private_rsa_private_key_t *rsa_private_key_create_empty(); + +/** + * Implementation of private_rsa_private_key_t.compute_prime. + */ +static status_t compute_prime(private_rsa_private_key_t *this, size_t prime_size, mpz_t *prime) +{ + randomizer_t *randomizer; + chunk_t random_bytes; + status_t status; + + randomizer = randomizer_create(); + mpz_init(*prime); + + do + { + status = randomizer->allocate_random_bytes(randomizer, prime_size, &random_bytes); + if (status != SUCCESS) + { + randomizer->destroy(randomizer); + mpz_clear(*prime); + return FAILED; + } + + /* make sure most significant bit is set */ + random_bytes.ptr[0] = random_bytes.ptr[0] | 0x80; + + /* convert chunk to mpz value */ + mpz_import(*prime, random_bytes.len, 1, 1, 1, 0, random_bytes.ptr); + + /* get next prime */ + mpz_nextprime (*prime, *prime); + + free(random_bytes.ptr); + } + /* check if it isnt too large */ + while (((mpz_sizeinbase(*prime, 2) + 7) / 8) > prime_size); + + randomizer->destroy(randomizer); + return SUCCESS; +} + +/** + * Implementation of private_rsa_private_key_t.rsadp and private_rsa_private_key_t.rsasp1. + */ +static chunk_t rsadp(private_rsa_private_key_t *this, chunk_t data) +{ + mpz_t t1, t2; + chunk_t decrypted; + + mpz_init(t1); + mpz_init(t2); + + mpz_import(t1, data.len, 1, 1, 1, 0, data.ptr); + + mpz_powm(t2, t1, this->exp1, this->p); /* m1 = c^dP mod p */ + mpz_powm(t1, t1, this->exp2, this->q); /* m2 = c^dQ mod Q */ + mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ + mpz_mod(t2, t2, this->p); + mpz_mul(t2, t2, this->coeff); + mpz_mod(t2, t2, this->p); + + mpz_mul(t2, t2, this->q); /* m = m2 + h q */ + mpz_add(t1, t1, t2); + + decrypted.len = this->k; + decrypted.ptr = mpz_export(NULL, NULL, 1, decrypted.len, 1, 0, t1); + + mpz_clear(t1); + mpz_clear(t2); + + return decrypted; +} + +/** + * Implementation of rsa_private_key.build_emsa_signature. + */ +static status_t build_emsa_pkcs1_signature(private_rsa_private_key_t *this, hash_algorithm_t hash_algorithm, chunk_t data, chunk_t *signature) +{ + hasher_t *hasher; + chunk_t hash; + chunk_t oid; + chunk_t em; + + /* get oid string prepended to hash */ + switch (hash_algorithm) + { + case HASH_MD2: + { + oid.ptr = md2_oid; + oid.len = sizeof(md2_oid); + break; + } + case HASH_MD5: + { + oid.ptr = md5_oid; + oid.len = sizeof(md5_oid); + break; + } + case HASH_SHA1: + { + oid.ptr = sha1_oid; + oid.len = sizeof(sha1_oid); + break; + } + case HASH_SHA256: + { + oid.ptr = sha256_oid; + oid.len = sizeof(sha256_oid); + break; + } + case HASH_SHA384: + { + oid.ptr = sha384_oid; + oid.len = sizeof(sha384_oid); + break; + } + case HASH_SHA512: + { + oid.ptr = sha512_oid; + oid.len = sizeof(sha512_oid); + break; + } + default: + { + return NOT_SUPPORTED; + } + } + + /* get hasher */ + hasher = hasher_create(hash_algorithm); + if (hasher == NULL) + { + return NOT_SUPPORTED; + } + + /* build hash */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + + /* build chunk to rsa-decrypt: + * EM = 0x00 || 0x01 || PS || 0x00 || T. + * PS = 0xFF padding, with length to fill em + * T = oid || hash + */ + em.len = this->k; + em.ptr = malloc(em.len); + + /* fill em with padding */ + memset(em.ptr, 0xFF, em.len); + /* set magic bytes */ + *(em.ptr) = 0x00; + *(em.ptr+1) = 0x01; + *(em.ptr + em.len - hash.len - oid.len - 1) = 0x00; + /* set hash */ + memcpy(em.ptr + em.len - hash.len, hash.ptr, hash.len); + /* set oid */ + memcpy(em.ptr + em.len - hash.len - oid.len, oid.ptr, oid.len); + + /* build signature */ + *signature = this->rsasp1(this, em); + + free(hash.ptr); + free(em.ptr); + + return SUCCESS; +} + +/** + * Implementation of rsa_private_key.get_key. + */ +static status_t get_key(private_rsa_private_key_t *this, chunk_t *key) +{ + chunk_t n, e, p, q, d, exp1, exp2, coeff; + + n.len = this->k; + n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n); + e.len = this->k; + e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e); + p.len = this->k; + p.ptr = mpz_export(NULL, NULL, 1, p.len, 1, 0, this->p); + q.len = this->k; + q.ptr = mpz_export(NULL, NULL, 1, q.len, 1, 0, this->q); + d.len = this->k; + d.ptr = mpz_export(NULL, NULL, 1, d.len, 1, 0, this->d); + exp1.len = this->k; + exp1.ptr = mpz_export(NULL, NULL, 1, exp1.len, 1, 0, this->exp1); + exp2.len = this->k; + exp2.ptr = mpz_export(NULL, NULL, 1, exp2.len, 1, 0, this->exp2); + coeff.len = this->k; + coeff.ptr = mpz_export(NULL, NULL, 1, coeff.len, 1, 0, this->coeff); + + key->len = this->k * 8; + key->ptr = malloc(key->len); + memcpy(key->ptr + this->k * 0, n.ptr , n.len); + memcpy(key->ptr + this->k * 1, e.ptr, e.len); + memcpy(key->ptr + this->k * 2, p.ptr, p.len); + memcpy(key->ptr + this->k * 3, q.ptr, q.len); + memcpy(key->ptr + this->k * 4, d.ptr, d.len); + memcpy(key->ptr + this->k * 5, exp1.ptr, exp1.len); + memcpy(key->ptr + this->k * 6, exp2.ptr, exp2.len); + memcpy(key->ptr + this->k * 7, coeff.ptr, coeff.len); + + free(n.ptr); + free(e.ptr); + free(p.ptr); + free(q.ptr); + free(d.ptr); + free(exp1.ptr); + free(exp2.ptr); + free(coeff.ptr); + + return SUCCESS; +} + +/** + * Implementation of rsa_private_key.save_key. + */ +static status_t save_key(private_rsa_private_key_t *this, char *file) +{ + return NOT_SUPPORTED; +} + +/** + * Implementation of rsa_private_key.get_public_key. + */ +rsa_public_key_t *get_public_key(private_rsa_private_key_t *this) +{ + return NULL; +} + +/** + * Implementation of rsa_private_key.belongs_to. + */ +static bool belongs_to(private_rsa_private_key_t *this, rsa_public_key_t *public) +{ + if (mpz_cmp(this->n, *public->get_modulus(public)) == 0) + { + return TRUE; + } + return FALSE; +} + +/** + * Check the loaded key if it is valid and usable + * TODO: Log errors + */ +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; +} + +/** + * Implementation of rsa_private_key.clone. + */ +static rsa_private_key_t* _clone(private_rsa_private_key_t *this) +{ + private_rsa_private_key_t *clone = rsa_private_key_create_empty(); + + mpz_init_set(clone->n, this->n); + mpz_init_set(clone->e, this->e); + mpz_init_set(clone->p, this->p); + mpz_init_set(clone->q, this->q); + mpz_init_set(clone->d, this->d); + mpz_init_set(clone->exp1, this->exp1); + mpz_init_set(clone->exp2, this->exp2); + mpz_init_set(clone->coeff, this->coeff); + clone->k = this->k; + + return &clone->public; +} + +/** + * Implementation of rsa_private_key.destroy. + */ +static void destroy(private_rsa_private_key_t *this) +{ + mpz_clear(this->n); + mpz_clear(this->e); + mpz_clear(this->p); + mpz_clear(this->q); + mpz_clear(this->d); + mpz_clear(this->exp1); + mpz_clear(this->exp2); + mpz_clear(this->coeff); + free(this); +} + +/** + * Internal generic constructor + */ +static private_rsa_private_key_t *rsa_private_key_create_empty() +{ + private_rsa_private_key_t *this = malloc_thing(private_rsa_private_key_t); + + /* public functions */ + this->public.build_emsa_pkcs1_signature = (status_t (*) (rsa_private_key_t*,hash_algorithm_t,chunk_t,chunk_t*))build_emsa_pkcs1_signature; + this->public.get_key = (status_t (*) (rsa_private_key_t*,chunk_t*))get_key; + this->public.save_key = (status_t (*) (rsa_private_key_t*,char*))save_key; + this->public.get_public_key = (rsa_public_key_t *(*) (rsa_private_key_t*))get_public_key; + this->public.belongs_to = (bool (*) (rsa_private_key_t*,rsa_public_key_t*))belongs_to; + this->public.clone = (rsa_private_key_t*(*)(rsa_private_key_t*))_clone; + this->public.destroy = (void (*) (rsa_private_key_t*))destroy; + + /* private functions */ + this->rsadp = rsadp; + this->rsasp1 = rsadp; /* same algorithm */ + this->compute_prime = compute_prime; + + return this; +} + +/* + * See header + */ +rsa_private_key_t *rsa_private_key_create(size_t key_size) +{ + mpz_t p, q, n, e, d, exp1, exp2, coeff; + mpz_t m, q1, t; + private_rsa_private_key_t *this; + + this = rsa_private_key_create_empty(); + key_size = key_size / 8; + + /* Get values of primes p and q */ + if (this->compute_prime(this, key_size/2, &p) != SUCCESS) + { + free(this); + return NULL; + } + if (this->compute_prime(this, key_size/2, &q) != SUCCESS) + { + mpz_clear(p); + free(this); + return NULL; + } + + mpz_init(t); + mpz_init(n); + mpz_init(d); + mpz_init(exp1); + mpz_init(exp2); + mpz_init(coeff); + + /* Swapping Primes so p is larger then q */ + if (mpz_cmp(p, q) < 0) + { + mpz_set(t, p); + mpz_set(p, q); + mpz_set(q, t); + } + + mpz_mul(n, p, q); /* n = p*q */ + mpz_init_set_ui(e, PUBLIC_EXPONENT); /* assign public exponent */ + mpz_init_set(m, p); /* m = p */ + mpz_sub_ui(m, m, 1); /* m = m -1 */ + mpz_init_set(q1, q); /* q1 = q */ + mpz_sub_ui(q1, q1, 1); /* q1 = q1 -1 */ + mpz_gcd(t, m, q1); /* t = gcd(p-1, q-1) */ + mpz_mul(m, m, q1); /* m = (p-1)*(q-1) */ + mpz_divexact(m, m, t); /* m = m / t */ + mpz_gcd(t, m, e); /* t = gcd(m, e) (greatest common divisor) */ + + mpz_invert(d, e, m); /* e has an inverse mod m */ + if (mpz_cmp_ui(d, 0) < 0) /* make sure d is positive */ + { + mpz_add(d, d, m); + } + mpz_sub_ui(t, p, 1); /* t = p-1 */ + mpz_mod(exp1, d, t); /* exp1 = d mod p-1 */ + mpz_sub_ui(t, q, 1); /* t = q-1 */ + mpz_mod(exp2, d, t); /* exp2 = d mod q-1 */ + + mpz_invert(coeff, q, p); /* coeff = q^-1 mod p */ + if (mpz_cmp_ui(coeff, 0) < 0) /* make coeff d is positive */ + { + mpz_add(coeff, coeff, p); + } + + mpz_clear(q1); + mpz_clear(m); + mpz_clear(t); + + /* apply values */ + *(this->p) = *p; + *(this->q) = *q; + *(this->n) = *n; + *(this->e) = *e; + *(this->d) = *d; + *(this->exp1) = *exp1; + *(this->exp2) = *exp2; + *(this->coeff) = *coeff; + + /* set key size in bytes */ + this->k = key_size; + + return &this->public; +} + +/* + * see header + */ +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 < PRIV_KEY_ROOF) + { + if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx)) + { + destroy(this); + return FALSE; + } + switch (objectID) + { + case PRIV_KEY_VERSION: + if (object.len > 0 && *object.ptr != 0) + { + destroy(this); + return NULL; + } + break; + case PRIV_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PUB_EXP: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIV_EXP: + mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME1: + mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME2: + mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_EXP1: + mpz_import(this->exp1, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_EXP2: + mpz_import(this->exp2, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_COEFF: + mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr); + break; + } + objectID++; + } + + this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8; + + if (check(this) != SUCCESS) + { + destroy(this); + return NULL; + } + else + { + return &this->public; + } +} + +/* + * see header + * TODO: PEM files + */ +rsa_private_key_t *rsa_private_key_create_from_file(char *filename, char *passphrase) +{ + chunk_t chunk; + struct stat stb; + FILE *file; + char *buffer; + + if (stat(filename, &stb) == -1) + { + return NULL; + } + + buffer = alloca(stb.st_size); + + file = fopen(filename, "r"); + if (file == NULL) + { + return NULL; + } + + if (fread(buffer, stb.st_size, 1, file) != 1) + { + fclose(file); + return NULL; + } + fclose(file); + + chunk.ptr = buffer; + chunk.len = stb.st_size; + + return rsa_private_key_create_from_chunk(chunk); +} diff --git a/src/charon/lib/crypto/rsa/rsa_private_key.h b/src/charon/lib/crypto/rsa/rsa_private_key.h new file mode 100644 index 000000000..b3b8ae87f --- /dev/null +++ b/src/charon/lib/crypto/rsa/rsa_private_key.h @@ -0,0 +1,185 @@ +/** + * @file rsa_private_key.h + * + * @brief Interface of rsa_private_key_t. + * + */ + +/* + * 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. + */ + +#ifndef RSA_PRIVATE_KEY_H_ +#define RSA_PRIVATE_KEY_H_ + +#include <types.h> +#include <definitions.h> +#include <crypto/rsa/rsa_public_key.h> +#include <crypto/hashers/hasher.h> + + +typedef struct rsa_private_key_t rsa_private_key_t; + +/** + * @brief RSA private key with associated functions. + * + * Currently only supports signing using EMSA encoding. + * + * @b Constructors: + * - rsa_private_key_create() + * - rsa_private_key_create_from_chunk() + * - rsa_private_key_create_from_file() + * + * @see rsa_public_key_t + * + * @todo Implement get_key(), save_key(), get_public_key() + * + * @ingroup rsa + */ +struct rsa_private_key_t { + + /** + * @brief Build a signature over a chunk using EMSA-PKCS1 encoding. + * + * This signature creates a hash using the specified hash algorithm, concatenates + * it with an ASN1-OID of the hash algorithm and runs the RSASP1 function + * on it. + * + * @param this calling object + * @param hash_algorithm hash algorithm to use for hashing + * @param data data to sign + * @param[out] signature allocated signature + * @return + * - SUCCESS + * - INVALID_STATE, if key not set + * - NOT_SUPPORTED, if hash algorithm not supported + */ + status_t (*build_emsa_pkcs1_signature) (rsa_private_key_t *this, hash_algorithm_t hash_algorithm, chunk_t data, chunk_t *signature); + + /** + * @brief Gets the key. + * + * UNIMPLEMENTED! + * + * @param this calling object + * @param key key (in a propriarity format) + * @return + * - SUCCESS + * - INVALID_STATE, if key not set + */ + status_t (*get_key) (rsa_private_key_t *this, chunk_t *key); + + /** + * @brief Saves a key to a file. + * + * Not implemented! + * + * @param this calling object + * @param file file to which the key should be written. + * @return NOT_SUPPORTED + */ + status_t (*save_key) (rsa_private_key_t *this, char *file); + + /** + * @brief Generate a new key. + * + * Generates a new private_key with specified key size + * + * @param this calling object + * @param key_size size of the key in bits + * @return + * - SUCCESS + * - INVALID_ARG if key_size invalid + */ + status_t (*generate_key) (rsa_private_key_t *this, size_t key_size); + + /** + * @brief Create a rsa_public_key_t with the public + * parts of the key. + * + * @param this calling object + * @return public_key + */ + rsa_public_key_t *(*get_public_key) (rsa_private_key_t *this); + + /** + * @brief Check if a private key belongs to a public key. + * + * Compares the public part of the private key with the + * public key, return TRUE if it equals. + * + * @param this private key + * @param public public key + * @return TRUE, if keys belong together + */ + bool (*belongs_to) (rsa_private_key_t *this, rsa_public_key_t *public); + + /** + * @brief Clone the private key. + * + * @param this private key to clone + * @return clone of this + */ + rsa_private_key_t *(*clone) (rsa_private_key_t *this); + + /** + * @brief Destroys the private key. + * + * @param this private key to destroy + */ + void (*destroy) (rsa_private_key_t *this); +}; + +/** + * @brief Generate a new RSA key with specified key lenght. + * + * @param key_size size of the key in bits + * @return generated rsa_private_key_t. + * + * @ingroup rsa + */ +rsa_private_key_t *rsa_private_key_create(size_t key_size); + +/** + * @brief Load an RSA private key from a chunk. + * + * Load a key from a chunk, encoded as described in PKCS#1 + * (ASN1 DER encoded). + * + * @param chunk chunk containing the DER encoded key + * @return loaded rsa_private_key_t, or NULL + * + * @ingroup rsa + */ +rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t chunk); + +/** + * @brief Load an RSA private key from a file. + * + * Load a key from a file, which is either in a unencrypted binary + * format (DER), or in a (encrypted) PEM format. The supplied + * passphrase is used to decrypt an ecrypted key. + * + * @param filename filename which holds the key + * @param passphrase optional passphase for decryption + * @return loaded rsa_private_key_t, or NULL + * + * @todo Implement PEM file loading + * @todo Implement key decryption + * + * @ingroup rsa + */ +rsa_private_key_t *rsa_private_key_create_from_file(char *filename, char *passphrase); + +#endif /*RSA_PRIVATE_KEY_H_*/ diff --git a/src/charon/lib/crypto/rsa/rsa_public_key.c b/src/charon/lib/crypto/rsa/rsa_public_key.c new file mode 100644 index 000000000..6601b6cda --- /dev/null +++ b/src/charon/lib/crypto/rsa/rsa_public_key.c @@ -0,0 +1,458 @@ +/** + * @file rsa_public_key.c + * + * @brief Implementation of rsa_public_key_t. + * + */ + +/* + * 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 <gmp.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include "rsa_public_key.h" + +#include <daemon.h> +#include <crypto/hashers/hasher.h> +#include <asn1/asn1.h> + +/* + * For simplicity, + * we use these predefined values for + * hash algorithm OIDs. These also contain + * the length of the following hash. + * These values are also used in rsa_private_key.c. + * TODO: We may move them in asn1 sometime... + */ + +u_int8_t md2_oid[] = { + 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86, + 0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00, + 0x04,0x10 +}; + +u_int8_t md5_oid[] = { + 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86, + 0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00, + 0x04,0x10 +}; + +u_int8_t sha1_oid[] = { + 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e, + 0x03,0x02,0x1a,0x05,0x00,0x04,0x14 +}; + +u_int8_t sha256_oid[] = { + 0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86, + 0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05, + 0x00,0x04,0x20 +}; + +u_int8_t sha384_oid[] = { + 0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86, + 0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05, + 0x00,0x04,0x30 +}; + +u_int8_t sha512_oid[] = { + 0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86, + 0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05, + 0x00,0x04,0x40 +}; + +/* ASN.1 definition public key */ +static const asn1Object_t pubkey_objects[] = { + { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */ +}; + +#define PUB_KEY_RSA_PUBLIC_KEY 0 +#define PUB_KEY_MODULUS 1 +#define PUB_KEY_EXPONENT 2 +#define PUB_KEY_ROOF 3 + +typedef struct private_rsa_public_key_t private_rsa_public_key_t; + +/** + * Private data structure with signing context. + */ +struct private_rsa_public_key_t { + /** + * Public interface for this signer. + */ + rsa_public_key_t public; + + /** + * Public modulus. + */ + mpz_t n; + + /** + * Public exponent. + */ + mpz_t e; + + /** + * Keysize in bytes. + */ + size_t k; + + /** + * @brief Implements the RSAEP algorithm specified in PKCS#1. + * + * @param this calling object + * @param data data to process + * @return processed data + */ + chunk_t (*rsaep) (private_rsa_public_key_t *this, chunk_t data); + + /** + * @brief Implements the RSASVP1 algorithm specified in PKCS#1. + * + * @param this calling object + * @param data data to process + * @return processed data + */ + chunk_t (*rsavp1) (private_rsa_public_key_t *this, chunk_t data); +}; + + +typedef struct rsa_public_key_info_t rsa_public_key_info_t; + +/** + * KeyInfo, as it appears in a public key file + */ +struct rsa_public_key_info_t { + /** + * Algorithm for this key + */ + chunk_t algorithm_oid; + + /** + * Public key, parseable with rsa_public_key_rules + */ + chunk_t public_key; +}; + +private_rsa_public_key_t *rsa_public_key_create_empty(); + +/** + * Implementation of private_rsa_public_key_t.rsaep and private_rsa_public_key_t.rsavp1 + */ +static chunk_t rsaep(private_rsa_public_key_t *this, chunk_t data) +{ + mpz_t m, c; + chunk_t encrypted; + + mpz_init(c); + mpz_init(m); + + mpz_import(m, data.len, 1, 1, 1, 0, data.ptr); + + mpz_powm(c, m, this->e, this->n); + + encrypted.len = this->k; + encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c); + + mpz_clear(c); + mpz_clear(m); + + return encrypted; +} + +/** + * Implementation of rsa_public_key.verify_emsa_pkcs1_signature. + */ +static status_t verify_emsa_pkcs1_signature(private_rsa_public_key_t *this, chunk_t data, chunk_t signature) +{ + hasher_t *hasher = NULL; + chunk_t hash; + chunk_t em; + u_int8_t *pos; + + if (signature.len > this->k) + { + return INVALID_ARG; + } + + /* unpack signature */ + em = this->rsavp1(this, signature); + + /* result should look like this: + * EM = 0x00 || 0x01 || PS || 0x00 || T. + * PS = 0xFF padding, with length to fill em + * T = oid || hash + */ + + /* check magic bytes */ + if ((*(em.ptr) != 0x00) || + (*(em.ptr+1) != 0x01)) + { + free(em.ptr); + return FAILED; + } + + /* find magic 0x00 */ + pos = em.ptr + 2; + while (pos <= em.ptr + em.len) + { + if (*pos == 0x00) + { + /* found magic byte, stop */ + pos++; + break; + } + else if (*pos != 0xFF) + { + /* bad padding, decryption failed ?!*/ + free(em.ptr); + return FAILED; + } + pos++; + } + + if (pos + 20 > em.ptr + em.len) + { + /* not enought room for oid compare */ + free(em.ptr); + return FAILED; + } + + if (memcmp(md2_oid, pos, sizeof(md2_oid)) == 0) + { + hasher = hasher_create(HASH_MD2); + pos += sizeof(md2_oid); + } + else if (memcmp(md5_oid, pos, sizeof(md5_oid)) == 0) + { + hasher = hasher_create(HASH_MD5); + pos += sizeof(md5_oid); + } + else if (memcmp(sha1_oid, pos, sizeof(sha1_oid)) == 0) + { + hasher = hasher_create(HASH_SHA1); + pos += sizeof(sha1_oid); + } + else if (memcmp(sha256_oid, pos, sizeof(sha256_oid)) == 0) + { + hasher = hasher_create(HASH_SHA256); + pos += sizeof(sha256_oid); + } + else if (memcmp(sha384_oid, pos, sizeof(sha384_oid)) == 0) + { + hasher = hasher_create(HASH_SHA384); + pos += sizeof(sha384_oid); + } + else if (memcmp(sha512_oid, pos, sizeof(sha512_oid)) == 0) + { + hasher = hasher_create(HASH_SHA512); + pos += sizeof(sha512_oid); + } + + if (hasher == NULL) + { + /* not supported hash algorithm */ + free(em.ptr); + return NOT_SUPPORTED; + } + + if (pos + hasher->get_hash_size(hasher) != em.ptr + em.len) + { + /* bad length */ + free(em.ptr); + hasher->destroy(hasher); + return FAILED; + } + + /* build own hash for a compare */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + + if (memcmp(hash.ptr, pos, hash.len) != 0) + { + /* hash does not equal */ + free(hash.ptr); + free(em.ptr); + return FAILED; + + } + + /* seems good */ + free(hash.ptr); + free(em.ptr); + return SUCCESS; +} + +/** + * Implementation of rsa_public_key.get_key. + */ +static status_t get_key(private_rsa_public_key_t *this, chunk_t *key) +{ + chunk_t n, e; + + n.len = this->k; + n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n); + e.len = this->k; + e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e); + + key->len = this->k * 2; + key->ptr = malloc(key->len); + memcpy(key->ptr, n.ptr, n.len); + memcpy(key->ptr + n.len, e.ptr, e.len); + free(n.ptr); + free(e.ptr); + + return SUCCESS; +} + +/** + * Implementation of rsa_public_key.save_key. + */ +static status_t save_key(private_rsa_public_key_t *this, char *file) +{ + return NOT_SUPPORTED; +} + +/** + * Implementation of rsa_public_key.get_modulus. + */ +static mpz_t *get_modulus(private_rsa_public_key_t *this) +{ + return &this->n; +} + +/** + * Implementation of rsa_public_key.clone. + */ +static rsa_public_key_t* _clone(private_rsa_public_key_t *this) +{ + private_rsa_public_key_t *clone = rsa_public_key_create_empty(); + + mpz_init_set(clone->n, this->n); + mpz_init_set(clone->e, this->e); + clone->k = this->k; + + return &clone->public; +} + +/** + * Implementation of rsa_public_key.destroy. + */ +static void destroy(private_rsa_public_key_t *this) +{ + mpz_clear(this->n); + mpz_clear(this->e); + free(this); +} + +/** + * Generic private constructor + */ +private_rsa_public_key_t *rsa_public_key_create_empty() +{ + private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t); + + /* public functions */ + this->public.verify_emsa_pkcs1_signature = (status_t (*) (rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature; + this->public.get_key = (status_t (*) (rsa_public_key_t*,chunk_t*))get_key; + this->public.save_key = (status_t (*) (rsa_public_key_t*,char*))save_key; + this->public.get_modulus = (mpz_t *(*) (rsa_public_key_t*))get_modulus; + this->public.clone = (rsa_public_key_t* (*) (rsa_public_key_t*))_clone; + this->public.destroy = (void (*) (rsa_public_key_t*))destroy; + + /* private functions */ + this->rsaep = rsaep; + this->rsavp1 = rsaep; /* same algorithm */ + + return this; +} + +/* + * See header + */ +rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + private_rsa_public_key_t *this; + + this = rsa_public_key_create_empty(); + mpz_init(this->n); + mpz_init(this->e); + + asn1_init(&ctx, blob, 0, FALSE); + + while (objectID < PUB_KEY_ROOF) + { + if (!extract_object(pubkey_objects, &objectID, &object, &level, &ctx)) + { + destroy(this); + return FALSE; + } + switch (objectID) + { + case PUB_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PUB_KEY_EXPONENT: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + } + objectID++; + } + + this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8; + return &this->public; +} + +/* + * See header + */ +rsa_public_key_t *rsa_public_key_create_from_file(char *filename) +{ + struct stat stb; + FILE *file; + char *buffer; + chunk_t chunk; + + if (stat(filename, &stb) == -1) + { + return NULL; + } + + buffer = alloca(stb.st_size); + + file = fopen(filename, "r"); + if (file == NULL) + { + return NULL; + } + + if (fread(buffer, stb.st_size, 1, file) != 1) + { + return NULL; + } + + chunk.ptr = buffer; + chunk.len = stb.st_size; + + return rsa_public_key_create_from_chunk(chunk); +} diff --git a/src/charon/lib/crypto/rsa/rsa_public_key.h b/src/charon/lib/crypto/rsa/rsa_public_key.h new file mode 100644 index 000000000..ef79153d6 --- /dev/null +++ b/src/charon/lib/crypto/rsa/rsa_public_key.h @@ -0,0 +1,153 @@ +/** + * @file rsa_public_key.h + * + * @brief Interface of rsa_public_key_t. + * + */ + +/* + * 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. + */ + +#ifndef RSA_PUBLIC_KEY_H_ +#define RSA_PUBLIC_KEY_H_ + +#include <gmp.h> + +#include <types.h> +#include <definitions.h> + + +typedef struct rsa_public_key_t rsa_public_key_t; + +/** + * @brief RSA public key with associated functions. + * + * Currently only supports signature verification using + * the EMSA encoding (see PKCS1) + * + * @b Constructors: + * - rsa_public_key_create_from_chunk() + * - rsa_public_key_create_from_file() + * - rsa_private_key_t.get_public_key() + * + * @see rsa_private_key_t + * + * @todo Implement getkey() and savekey() + * + * @ingroup rsa + */ +struct rsa_public_key_t { + + /** + * @brief Verify a EMSA-PKCS1 encodined signature. + * + * Processes the supplied signature with the RSAVP1 function, + * selects the hash algorithm form the resultign ASN1-OID and + * verifies the hash against the supplied data. + * + * @param this rsa_public_key to use + * @param data data to sign + * @param signature signature to verify + * @return + * - SUCCESS, if signature ok + * - INVALID_STATE, if key not set + * - NOT_SUPPORTED, if hash algorithm not supported + * - INVALID_ARG, if signature is not a signature + * - FAILED if signature invalid or unable to verify + */ + status_t (*verify_emsa_pkcs1_signature) (rsa_public_key_t *this, chunk_t data, chunk_t signature); + + /** + * @brief Gets the key. + * + * Currently uses a proprietary format which is only inteded + * for testing. This should be replaced with a proper + * ASN1 encoded key format, when charon gets the ASN1 + * capabilities. + * + * @param this calling object + * @param key key (in a propriarity format) + * @return + * - SUCCESS + * - INVALID_STATE, if key not set + */ + status_t (*get_key) (rsa_public_key_t *this, chunk_t *key); + + /** + * @brief Saves a key to a file. + * + * Not implemented! + * + * @param this calling object + * @param file file to which the key should be written. + * @return NOT_SUPPORTED + */ + status_t (*save_key) (rsa_public_key_t *this, char *file); + + /** + * @brief Get the modulus of the key. + * + * @param this calling object + * @return modulus (n) of the key + */ + mpz_t *(*get_modulus) (rsa_public_key_t *this); + + /** + * @brief Clone the public key. + * + * @param this public key to clone + * @return clone of this + */ + rsa_public_key_t *(*clone) (rsa_public_key_t *this); + + /** + * @brief Destroys the public key. + * + * @param this public key to destroy + */ + void (*destroy) (rsa_public_key_t *this); +}; + +/** + * @brief Load an RSA public key from a chunk. + * + * Load a key from a chunk, encoded in the more frequently + * used PublicKeyInfo struct (ASN1 DER encoded). + * + * @param chunk chunk containing the DER encoded key + * @return loaded rsa_public_key_t, or NULL + * + * @todo Check OID in PublicKeyInfo + * + * @ingroup rsa + */ +rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t chunk); + +/** + * @brief Load an RSA public key from a file. + * + * Load a key from a file, which is either in binary + * format (DER), or in PEM format. + * + * @param filename filename which holds the key + * @return loaded rsa_public_key_t, or NULL + * + * @todo Implement PEM file loading + * + * @ingroup rsa + */ +rsa_public_key_t *rsa_public_key_create_from_file(char *filename); + +#endif /*RSA_PUBLIC_KEY_H_*/ diff --git a/src/charon/lib/crypto/signers/Makefile.signers b/src/charon/lib/crypto/signers/Makefile.signers new file mode 100644 index 000000000..8f161a09d --- /dev/null +++ b/src/charon/lib/crypto/signers/Makefile.signers @@ -0,0 +1,23 @@ +# 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. +# + +SIGNERS_DIR= $(CRYPTO_DIR)signers/ + +LIB_OBJS+= $(BUILD_DIR)signer.o +$(BUILD_DIR)signer.o : $(SIGNERS_DIR)signer.c $(SIGNERS_DIR)signer.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)hmac_signer.o +$(BUILD_DIR)hmac_signer.o : $(SIGNERS_DIR)hmac_signer.c $(SIGNERS_DIR)hmac_signer.h + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/charon/lib/crypto/signers/hmac_signer.c b/src/charon/lib/crypto/signers/hmac_signer.c new file mode 100644 index 000000000..cb7d08244 --- /dev/null +++ b/src/charon/lib/crypto/signers/hmac_signer.c @@ -0,0 +1,169 @@ +/** + * @file hmac_signer.c + * + * @brief Implementation of hmac_signer_t. + * + */ + +/* + * 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 <string.h> + +#include "hmac_signer.h" + +#include <crypto/prfs/hmac_prf.h> + +/** + * This class represents a hmac signer with 12 byte (96 bit) output. + */ +#define BLOCK_SIZE 12 + +typedef struct private_hmac_signer_t private_hmac_signer_t; + +/** + * Private data structure with signing context. + */ +struct private_hmac_signer_t { + /** + * Public interface of hmac_signer_t. + */ + hmac_signer_t public; + + /* + * Assigned hmac function. + */ + prf_t *hmac_prf; +}; + +/** + * Implementation of signer_t.get_signature. + */ +static void get_signature (private_hmac_signer_t *this, chunk_t data, u_int8_t *buffer) +{ + u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; + + this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); + + /* copy mac aka signature :-) */ + memcpy(buffer,full_mac,BLOCK_SIZE); +} + +/** + * Implementation of signer_t.allocate_signature. + */ +static void allocate_signature (private_hmac_signer_t *this, chunk_t data, chunk_t *chunk) +{ + chunk_t signature; + u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; + + this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); + + signature.ptr = malloc(BLOCK_SIZE); + signature.len = BLOCK_SIZE; + + /* copy signature */ + memcpy(signature.ptr,full_mac,BLOCK_SIZE); + + *chunk = signature; +} + +/** + * Implementation of signer_t.verify_signature. + */ +static bool verify_signature (private_hmac_signer_t *this, chunk_t data, chunk_t signature) +{ + u_int8_t full_mac[this->hmac_prf->get_block_size(this->hmac_prf)]; + + this->hmac_prf->get_bytes(this->hmac_prf,data,full_mac); + + if (signature.len != BLOCK_SIZE) + { + return FALSE; + } + + /* compare mac aka signature :-) */ + if (memcmp(signature.ptr,full_mac,BLOCK_SIZE) == 0) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/** + * Implementation of signer_t.get_key_size. + */ +static size_t get_key_size (private_hmac_signer_t *this) +{ + /* for HMAC signer, IKEv2 uses block size as key size */ + return this->hmac_prf->get_block_size(this->hmac_prf); +} + +/** + * Implementation of signer_t.get_block_size. + */ +static size_t get_block_size (private_hmac_signer_t *this) +{ + return BLOCK_SIZE; +} + +/** + * Implementation of signer_t.set_key. + */ +static void set_key (private_hmac_signer_t *this, chunk_t key) +{ + this->hmac_prf->set_key(this->hmac_prf,key); +} + +/** + * Implementation of signer_t.destroy. + */ +static status_t destroy(private_hmac_signer_t *this) +{ + this->hmac_prf->destroy(this->hmac_prf); + free(this); + return SUCCESS; +} + +/* + * Described in header + */ +hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm) +{ + private_hmac_signer_t *this = malloc_thing(private_hmac_signer_t); + + this->hmac_prf = (prf_t *) hmac_prf_create(hash_algoritm); + + if (this->hmac_prf == NULL) + { + /* algorithm not supported */ + free(this); + return NULL; + } + + /* interface functions */ + this->public.signer_interface.get_signature = (void (*) (signer_t*, chunk_t, u_int8_t*))get_signature; + this->public.signer_interface.allocate_signature = (void (*) (signer_t*, chunk_t, chunk_t*))allocate_signature; + this->public.signer_interface.verify_signature = (bool (*) (signer_t*, chunk_t, chunk_t))verify_signature; + this->public.signer_interface.get_key_size = (size_t (*) (signer_t*))get_key_size; + this->public.signer_interface.get_block_size = (size_t (*) (signer_t*))get_block_size; + this->public.signer_interface.set_key = (void (*) (signer_t*,chunk_t))set_key; + this->public.signer_interface.destroy = (void (*) (signer_t*))destroy; + + return &(this->public); +} diff --git a/src/charon/lib/crypto/signers/hmac_signer.h b/src/charon/lib/crypto/signers/hmac_signer.h new file mode 100644 index 000000000..62427167e --- /dev/null +++ b/src/charon/lib/crypto/signers/hmac_signer.h @@ -0,0 +1,58 @@ +/** + * @file hmac_signer.h + * + * @brief Interface of hmac_signer_t. + * + */ + +/* + * 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. + */ + +#ifndef HMAC_SIGNER_H_ +#define HMAC_SIGNER_H_ + +#include <crypto/signers/signer.h> +#include <crypto/hashers/hasher.h> + +typedef struct hmac_signer_t hmac_signer_t; + +/** + * @brief Implementation of signer_t interface using the + * HMAC algorithm in combination with either MD5 or SHA1. + * + * @ingroup signers + */ +struct hmac_signer_t { + + /** + * generic signer_t interface for this signer + */ + signer_t signer_interface; +}; + +/** + * @brief Creates a new hmac_signer_t. + * + * @param hash_algoritm Hash algorithm to use with signer + * @return + * - hmac_signer_t + * - NULL if hash algorithm not supported + * + * @ingroup signers + */ +hmac_signer_t *hmac_signer_create(hash_algorithm_t hash_algoritm); + + +#endif /*HMAC_SIGNER_H_*/ diff --git a/src/charon/lib/crypto/signers/signer.c b/src/charon/lib/crypto/signers/signer.c new file mode 100644 index 000000000..3e6378957 --- /dev/null +++ b/src/charon/lib/crypto/signers/signer.c @@ -0,0 +1,59 @@ +/** + * @file signer.c + * + * @brief Implementation of generic signer_t constructor. + * + */ + +/* + * 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 "signer.h" + +#include <crypto/signers/hmac_signer.h> + +/** + * String mappings for integrity_algorithm_t. + */ +mapping_t integrity_algorithm_m[] = { + {AUTH_UNDEFINED, "AUTH_UNDEFINED"}, + {AUTH_HMAC_MD5_96, "AUTH_HMAC_MD5_96"}, + {AUTH_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96"}, + {AUTH_DES_MAC, "AUTH_DES_MAC"}, + {AUTH_KPDK_MD5, "AUTH_KPDK_MD5"}, + {AUTH_AES_XCBC_96, "AUTH_AES_XCBC_96"}, + {MAPPING_END, NULL} +}; + + +/* + * Described in header. + */ +signer_t *signer_create(integrity_algorithm_t integrity_algorithm) +{ + switch(integrity_algorithm) + { + case AUTH_HMAC_SHA1_96: + { + return ((signer_t *) hmac_signer_create(HASH_SHA1)); + } + case AUTH_HMAC_MD5_96: + { + return ((signer_t *) hmac_signer_create(HASH_MD5)); + } + default: + return NULL; + } +} diff --git a/src/charon/lib/crypto/signers/signer.h b/src/charon/lib/crypto/signers/signer.h new file mode 100644 index 000000000..9625af813 --- /dev/null +++ b/src/charon/lib/crypto/signers/signer.h @@ -0,0 +1,147 @@ +/** + * @file signer.h + * + * @brief Interface for signer_t. + * + */ + +/* + * 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. + */ + +#ifndef SIGNER_H_ +#define SIGNER_H_ + +#include <types.h> +#include <definitions.h> + +typedef enum integrity_algorithm_t integrity_algorithm_t; + +/** + * @brief Integrity algorithm, as in IKEv2 RFC 3.3.2. + * + * Currently only the following algorithms are implemented and therefore supported: + * - AUTH_HMAC_MD5_96 + * - AUTH_HMAC_SHA1_96 + * + * @ingroup signers + */ +enum integrity_algorithm_t { + AUTH_UNDEFINED = 1024, + /** + * Implemented in class hmac_signer_t. + */ + AUTH_HMAC_MD5_96 = 1, + /** + * Implemented in class hmac_signer_t. + */ + AUTH_HMAC_SHA1_96 = 2, + AUTH_DES_MAC = 3, + AUTH_KPDK_MD5 = 4, + AUTH_AES_XCBC_96 = 5 +}; + +/** + * String mappings for integrity_algorithm_t. + */ +extern mapping_t integrity_algorithm_m[]; + + +typedef struct signer_t signer_t; + +/** + * @brief Generig interface for a symmetric signature algorithm. + * + * @b Constructors: + * - signer_create() + * - hmac_signer_create() + * + * @todo Implement more integrity algorithms + * + * @ingroup signers + */ +struct signer_t { + /** + * @brief Generate a signature. + * + * @param this calling object + * @param data a chunk containing the data to sign + * @param[out] buffer pointer where the signature will be written + */ + void (*get_signature) (signer_t *this, chunk_t data, u_int8_t *buffer); + + /** + * @brief Generate a signature and allocate space for it. + * + * @param this calling object + * @param data a chunk containing the data to sign + * @param[out] chunk chunk which will hold the allocated signature + */ + void (*allocate_signature) (signer_t *this, chunk_t data, chunk_t *chunk); + + /** + * @brief Verify a signature. + * + * @param this calling object + * @param data a chunk containing the data to verify + * @param signature a chunk containing the signature + * @return TRUE, if signature is valid, FALSE otherwise + */ + bool (*verify_signature) (signer_t *this, chunk_t data, chunk_t signature); + + /** + * @brief Get the block size of this signature algorithm. + * + * @param this calling object + * @return block size in bytes + */ + size_t (*get_block_size) (signer_t *this); + + /** + * @brief Get the key size of the signature algorithm. + * + * @param this calling object + * @return key size in bytes + */ + size_t (*get_key_size) (signer_t *this); + + /** + * @brief Set the key for this object. + * + * @param this calling object + * @param key key to set + */ + void (*set_key) (signer_t *this, chunk_t key); + + /** + * @brief Destroys a signer_t object. + * + * @param this calling object + */ + void (*destroy) (signer_t *this); +}; + +/** + * @brief Creates a new signer_t object. + * + * @param integrity_algorithm Algorithm to use for signing and verifying. + * @return + * - signer_t object + * - NULL if signer not supported + * + * @ingroup signers + */ +signer_t *signer_create(integrity_algorithm_t integrity_algorithm); + +#endif /*SIGNER_H_*/ diff --git a/src/charon/lib/crypto/x509.c b/src/charon/lib/crypto/x509.c new file mode 100755 index 000000000..86a595618 --- /dev/null +++ b/src/charon/lib/crypto/x509.c @@ -0,0 +1,937 @@ +/** + * @file x509.c + * + * @brief Implementation of x509_t. + * + */ + +/* + * 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. + */ + +#include <gmp.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include "x509.h" + +#include <daemon.h> +#include <asn1/asn1.h> +#include <asn1/oid.h> +#include <utils/logger_manager.h> + +typedef const char *err_t; /* error message, or NULL for success */ + + +#define BUF_LEN 512 +#define RSA_MIN_OCTETS (512 / 8) +#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits" +#define RSA_MAX_OCTETS (8192 / 8) +#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits" + +logger_t *logger; + +typedef enum generalNames_t generalNames_t; + +/** + * Different kinds of generalNames + */ +enum generalNames_t { + GN_OTHER_NAME = 0, + GN_RFC822_NAME = 1, + GN_DNS_NAME = 2, + GN_X400_ADDRESS = 3, + GN_DIRECTORY_NAME = 4, + GN_EDI_PARTY_NAME = 5, + GN_URI = 6, + GN_IP_ADDRESS = 7, + GN_REGISTERED_ID = 8, +}; + +typedef struct generalName_t generalName_t; + +/** + * A generalName, chainable in a list + */ +struct generalName_t { + generalName_t *next; + generalNames_t kind; + chunk_t name; +}; + +typedef struct private_x509_t private_x509_t; + +/** + * Private data of a x509_t object. + */ +struct private_x509_t { + /** + * Public interface for this certificate. + */ + x509_t public; + + /** + * Version of the X509 certificate + */ + u_int version; + + /** + * ID representing the certificates subject + */ + identification_t *subject; + + /** + * ID representing the certificate issuer + */ + identification_t *issuer; + + /** + * List of identification_t's representing subjectAltNames + */ + linked_list_t *subjectAltNames; + + /** + * List of identification_t's representing issuerAltNames + */ + linked_list_t *issuerAltNames; + + /** + * List of identification_t's representing crlDistributionPoints + */ + linked_list_t *crlDistributionPoints; + + /** + * Type of the subjects Key (currently RSA only) + */ + auth_method_t subjectPublicKeyAlgorithm; + + + /** + * Subjects RSA public key, if subjectPublicKeyAlgorithm == RSA + */ + rsa_public_key_t *public_key; + + + + + time_t installed; + u_char authority_flags; + chunk_t x509; + chunk_t tbsCertificate; + chunk_t serialNumber; + /* signature */ + int sigAlg; + /* validity */ + time_t notBefore; + time_t notAfter; + /* subjectPublicKeyInfo */ + chunk_t subjectPublicKey; + /* issuerUniqueID */ + /* subjectUniqueID */ + /* v3 extensions */ + /* extension */ + /* extension */ + /* extnID */ + /* critical */ + /* extnValue */ + bool isCA; + bool isOcspSigner; /* ocsp */ + chunk_t subjectKeyID; + chunk_t authKeyID; + chunk_t authKeySerialNumber; + chunk_t accessLocation; /* ocsp */ + /* signatureAlgorithm */ + int algorithm; + chunk_t signature; +}; + +/** + * ASN.1 definition of a basicConstraints extension + */ +static const asn1Object_t basicConstraintsObjects[] = { + { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ + { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */ +}; +#define BASIC_CONSTRAINTS_CA 1 +#define BASIC_CONSTRAINTS_ROOF 4 + +/** + * ASN.1 definition of time + */ +static const asn1Object_t timeObjects[] = { + { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */ + { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */ + { 0, "generalizeTime",ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 0, "end opt", ASN1_EOC, ASN1_END } /* 3 */ +}; +#define TIME_UTC 0 +#define TIME_GENERALIZED 2 +#define TIME_ROOF 4 + +/** + * ASN.1 definition of a keyIdentifier + */ +static const asn1Object_t keyIdentifierObjects[] = { + { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */ +}; + +/** + * ASN.1 definition of a authorityKeyIdentifier extension + */ +static const asn1Object_t authorityKeyIdentifierObjects[] = { + { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_OBJ }, /* 1 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "authorityCertSerialNumber",ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ +}; +#define AUTH_KEY_ID_KEY_ID 1 +#define AUTH_KEY_ID_CERT_ISSUER 3 +#define AUTH_KEY_ID_CERT_SERIAL 5 +#define AUTH_KEY_ID_ROOF 7 + +/** + * ASN.1 definition of a authorityInfoAccess extension + */ +static const asn1Object_t authorityInfoAccessObjects[] = { + { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 4 */ +}; +#define AUTH_INFO_ACCESS_METHOD 2 +#define AUTH_INFO_ACCESS_LOCATION 3 +#define AUTH_INFO_ACCESS_ROOF 5 + +/** + * ASN.1 definition of a extendedKeyUsage extension + */ +static const asn1Object_t extendedKeyUsageObjects[] = { + { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ +}; + +#define EXT_KEY_USAGE_PURPOSE_ID 1 +#define EXT_KEY_USAGE_ROOF 3 + +/** + * ASN.1 definition of generalNames + */ +static const asn1Object_t generalNamesObjects[] = { + { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ +}; +#define GENERAL_NAMES_GN 1 +#define GENERAL_NAMES_ROOF 3 + + +/** + * ASN.1 definition of crlDistributionPoints + */ +static const asn1Object_t crlDistributionPointsObjects[] = { + { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */ + { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ + { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ + { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ +}; +#define CRL_DIST_POINTS_FULLNAME 3 +#define CRL_DIST_POINTS_ROOF 13 + +/** + * ASN.1 definition of an X.509v3 x509 + */ +static const asn1Object_t certObjects[] = { + { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ + { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ + { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ + { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ + { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ + { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ + { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ + { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ + { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 13 */ + { 4, "RSAPublicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 14 */ + { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 15 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 16 */ + { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 17 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 19 */ + { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 23 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ +}; +#define X509_OBJ_CERTIFICATE 0 +#define X509_OBJ_TBS_CERTIFICATE 1 +#define X509_OBJ_VERSION 3 +#define X509_OBJ_SERIAL_NUMBER 4 +#define X509_OBJ_SIG_ALG 5 +#define X509_OBJ_ISSUER 6 +#define X509_OBJ_NOT_BEFORE 8 +#define X509_OBJ_NOT_AFTER 9 +#define X509_OBJ_SUBJECT 10 +#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12 +#define X509_OBJ_SUBJECT_PUBLIC_KEY 13 +#define X509_OBJ_RSA_PUBLIC_KEY 14 +#define X509_OBJ_EXTN_ID 22 +#define X509_OBJ_CRITICAL 23 +#define X509_OBJ_EXTN_VALUE 24 +#define X509_OBJ_ALGORITHM 27 +#define X509_OBJ_SIGNATURE 28 +#define X509_OBJ_ROOF 29 + + +static u_char ASN1_subjectAltName_oid_str[] = { + 0x06, 0x03, 0x55, 0x1D, 0x11 +}; + +static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_subjectAltName_oid_str); + + +/** + * compare two X.509 x509s by comparing their signatures + */ +static bool equals(private_x509_t *this, private_x509_t *other) +{ + return chunk_equals(this->signature, other->signature); +} + +/** + * encode a linked list of subjectAltNames + */ +chunk_t build_subjectAltNames(generalName_t *subjectAltNames) +{ + u_char *pos; + chunk_t names; + size_t len = 0; + generalName_t *gn = subjectAltNames; + + /* compute the total size of the ASN.1 attributes object */ + while (gn != NULL) + { + len += gn->name.len; + gn = gn->next; + } + + pos = build_asn1_object(&names, ASN1_SEQUENCE, len); + + gn = subjectAltNames; + while (gn != NULL) + { + memcpy(pos, gn->name.ptr, gn->name.len); + pos += gn->name.len; + gn = gn->next; + } + + return asn1_wrap(ASN1_SEQUENCE, "cm", + ASN1_subjectAltName_oid, + asn1_wrap(ASN1_OCTET_STRING, "m", names) + ); +} + +/** + * free the dynamic memory used to store generalNames + */ +void free_generalNames(generalName_t* gn, bool free_name) +{ + while (gn != NULL) + { + generalName_t *gn_top = gn; + if (free_name) + { + free(gn->name.ptr); + } + gn = gn->next; + free(gn_top); + } +} + +/** + * extracts the basicConstraints extension + */ +static bool parse_basicConstraints(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + bool isCA = FALSE; + + asn1_init(&ctx, blob, level0, FALSE); + + while (objectID < BASIC_CONSTRAINTS_ROOF) { + + if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx)) + { + break; + } + if (objectID == BASIC_CONSTRAINTS_CA) + { + isCA = object.len && *object.ptr; + logger->log(logger, RAW|LEVEL1, " %s", isCA ? "TRUE" : "FALSE"); + } + objectID++; + } + return isCA; +} + +/** + * extracts one or several GNs and puts them into a chained list + */ +static void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, implicit); + + while (objectID < GENERAL_NAMES_ROOF) + { + if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx)) + return; + + if (objectID == GENERAL_NAMES_GN) + { + list->insert_last(list, identification_create_from_encoding(ID_DER_ASN1_GN, object)); + } + objectID++; + } + return; +} + +/** + * extracts and converts a UTCTIME or GENERALIZEDTIME object + */ +time_t parse_time(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE); + + while (objectID < TIME_ROOF) + { + if (!extract_object(timeObjects, &objectID, &object, &level, &ctx)) + return 0; + + if (objectID == TIME_UTC || objectID == TIME_GENERALIZED) + { + return asn1totime(&object, (objectID == TIME_UTC) + ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME); + } + objectID++; + } + return 0; +} + +/** + * extracts a keyIdentifier + */ +static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, implicit); + + extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx); + return object; +} + +/** + * extracts an authoritykeyIdentifier + */ +void parse_authorityKeyIdentifier(chunk_t blob, int level0 , chunk_t *authKeyID, chunk_t *authKeySerialNumber) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE); + while (objectID < AUTH_KEY_ID_ROOF) + { + if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx)) + { + return; + } + switch (objectID) + { + case AUTH_KEY_ID_KEY_ID: + *authKeyID = parse_keyIdentifier(object, level+1, TRUE); + break; + case AUTH_KEY_ID_CERT_ISSUER: + { + /* TODO: parse_generalNames(object, level+1, TRUE); */ + break; + } + case AUTH_KEY_ID_CERT_SERIAL: + *authKeySerialNumber = object; + break; + default: + break; + } + objectID++; + } +} + +/** + * extracts an authorityInfoAcess location + */ +static void parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessLocation) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + u_int accessMethod = OID_UNKNOWN; + + asn1_init(&ctx, blob, level0, FALSE); + while (objectID < AUTH_INFO_ACCESS_ROOF) + { + if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx)) + { + return; + } + switch (objectID) + { + case AUTH_INFO_ACCESS_METHOD: + accessMethod = known_oid(object); + break; + case AUTH_INFO_ACCESS_LOCATION: + { + switch (accessMethod) + { + case OID_OCSP: + if (*object.ptr == ASN1_CONTEXT_S_6) + { + if (asn1_length(&object) == ASN1_INVALID_LENGTH) + { + return; + } + logger->log(logger, RAW|LEVEL1, " '%.*s'",(int)object.len, object.ptr); + /* only HTTP(S) URIs accepted */ + if (strncasecmp(object.ptr, "http", 4) == 0) + { + *accessLocation = object; + return; + } + } + logger->log(logger, ERROR|LEVEL2, "ignoring OCSP InfoAccessLocation with unkown protocol"); + break; + default: + /* unkown accessMethod, ignoring */ + break; + } + break; + } + default: + break; + } + objectID++; + } +} + +/** + * extracts extendedKeyUsage OIDs + */ +static bool parse_extendedKeyUsage(chunk_t blob, int level0) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE); + while (objectID < EXT_KEY_USAGE_ROOF) + { + if (!extract_object(extendedKeyUsageObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + if (objectID == EXT_KEY_USAGE_PURPOSE_ID && + known_oid(object) == OID_OCSP_SIGNING) + { + return TRUE; + } + objectID++; + } + return FALSE; +} + +/** + * extracts one or several crlDistributionPoints and puts them into + * a chained list + */ +static void parse_crlDistributionPoints(chunk_t blob, int level0, linked_list_t *list) +{ + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE); + while (objectID < CRL_DIST_POINTS_ROOF) + { + if (!extract_object(crlDistributionPointsObjects, &objectID, &object, &level, &ctx)) + { + return; + } + if (objectID == CRL_DIST_POINTS_FULLNAME) + { + /* append extracted generalNames to existing chained list */ + parse_generalNames(object, level+1, TRUE, list); + + } + objectID++; + } +} + + +/** + * Parses an X.509v3 x509 + */ +bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert) +{ + asn1_ctx_t ctx; + bool critical; + chunk_t object; + u_int level; + u_int extn_oid = OID_UNKNOWN; + int objectID = 0; + + asn1_init(&ctx, blob, level0, FALSE); + while (objectID < X509_OBJ_ROOF) + { + if (!extract_object(certObjects, &objectID, &object, &level, &ctx)) + { + return FALSE; + } + /* those objects which will parsed further need the next higher level */ + level++; + switch (objectID) { + case X509_OBJ_CERTIFICATE: + cert->x509 = object; + break; + case X509_OBJ_TBS_CERTIFICATE: + cert->tbsCertificate = object; + break; + case X509_OBJ_VERSION: + cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + logger->log(logger, RAW|LEVEL1, " v%d", cert->version); + break; + case X509_OBJ_SERIAL_NUMBER: + cert->serialNumber = object; + break; + case X509_OBJ_SIG_ALG: + cert->sigAlg = parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_ISSUER: + cert->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); + break; + case X509_OBJ_NOT_BEFORE: + cert->notBefore = parse_time(object, level); + break; + case X509_OBJ_NOT_AFTER: + cert->notAfter = parse_time(object, level); + break; + case X509_OBJ_SUBJECT: + cert->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); + break; + case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: + if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION) + { + cert->subjectPublicKeyAlgorithm = RSA_DIGITAL_SIGNATURE; + } + else + { + logger->log(logger, ERROR|LEVEL1, " unsupported public key algorithm"); + return FALSE; + } + break; + case X509_OBJ_SUBJECT_PUBLIC_KEY: + if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00) + { + /* skip initial bit string octet defining 0 unused bits */ + ctx.blobs[4].ptr++; ctx.blobs[4].len--; + } + else + { + logger->log(logger, ERROR|LEVEL1, " invalid RSA public key format"); + return FALSE; + } + break; + case X509_OBJ_RSA_PUBLIC_KEY: + cert->subjectPublicKey = object; + break; + case X509_OBJ_EXTN_ID: + extn_oid = known_oid(object); + break; + case X509_OBJ_CRITICAL: + critical = object.len && *object.ptr; + logger->log(logger, ERROR|LEVEL1, " %s", critical ? "TRUE" : "FALSE"); + break; + case X509_OBJ_EXTN_VALUE: + { + switch (extn_oid) { + case OID_SUBJECT_KEY_ID: + cert->subjectKeyID = parse_keyIdentifier(object, level, FALSE); + break; + case OID_SUBJECT_ALT_NAME: + parse_generalNames(object, level, FALSE, cert->subjectAltNames); + break; + case OID_BASIC_CONSTRAINTS: + cert->isCA = parse_basicConstraints(object, level); + break; + case OID_CRL_DISTRIBUTION_POINTS: + parse_crlDistributionPoints(object, level, cert->crlDistributionPoints); + break; + case OID_AUTHORITY_KEY_ID: + parse_authorityKeyIdentifier(object, level , &cert->authKeyID, &cert->authKeySerialNumber); + break; + case OID_AUTHORITY_INFO_ACCESS: + parse_authorityInfoAccess(object, level, &cert->accessLocation); + break; + case OID_EXTENDED_KEY_USAGE: + cert->isOcspSigner = parse_extendedKeyUsage(object, level); + break; + case OID_NS_REVOCATION_URL: + case OID_NS_CA_REVOCATION_URL: + case OID_NS_CA_POLICY_URL: + case OID_NS_COMMENT: + if (!parse_asn1_simple_object(&object, ASN1_IA5STRING , level, oid_names[extn_oid].name)) + { + return FALSE; + } + break; + default: + break; + } + break; + } + case X509_OBJ_ALGORITHM: + cert->algorithm = parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_SIGNATURE: + cert->signature = object; + break; + default: + break; + } + objectID++; + } + time(&cert->installed); + return TRUE; +} + +/** + * verify the validity of a x509 by + * checking the notBefore and notAfter dates + */ +err_t check_validity(const private_x509_t *cert, time_t *until) +{ + time_t current_time; + + time(¤t_time); + + if (cert->notAfter < *until) + { + *until = cert->notAfter; + } + if (current_time < cert->notBefore) + { + return "x509 is not valid yet"; + } + if (current_time > cert->notAfter) + { + return "x509 has expired"; + } + else + { + return NULL; + } +} + +/** + * Implements x509_t.get_public_key + */ +static rsa_public_key_t *get_public_key(private_x509_t *this) +{ + return this->public_key->clone(this->public_key);; +} + +/** + * Implements x509_t.get_subject + */ +static identification_t *get_subject(private_x509_t *this) +{ + return this->subject; +} + +/** + * Implements x509_t.get_issuer + */ +static identification_t *get_issuer(private_x509_t *this) +{ + return this->issuer; +} + +/** + * destroy + */ +static void destroy(private_x509_t *this) +{ + identification_t *id; + while (this->subjectAltNames->remove_last(this->subjectAltNames, (void**)&id) == SUCCESS) + { + id->destroy(id); + } + this->subjectAltNames->destroy(this->subjectAltNames); + while (this->issuerAltNames->remove_last(this->issuerAltNames, (void**)&id) == SUCCESS) + { + id->destroy(id); + } + this->issuerAltNames->destroy(this->issuerAltNames); + while (this->crlDistributionPoints->remove_last(this->crlDistributionPoints, (void**)&id) == SUCCESS) + { + id->destroy(id); + } + this->crlDistributionPoints->destroy(this->crlDistributionPoints); + if (this->issuer) + { + this->issuer->destroy(this->issuer); + } + if (this->subject) + { + this->subject->destroy(this->subject); + } + if (this->public_key) + { + this->public_key->destroy(this->public_key); + } + free(this); +} + +/* + * Described in header. + */ +x509_t *x509_create_from_chunk(chunk_t chunk) +{ + private_x509_t *this = malloc_thing(private_x509_t); + + /* public functions */ + this->public.equals = (bool (*) (x509_t*,x509_t*))equals; + this->public.destroy = (void (*) (x509_t*))destroy; + this->public.get_public_key = (rsa_public_key_t* (*) (x509_t*))get_public_key; + this->public.get_subject = (identification_t* (*) (x509_t*))get_subject; + this->public.get_issuer = (identification_t* (*) (x509_t*))get_issuer; + + /* initialize */ + this->subjectPublicKey = CHUNK_INITIALIZER; + this->public_key = NULL; + this->subject = NULL; + this->issuer = NULL; + this->subjectAltNames = linked_list_create(this->subjectAltNames); + this->issuerAltNames = linked_list_create(this->issuerAltNames); + this->crlDistributionPoints = linked_list_create(this->crlDistributionPoints); + + /* we do not use a per-instance logger right now, since its not always accessible */ + logger = logger_manager->get_logger(logger_manager, ASN1); + + if (!is_asn1(chunk) || + !parse_x509cert(chunk, 0, this)) + { + destroy(this); + return NULL; + } + + this->public_key = rsa_public_key_create_from_chunk(this->subjectPublicKey); + if (this->public_key == NULL) + { + destroy(this); + return NULL; + } + + return &this->public; +} + +/* + * Described in header. + */ +x509_t *x509_create_from_file(char *filename) +{ + struct stat stb; + FILE *file; + char *buffer; + chunk_t chunk; + + if (stat(filename, &stb) == -1) + { + return NULL; + } + + buffer = alloca(stb.st_size); + + file = fopen(filename, "r"); + if (file == NULL) + { + return NULL; + } + + if (fread(buffer, stb.st_size, 1, file) == -1) + { + fclose(file); + return NULL; + } + fclose(file); + + chunk.ptr = buffer; + chunk.len = stb.st_size; + + return x509_create_from_chunk(chunk); +} diff --git a/src/charon/lib/crypto/x509.h b/src/charon/lib/crypto/x509.h new file mode 100755 index 000000000..077238eab --- /dev/null +++ b/src/charon/lib/crypto/x509.h @@ -0,0 +1,136 @@ +/** + * @file x509.h + * + * @brief Interface of x509_t. + * + */ + +/* + * 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 X509_H_ +#define X509_H_ + +#include <types.h> +#include <definitions.h> +#include <crypto/rsa/rsa_public_key.h> +#include <utils/identification.h> +#include <utils/iterator.h> + + +typedef struct x509_t x509_t; + +/** + * @brief X509 certificate. + * + * @b Constructors: + * - x509_create_from_chunk() + * - x509_create_from_file() + * + * @todo more code cleanup needed! + * @todo fix unimplemented functions... + * @todo handle memory management + * + * @ingroup transforms + */ +struct x509_t { + + /** + * @brief Get the RSA public key from the certificate. + * + * @param this calling object + * @return public_key + */ + rsa_public_key_t *(*get_public_key) (x509_t *this); + + /** + * @brief Get the certificate issuers ID. + * + * The resulting ID is always a identification_t + * of type ID_DER_ASN1_DN. + * + * @param this calling object + * @return issuers ID + */ + identification_t *(*get_issuer) (x509_t *this); + + /** + * @brief Get the subjects ID. + * + * The resulting ID is always a identification_t + * of type ID_DER_ASN1_DN. + * + * @param this calling object + * @return subjects ID + */ + identification_t *(*get_subject) (x509_t *this); + + /** + * @brief Check if a certificate is valid. + * + * This function uses the issuers public key to verify + * the validity of a certificate. + * + * @todo implement! + */ + bool (*verify) (x509_t *this, rsa_public_key_t *signer); + + /** + * @brief Get the key identifier of the public key. + * + * @todo implement! + */ + chunk_t (*get_subject_key_identifier) (x509_t *this); + + /** + * @brief Compare two certificates. + * + * Comparison is done via the certificates signature. + * + * @param this first cert for compare + * @param other second cert for compare + * @return TRUE if signature is equal + */ + bool (*equals) (x509_t *this, x509_t *other); + + /** + * @brief Destroys the certificate. + * + * @param this certificate to destroy + */ + void (*destroy) (x509_t *this); +}; + +/** + * @brief Read a x509 certificate from a DER encoded blob. + * + * @param chunk chunk containing DER encoded data + * @return created x509_t certificate, or NULL if invalid. + * + * @ingroup transforms + */ +x509_t *x509_create_from_chunk(chunk_t chunk); + +/** + * @brief Read a x509 certificate from a DER encoded file. + * + * @param filename file containing DER encoded data + * @return created x509_t certificate, or NULL if invalid. + * + * @ingroup transforms + */ +x509_t *x509_create_from_file(char *filename); + +#endif /* X509_H_ */ diff --git a/src/charon/lib/definitions.c b/src/charon/lib/definitions.c new file mode 100644 index 000000000..59c97a29b --- /dev/null +++ b/src/charon/lib/definitions.c @@ -0,0 +1,40 @@ +/** + * @file definitions.c + * + * @brief General purpose definitions and macros. + * + */ + +/* + * 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 "definitions.h" + +/* + * Described in header. + */ +char *mapping_find(mapping_t * maps, int value) +{ + int i = 0; + while (maps[i].value != MAPPING_END) + { + if (maps[i].value == value) + { + return maps[i].string; + } + i++; + } + return "INVALID MAPPING"; +} diff --git a/src/charon/lib/definitions.h b/src/charon/lib/definitions.h new file mode 100644 index 000000000..c9ef066c1 --- /dev/null +++ b/src/charon/lib/definitions.h @@ -0,0 +1,120 @@ +/** + * @file definitions.h + * + * @brief General purpose definitions and macros. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * Copyright (C) 1998, 1999 D. Hugh Redelmeier. (Endian stuff) + * + * 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 DEFINITIONS_H_ +#define DEFINITIONS_H_ + + + +/* stolen from strongswan */ +#if linux +# if defined(i386) && !defined(__i386__) +# define __i386__ 1 +# define MYHACKFORTHIS 1 +# endif +# include <endian.h> +# ifdef MYHACKFORTHIS +# undef __i386__ +# undef MYHACKFORTHIS +# endif +#elif !(defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN) && defined(BYTE_ORDER)) + /* we don't know how to do this, so we require the macros to be defined + * with compiler flags: + * -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=BIG_ENDIAN + * or -DBIG_ENDIAN=4321 -DLITTLE_ENDIAN=1234 -DBYTE_ORDER=LITTLE_ENDIAN + * Thse match the GNU definitions + */ +# include <sys/endian.h> +#endif + +#ifndef BIG_ENDIAN + #error "BIG_ENDIAN must be defined" +#endif + +#ifndef LITTLE_ENDIAN + #error "LITTLE_ENDIAN must be defined" +#endif + +#ifndef BYTE_ORDER + #error "BYTE_ORDER must be defined" +#endif + + +/** + * Macro gives back larger of two values. + */ +#define max(x,y) (x > y ? x : y) + +/** + * Macro gives back smaller of two values. + */ +#define min(x,y) (x < y ? x : y) + +/** + * Debug macro to follow control flow + */ +#define POS printf("%s, line %d\n", __FILE__, __LINE__) + +/** + * Macro to allocate a sized type. + * + * @param thing object on which a sizeof is performed + * @return poiner to allocated memory + */ +#define malloc_thing(thing) ((thing*)malloc(sizeof(thing))) + + +/** + * Mapping entry which defines the end of a mapping_t array. + */ +#define MAPPING_END (-1) + +typedef struct mapping_t mapping_t; + +/** + * @brief Mapping entry, where enum-to-string mappings are stored. + */ +struct mapping_t +{ + /** + * Enumeration value. + */ + int value; + + /** + * Mapped string. + */ + char *string; +}; + + +/** + * @brief Find a mapping_string in the mapping[]. + * + * @param mappings mappings array + * @param value enum-value to get the string from + * + */ +char *mapping_find(mapping_t *mappings, int value); + +#endif /*DEFINITIONS_H_*/ diff --git a/src/charon/lib/library.c b/src/charon/lib/library.c new file mode 100644 index 000000000..fa9c732bf --- /dev/null +++ b/src/charon/lib/library.c @@ -0,0 +1,42 @@ +/** + * @file library.c + * + * @brief Library (de-)initialization. + * + */ + +/* + * 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 <utils/logger_manager.h> +#include <utils/leak_detective.h> + +/** + * Called whenever the library is linked from a process + */ +void __attribute__ ((constructor)) library_init() +{ + logger_manager_init(); + leak_detective_init(); +} + +/** + * Called whenever the library is unlinked from a process + */ +void __attribute__ ((destructor)) library_cleanup() +{ + leak_detective_cleanup(); + logger_manager_cleanup(); +} diff --git a/src/charon/lib/library.h b/src/charon/lib/library.h new file mode 100644 index 000000000..da96befe1 --- /dev/null +++ b/src/charon/lib/library.h @@ -0,0 +1,100 @@ +/** + * @file library.h + * + * @brief Global library header. + * + */ + +/* + * 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 LIBRARY_H_ +#define LIBRARY_H_ + +/** + * @defgroup lib lib + * + * libstrongswan: library with various crypto related things. + */ + +/** + * @defgroup asn1 asn1 + * + * ASN1 definitions, parser and generator functions. + * + * @ingroup lib + */ + +/** + * @defgroup crypto crypto + * + * Crypto algorithms of different kind. + * + * @ingroup lib + */ + +/** + * @defgroup crypters crypters + * + * Symmetric encryption algorithms, used for + * encryption and decryption. + * + * @ingroup crypto + */ + +/** + * @defgroup hashers hashers + * + * Hashing algorithms, such as MD5 or SHA1 + * + * @ingroup crypto + */ + +/** + * @defgroup prfs prfs + * + * Pseudo random functions, used to generate + * pseude random byte sequences. + * + * @ingroup crypto + */ + +/** + * @defgroup rsa rsa + * + * RSA private/public key algorithm. + * + * @ingroup crypto + */ + +/** + * @defgroup signers signers + * + * Symmetric signing algorithms, + * used to ensure message integrity. + * + * @ingroup crypto + */ + +/** + * @defgroup utils utils + * + * Generic helper classes. + * + * @ingroup lib + */ + + +#endif /* LIBRARY_H_ */ diff --git a/src/charon/lib/types.c b/src/charon/lib/types.c new file mode 100644 index 000000000..09ebf7310 --- /dev/null +++ b/src/charon/lib/types.c @@ -0,0 +1,115 @@ +/** + * @file types.c + * + * @brief Generic types. + * + */ + +/* + * 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 <string.h> + +#include "types.h" + + +/** + * String mappings for type status_t. + */ +mapping_t status_m[] = { + {SUCCESS, "SUCCESS"}, + {FAILED, "FAILED"}, + {OUT_OF_RES, "OUT_OF_RES"}, + {ALREADY_DONE, "ALREADY_DONE"}, + {NOT_SUPPORTED, "NOT_SUPPORTED"}, + {INVALID_ARG, "INVALID_ARG"}, + {NOT_FOUND, "NOT_FOUND"}, + {PARSE_ERROR, "PARSE_ERROR"}, + {VERIFY_ERROR, "VERIFY_ERROR"}, + {INVALID_STATE, "INVALID_STATE"}, + {DELETE_ME, "DELETE_ME"}, + {CREATED, "CREATED"}, + {MAPPING_END, NULL} +}; + +/** + * Empty chunk. + */ +chunk_t CHUNK_INITIALIZER = {NULL,0}; + +/** + * Described in header. + */ +chunk_t chunk_clone(chunk_t chunk) +{ + chunk_t clone = CHUNK_INITIALIZER; + + if (chunk.ptr && chunk.len > 0) + { + clone.ptr = malloc(chunk.len); + clone.len = chunk.len; + memcpy(clone.ptr, chunk.ptr, chunk.len); + } + + return clone; +} + +/** + * Described in header. + */ +void chunk_free(chunk_t *chunk) +{ + free(chunk->ptr); + chunk->ptr = NULL; + chunk->len = 0; +} + +/** + * Described in header. + */ +chunk_t chunk_alloc(size_t bytes) +{ + chunk_t new_chunk; + new_chunk.ptr = malloc(bytes); + new_chunk.len = bytes; + return new_chunk; +} + +/** + * Described in header. + */ +bool chunk_equals(chunk_t a, chunk_t b) +{ + if (a.ptr == NULL || b.ptr == NULL || + a.len != b.len || + memcmp(a.ptr, b.ptr, a.len) != 0) + { + return FALSE; + } + return TRUE; +} + +/** + * Described in header. + */ +void *clalloc(void * pointer, size_t size) +{ + void *data; + data = malloc(size); + + memcpy(data, pointer,size); + + return (data); +} diff --git a/src/charon/lib/types.h b/src/charon/lib/types.h new file mode 100644 index 000000000..0e0782b31 --- /dev/null +++ b/src/charon/lib/types.h @@ -0,0 +1,186 @@ +/** + * @file types.h + * + * @brief Generic types. + * + */ + +/* + * 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. + */ + + +#ifndef TYPES_H_ +#define TYPES_H_ + +#include <gmp.h> +#include <sys/types.h> +#include <stdlib.h> + +#include <definitions.h> + +/** + * General purpose boolean type. + */ +typedef int bool; +#define FALSE 0 +#define TRUE 1 + +typedef enum status_t status_t; + +/** + * Return values of function calls. + */ +enum status_t { + /** + * Call succeeded. + */ + SUCCESS, + + /** + * Call failed. + */ + FAILED, + + /** + * Out of ressources. + */ + + OUT_OF_RES, + /** + * Already done. + */ + ALREADY_DONE, + + /** + * Not supported. + */ + NOT_SUPPORTED, + + /** + * One of the arguments is invalid. + */ + INVALID_ARG, + + /** + * Something could not be found. + */ + NOT_FOUND, + + /** + * Error while parsing. + */ + PARSE_ERROR, + + /** + * Error while verifying. + */ + VERIFY_ERROR, + + /** + * Object in invalid state. + */ + INVALID_STATE, + + /** + * Delete object which function belongs to. + */ + DELETE_ME, + + /** + * An object got created. + */ + CREATED, +}; + + +/** + * String mappings for type status_t. + */ +extern mapping_t status_m[]; + +/** + * Handle struct timeval like an own type. + */ +typedef struct timeval timeval_t; + +/** + * Handle struct timespec like an own type. + */ +typedef struct timespec timespec_t; + +/** + * Handle struct chunk_t like an own type. + */ +typedef struct sockaddr sockaddr_t; + +/** + * Use struct chunk_t as chunk_t. + */ +typedef struct chunk_t chunk_t; + +/** + * General purpose pointer/length abstraction. + */ +struct chunk_t { + /** + * Pointer to start of data + */ + u_char *ptr; + + /** + * Length of data in bytes + */ + size_t len; +}; + +/** + * {NULL, 0}-chunk, handy for initialization + * of chunks. + */ +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); + +/** + * Free contents of a chunk + */ +void chunk_free(chunk_t *chunk); + +/** + * Allocate a chunk + */ +chunk_t chunk_alloc(size_t bytes); + +/** + * Compare two chunks for equality, + * NULL chunks are never equal. + */ +bool chunk_equals(chunk_t a, chunk_t b); + +/** + * Clone a data to a newly allocated buffer + */ +void *clalloc(void *pointer, size_t size); + + +#endif /*TYPES_H_*/ diff --git a/src/charon/lib/utils/Makefile.utils b/src/charon/lib/utils/Makefile.utils new file mode 100644 index 000000000..1c82283d7 --- /dev/null +++ b/src/charon/lib/utils/Makefile.utils @@ -0,0 +1,47 @@ +# 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. +# + +UTILS_DIR= $(LIB_DIR)utils/ + +LIB_OBJS+= $(BUILD_DIR)leak_detective.o +$(BUILD_DIR)leak_detective.o : $(UTILS_DIR)leak_detective.c $(UTILS_DIR)leak_detective.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)linked_list.o +$(BUILD_DIR)linked_list.o : $(UTILS_DIR)linked_list.c $(UTILS_DIR)linked_list.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)logger.o +$(BUILD_DIR)logger.o : $(UTILS_DIR)logger.c $(UTILS_DIR)logger.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)logger_manager.o +$(BUILD_DIR)logger_manager.o : $(UTILS_DIR)logger_manager.c $(UTILS_DIR)logger_manager.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)randomizer.o +$(BUILD_DIR)randomizer.o : $(UTILS_DIR)randomizer.c $(UTILS_DIR)randomizer.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)tester.o +$(BUILD_DIR)tester.o : $(UTILS_DIR)tester.c $(UTILS_DIR)tester.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)identification.o +$(BUILD_DIR)identification.o : $(UTILS_DIR)identification.c $(UTILS_DIR)identification.h + $(CC) $(CFLAGS) -c -o $@ $< + +LIB_OBJS+= $(BUILD_DIR)host.o +$(BUILD_DIR)host.o : $(UTILS_DIR)host.c $(UTILS_DIR)host.h + $(CC) $(CFLAGS) -c -o $@ $<
\ No newline at end of file diff --git a/src/charon/lib/utils/host.c b/src/charon/lib/utils/host.c new file mode 100644 index 000000000..020ed27f3 --- /dev/null +++ b/src/charon/lib/utils/host.c @@ -0,0 +1,365 @@ +/** + * @file host.c + * + * @brief Implementation of host_t. + * + */ + +/* + * 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 <string.h> + +#include "host.h" + + +typedef struct private_host_t private_host_t; + +/** + * @brief Private Data of a host object. + */ +struct private_host_t { + /** + * Public data + */ + host_t public; + + /** + * Address family to use, such as AF_INET or AF_INET6 + */ + int family; + + /** + * string representation of host + */ + char *string; + + /** + * low-lewel structure, wich stores the address + */ + union { + struct sockaddr address; + struct sockaddr_in address4; + }; + /** + * length of address structure + */ + socklen_t socklen; +}; + + +/** + * implements host_t.get_sockaddr + */ +static sockaddr_t *get_sockaddr(private_host_t *this) +{ + return &(this->address); +} + +/** + * implements host_t.get_sockaddr_len + */ +static socklen_t *get_sockaddr_len(private_host_t *this) +{ + return &(this->socklen); +} + +/** + * Implementation of host_t.is_default_route. + */ +static bool is_default_route (private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + static u_int8_t default_route[4] = {0x00,0x00,0x00,0x00}; + + if (memcmp(default_route,&(this->address4.sin_addr.s_addr),4) == 0) + { + return TRUE; + } + return FALSE; + } + default: + { + /* empty chunk is returned */ + return FALSE; + } + } +} + +/** + * implements host_t.get_address + */ +static char *get_address(private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + char *string; + /* we need to clone it, since inet_ntoa overwrites + * internal buffer on subsequent calls + */ + free(this->string); + string = inet_ntoa(this->address4.sin_addr); + this->string = malloc(strlen(string)+1); + strcpy(this->string, string); + return this->string; + } + default: + { + return "(family not supported)"; + } + } +} + +/** + * Implementation of host_t.get_address_as_chunk. + */ +static chunk_t get_address_as_chunk(private_host_t *this) +{ + chunk_t address = CHUNK_INITIALIZER; + + switch (this->family) + { + case AF_INET: + { + /* allocate 4 bytes for IPV4 address*/ + address.ptr = malloc(4); + address.len = 4; + memcpy(address.ptr,&(this->address4.sin_addr.s_addr),4); + } + default: + { + /* empty chunk is returned */ + return address; + } + } +} + +static xfrm_address_t get_xfrm_addr(private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + return (xfrm_address_t)(this->address4.sin_addr.s_addr); + } + default: + { + /* todo */ + return (xfrm_address_t)(this->address4.sin_addr.s_addr); + } + } +} + +static int get_family(private_host_t *this) +{ + return this->family; +} + +/** + * implements host_t.get_port + */ +static u_int16_t get_port(private_host_t *this) +{ + switch (this->family) + { + case AF_INET: + { + return ntohs(this->address4.sin_port); + } + default: + { + return 0; + } + } +} + + +/** + * Implements host_t.clone. + */ +static private_host_t *clone(private_host_t *this) +{ + private_host_t *new = malloc_thing(private_host_t); + + + memcpy(new, this, sizeof(private_host_t)); + if (this->string) + { + new->string = malloc(strlen(this->string)+1); + strcpy(new->string, this->string); + } + return new; +} + +/** + * Impelements host_t.ip_equals + */ +static bool ip_equals(private_host_t *this, private_host_t *other) +{ + switch (this->family) + { + /* IPv4 */ + case AF_INET: + { + if ((this->address4.sin_family == other->address4.sin_family) && + (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr)) + { + return TRUE; + } + } + } + return FALSE; +} + +/** + * Impelements host_t.equals + */ +static bool equals(private_host_t *this, private_host_t *other) +{ + switch (this->family) + { + /* IPv4 */ + case AF_INET: + { + if ((this->address4.sin_family == other->address4.sin_family) && + (this->address4.sin_addr.s_addr == other->address4.sin_addr.s_addr) && + (this->address4.sin_port == other->address4.sin_port)) + { + return TRUE; + } + } + } + return FALSE; +} + +/** + * Implements host_t.destroy + */ +static void destroy(private_host_t *this) +{ + free(this->string); + free(this); +} + +/** + * Creates an empty host_t object + */ +static private_host_t *host_create_empty() +{ + private_host_t *this = malloc_thing(private_host_t); + + this->public.get_sockaddr = (sockaddr_t* (*) (host_t*))get_sockaddr; + this->public.get_sockaddr_len = (socklen_t*(*) (host_t*))get_sockaddr_len; + this->public.clone = (host_t* (*) (host_t*))clone; + this->public.get_family = (int (*) (host_t*))get_family; + this->public.get_xfrm_addr = (xfrm_address_t (*) (host_t *))get_xfrm_addr; + this->public.get_address = (char* (*) (host_t *))get_address; + this->public.get_address_as_chunk = (chunk_t (*) (host_t *)) get_address_as_chunk; + this->public.get_port = (u_int16_t (*) (host_t *))get_port; + this->public.ip_equals = (bool (*) (host_t *,host_t *)) ip_equals; + this->public.equals = (bool (*) (host_t *,host_t *)) equals; + this->public.is_default_route = (bool (*) (host_t *)) is_default_route; + this->public.destroy = (void (*) (host_t*))destroy; + + this->string = NULL; + + return this; +} + +/* + * Described in header. + */ +host_t *host_create(int family, char *address, u_int16_t port) +{ + private_host_t *this = host_create_empty(); + + this->family = family; + + switch (family) + { + /* IPv4 */ + case AF_INET: + { + this->address4.sin_family = AF_INET; + this->address4.sin_addr.s_addr = inet_addr(address); + this->address4.sin_port = htons(port); + this->socklen = sizeof(struct sockaddr_in); + return &(this->public); + } + default: + { + free(this); + return NULL; + + } + } + +} + +/* + * Described in header. + */ +host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port) +{ + private_host_t *this = host_create_empty(); + + this->family = family; + switch (family) + { + /* IPv4 */ + case AF_INET: + { + if (address.len != 4) + { + break; + } + this->address4.sin_family = AF_INET; + memcpy(&(this->address4.sin_addr.s_addr),address.ptr,4); + this->address4.sin_port = htons(port); + this->socklen = sizeof(struct sockaddr_in); + return &(this->public); + } + } + free(this); + return NULL; +} + +/* + * Described in header. + */ +host_t *host_create_from_sockaddr(sockaddr_t *sockaddr) +{ + chunk_t address; + + switch (sockaddr->sa_family) + { + /* IPv4 */ + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)sockaddr; + address.ptr = (void*)&(sin->sin_addr.s_addr); + address.len = 4; + return host_create_from_chunk(AF_INET, address, ntohs(sin->sin_port)); + } + default: + return NULL; + } +} + diff --git a/src/charon/lib/utils/host.h b/src/charon/lib/utils/host.h new file mode 100644 index 000000000..d81efffa6 --- /dev/null +++ b/src/charon/lib/utils/host.h @@ -0,0 +1,225 @@ +/** + * @file host.h + * + * @brief Interface of host_t. + * + */ + +/* + * 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. + */ + +#ifndef HOST_H_ +#define HOST_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <linux/xfrm.h> + +#include <types.h> + + +typedef struct host_t host_t; + +/** + * @brief Representates a Host + * + * Host object, identifies a address:port pair and defines some + * useful functions on it. + * + * @b Constructors: + * - host_create() + * - host_create_from_chunk() + * - host_create_from_sockaddr() + * + * @todo Add IPv6 support + * + * @ingroup network + */ +struct host_t { + + /** + * @brief Build a clone of this host object. + * + * @param this object to clone + * @return cloned host + */ + host_t *(*clone) (host_t *this); + + /** + * @brief Get a pointer to the internal sockaddr struct. + * + * This is used for sending and receiving via sockets. + * + * @param this object to clone + * @return pointer to the internal sockaddr structure + */ + sockaddr_t *(*get_sockaddr) (host_t *this); + + /** + * @brief Get the length of the sockaddr struct. + * + * Sepending on the family, the length of the sockaddr struct + * is different. Use this function to get the length of the sockaddr + * struct returned by get_sock_addr. + * + * This is used for sending and receiving via sockets. + * + * @param this object to clone + * @return length of the sockaddr struct + */ + socklen_t *(*get_sockaddr_len) (host_t *this); + + /** + * @brief Gets the address as xfrm_address_t. + * + * This function allows the conversion to an + * xfrm_address_t, used for netlink communication + * with the kernel. + * + * @see kernel_interface_t. + * + * @param this calling object + * @return address in xfrm_address_t format + */ + xfrm_address_t (*get_xfrm_addr) (host_t *this); + + /** + * @brief Gets the family of the address + * + * @param this calling object + * @return family + */ + int (*get_family) (host_t *this); + + /** + * @brief get the address of this host + * + * Mostly used for debugging purposes. + * @warning string must NOT be freed + * + * @param this object + * @return address string, + */ + char* (*get_address) (host_t *this); + + /** + * @brief Checks if the ip address of host is set to default route. + * + * @param this calling object + * @return + * - TRUE if host has IP 0.0.0.0 for default route + * - FALSE otherwise + */ + bool (*is_default_route) (host_t *this); + + /** + * @brief get the address of this host as chunk_t + * + * @warning returned chunk has to get destroyed by caller. + * + * @param this object + * @return address string, + */ + chunk_t (*get_address_as_chunk) (host_t *this); + + /** + * @brief get the port of this host + * + * Mostly used for debugging purposes. + * + * @param this object to clone + * @return port number + */ + u_int16_t (*get_port) (host_t *this); + + /** + * @brief Compare the ips of two hosts hosts. + * + * @param this object to compare + * @param other the other to compare + * @return TRUE if addresses are equal. + */ + bool (*ip_equals) (host_t *this, host_t *other); + + /** + * @brief Compare two hosts, with port. + * + * @param this object to compare + * @param other the other to compare + * @return TRUE if addresses and ports are equal. + */ + bool (*equals) (host_t *this, host_t *other); + + /** + * @brief Destroy this host object + * + * @param this calling + * @return SUCCESS in any case + */ + void (*destroy) (host_t *this); +}; + +/** + * @brief Constructor to create a host_t object from an address string + * + * Currently supports only IPv4! + * + * @param family Address family to use for this object, such as AF_INET or AF_INET6 + * @param address string of an address, such as "152.96.193.130" + * @param port port number + * @return + * - host_t object + * - NULL, if family not supported. + * + * @ingroup network + */ +host_t *host_create(int family, char *address, u_int16_t port); + +/** + * @brief Constructor to create a host_t object from an address chunk + * + * Currently supports only IPv4! + * + * @param family Address family to use for this object, such as AF_INET or AF_INET6 + * @param address address as 4 byte chunk_t in networ order + * @param port port number + * @return + * - host_t object + * - NULL, if family not supported or chunk_t length not 4 bytes. + * + * @ingroup network + */ +host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); + +/** + * @brief Constructor to create a host_t object from a sockaddr struct + * + * Currently supports only IPv4! + * + * @param sockaddr sockaddr struct which contains family, address and port + * @return + * - host_t object + * - NULL, if family not supported. + * + * @ingroup network + */ +host_t *host_create_from_sockaddr(sockaddr_t *sockaddr); + + +#endif /*HOST_H_*/ diff --git a/src/charon/lib/utils/identification.c b/src/charon/lib/utils/identification.c new file mode 100644 index 000000000..33f3d92cd --- /dev/null +++ b/src/charon/lib/utils/identification.c @@ -0,0 +1,1167 @@ +/** + * @file identification.c + * + * @brief Implementation of identification_t. + * + */ + +/* + * 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. + */ + +#define _GNU_SOURCE +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> + +#include "identification.h" + +#include <asn1/asn1.h> + +/** + * String mappings for id_type_t. + */ +mapping_t id_type_m[] = { + {ID_IPV4_ADDR, "ID_IPV4_ADDR"}, + {ID_FQDN, "ID_FQDN"}, + {ID_RFC822_ADDR, "ID_RFC822_ADDR"}, + {ID_IPV6_ADDR, "ID_IPV6_ADDR"}, + {ID_DER_ASN1_DN, "ID_DER_ASN1_DN"}, + {ID_DER_ASN1_GN, "ID_DER_ASN1_GN"}, + {ID_KEY_ID, "ID_KEY_ID"}, + {ID_ANY, "ID_ANY"}, + {MAPPING_END, NULL} +}; + + +/** + * X.501 acronyms for well known object identifiers (OIDs) + */ +static u_char oid_ND[] = { + 0x02, 0x82, 0x06, 0x01, + 0x0A, 0x07, 0x14 +}; +static u_char oid_UID[] = { + 0x09, 0x92, 0x26, 0x89, 0x93, + 0xF2, 0x2C, 0x64, 0x01, 0x01 +}; +static u_char oid_DC[] = { + 0x09, 0x92, 0x26, 0x89, 0x93, + 0xF2, 0x2C, 0x64, 0x01, 0x19 +}; +static u_char oid_CN[] = { + 0x55, 0x04, 0x03 +}; +static u_char oid_S[] = { + 0x55, 0x04, 0x04 +}; +static u_char oid_SN[] = { + 0x55, 0x04, 0x05 +}; +static u_char oid_C[] = { + 0x55, 0x04, 0x06 +}; +static u_char oid_L[] = { + 0x55, 0x04, 0x07 +}; +static u_char oid_ST[] = { + 0x55, 0x04, 0x08 +}; +static u_char oid_O[] = { + 0x55, 0x04, 0x0A +}; +static u_char oid_OU[] = { + 0x55, 0x04, 0x0B +}; +static u_char oid_T[] = { + 0x55, 0x04, 0x0C +}; +static u_char oid_D[] = { + 0x55, 0x04, 0x0D +}; +static u_char oid_N[] = { + 0x55, 0x04, 0x29 +}; +static u_char oid_G[] = { + 0x55, 0x04, 0x2A +}; +static u_char oid_I[] = { + 0x55, 0x04, 0x2B +}; +static u_char oid_ID[] = { + 0x55, 0x04, 0x2D +}; +static u_char oid_EN[] = { + 0x60, 0x86, 0x48, 0x01, 0x86, + 0xF8, 0x42, 0x03, 0x01, 0x03 +}; +static u_char oid_E[] = { + 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x09, 0x01 +}; +static u_char oid_UN[] = { + 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x09, 0x02 +}; +static u_char oid_TCGID[] = { + 0x2B, 0x06, 0x01, 0x04, 0x01, 0x89, + 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B +}; + +/** + * coding of X.501 distinguished name + */ +typedef struct { + const u_char *name; + chunk_t oid; + u_char type; +} x501rdn_t; + +static const x501rdn_t x501rdns[] = { + {"ND", {oid_ND, 7}, ASN1_PRINTABLESTRING}, + {"UID", {oid_UID, 10}, ASN1_PRINTABLESTRING}, + {"DC", {oid_DC, 10}, ASN1_PRINTABLESTRING}, + {"CN", {oid_CN, 3}, ASN1_PRINTABLESTRING}, + {"S", {oid_S, 3}, ASN1_PRINTABLESTRING}, + {"SN", {oid_SN, 3}, ASN1_PRINTABLESTRING}, + {"serialNumber", {oid_SN, 3}, ASN1_PRINTABLESTRING}, + {"C", {oid_C, 3}, ASN1_PRINTABLESTRING}, + {"L", {oid_L, 3}, ASN1_PRINTABLESTRING}, + {"ST", {oid_ST, 3}, ASN1_PRINTABLESTRING}, + {"O", {oid_O, 3}, ASN1_PRINTABLESTRING}, + {"OU", {oid_OU, 3}, ASN1_PRINTABLESTRING}, + {"T", {oid_T, 3}, ASN1_PRINTABLESTRING}, + {"D", {oid_D, 3}, ASN1_PRINTABLESTRING}, + {"N", {oid_N, 3}, ASN1_PRINTABLESTRING}, + {"G", {oid_G, 3}, ASN1_PRINTABLESTRING}, + {"I", {oid_I, 3}, ASN1_PRINTABLESTRING}, + {"ID", {oid_ID, 3}, ASN1_PRINTABLESTRING}, + {"EN", {oid_EN, 10}, ASN1_PRINTABLESTRING}, + {"employeeNumber", {oid_EN, 10}, ASN1_PRINTABLESTRING}, + {"E", {oid_E, 9}, ASN1_IA5STRING}, + {"Email", {oid_E, 9}, ASN1_IA5STRING}, + {"emailAddress", {oid_E, 9}, ASN1_IA5STRING}, + {"UN", {oid_UN, 9}, ASN1_IA5STRING}, + {"unstructuredName",{oid_UN, 9}, ASN1_IA5STRING}, + {"TCGID", {oid_TCGID, 12}, ASN1_PRINTABLESTRING} +}; +#define X501_RDN_ROOF 26 + +/** + * Different kinds of generalNames + */ +enum generalNames_t { + GN_OTHER_NAME = 0, + GN_RFC822_NAME = 1, + GN_DNS_NAME = 2, + GN_X400_ADDRESS = 3, + GN_DIRECTORY_NAME = 4, + GN_EDI_PARTY_NAME = 5, + GN_URI = 6, + GN_IP_ADDRESS = 7, + GN_REGISTERED_ID = 8, +}; + +/** + * ASN.1 definition of generalName + */ +static const asn1Object_t generalNameObjects[] = { + { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ + { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ + { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ + { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */ + { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */ +}; +#define GN_OBJ_OTHER_NAME 0 +#define GN_OBJ_RFC822_NAME 2 +#define GN_OBJ_DNS_NAME 4 +#define GN_OBJ_X400_ADDRESS 6 +#define GN_OBJ_DIRECTORY_NAME 8 +#define GN_OBJ_EDI_PARTY_NAME 10 +#define GN_OBJ_URI 12 +#define GN_OBJ_IP_ADDRESS 14 +#define GN_OBJ_REGISTERED_ID 16 +#define GN_OBJ_ROOF 18 + +/** + * ASN.1 definition of otherName + */ +static const asn1Object_t otherNameObjects[] = { + {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ + {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */ +}; +#define ON_OBJ_ID_TYPE 0 +#define ON_OBJ_VALUE 1 +#define ON_OBJ_ROOF 2 + +typedef struct private_identification_t private_identification_t; + +/** + * Private data of an identification_t object. + */ +struct private_identification_t { + /** + * Public interface. + */ + identification_t public; + + /** + * String representation of this ID. + */ + char *string; + + /** + * Encoded representation of this ID. + */ + chunk_t encoded; + + /** + * Type of this ID. + */ + id_type_t type; +}; + +static private_identification_t *identification_create(); + + +/** + * updates a chunk (!????) + * TODO: We should reconsider this stuff, its not really clear + */ +static void update_chunk(chunk_t *ch, int n) +{ + n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1; + ch->ptr += n; ch->len -= n; +} + +/** + * Prints a binary string in hexadecimal form + */ +void hex_str(chunk_t bin, chunk_t *str) +{ + u_int i; + update_chunk(str, snprintf(str->ptr,str->len,"0x")); + for (i=0; i < bin.len; i++) + { + update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++)); + } +} + +/** + * Pointer is set to the first RDN in a DN + */ +static status_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next) +{ + *rdn = CHUNK_INITIALIZER; + *attribute = CHUNK_INITIALIZER; + + /* a DN is a SEQUENCE OF RDNs */ + if (*dn.ptr != ASN1_SEQUENCE) + { + /* DN is not a SEQUENCE */ + return FAILED; + } + + rdn->len = asn1_length(&dn); + + if (rdn->len == ASN1_INVALID_LENGTH) + { + /* Invalid RDN length */ + return FAILED; + } + + rdn->ptr = dn.ptr; + + /* are there any RDNs ? */ + *next = rdn->len > 0; + + return SUCCESS; +} + +/** + * Fetches the next RDN in a DN + */ +static status_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value, asn1_t *type, bool *next) +{ + chunk_t body; + + /* initialize return values */ + *oid = CHUNK_INITIALIZER; + *value = CHUNK_INITIALIZER; + + /* if all attributes have been parsed, get next rdn */ + if (attribute->len <= 0) + { + /* an RDN is a SET OF attributeTypeAndValue */ + if (*rdn->ptr != ASN1_SET) + { + /* RDN is not a SET */ + return FAILED; + } + attribute->len = asn1_length(rdn); + if (attribute->len == ASN1_INVALID_LENGTH) + { + /* Invalid attribute length */ + return FAILED; + } + attribute->ptr = rdn->ptr; + /* advance to start of next RDN */ + rdn->ptr += attribute->len; + rdn->len -= attribute->len; + } + + /* an attributeTypeAndValue is a SEQUENCE */ + if (*attribute->ptr != ASN1_SEQUENCE) + { + /* attributeTypeAndValue is not a SEQUENCE */ + return FAILED; + } + + /* extract the attribute body */ + body.len = asn1_length(attribute); + + if (body.len == ASN1_INVALID_LENGTH) + { + /* Invalid attribute body length */ + return FAILED; + } + + body.ptr = attribute->ptr; + + /* advance to start of next attribute */ + attribute->ptr += body.len; + attribute->len -= body.len; + + /* attribute type is an OID */ + if (*body.ptr != ASN1_OID) + { + /* attributeType is not an OID */ + return FAILED; + } + /* extract OID */ + oid->len = asn1_length(&body); + + if (oid->len == ASN1_INVALID_LENGTH) + { + /* Invalid attribute OID length */ + return FAILED; + } + oid->ptr = body.ptr; + + /* advance to the attribute value */ + body.ptr += oid->len; + body.len -= oid->len; + + /* extract string type */ + *type = *body.ptr; + + /* extract string value */ + value->len = asn1_length(&body); + + if (value->len == ASN1_INVALID_LENGTH) + { + /* Invalid attribute string length */ + return FAILED; + } + value->ptr = body.ptr; + + /* are there any RDNs left? */ + *next = rdn->len > 0 || attribute->len > 0; + return SUCCESS; +} + +/** + * Parses an ASN.1 distinguished name int its OID/value pairs + */ +static status_t dntoa(chunk_t dn, chunk_t *str) +{ + chunk_t rdn, oid, attribute, value; + asn1_t type; + int oid_code; + bool next; + bool first = TRUE; + + status_t status = init_rdn(dn, &rdn, &attribute, &next); + + if (status != SUCCESS) + {/* a parsing error has occured */ + return status; + } + + while (next) + { + status = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); + + if (status != SUCCESS) + {/* a parsing error has occured */ + return status; + } + + if (first) + { /* first OID/value pair */ + first = FALSE; + } + else + { /* separate OID/value pair by a comma */ + update_chunk(str, snprintf(str->ptr,str->len,", ")); + } + + /* print OID */ + oid_code = known_oid(oid); + if (oid_code == OID_UNKNOWN) + { /* OID not found in list */ + hex_str(oid, str); + } + else + { + update_chunk(str, snprintf(str->ptr,str->len,"%s", oid_names[oid_code].name)); + } + /* print value */ + update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", (int)value.len,value.ptr)); + } + return SUCCESS; +} + +/** + * compare two distinguished names by + * comparing the individual RDNs + */ +static bool same_dn(chunk_t a, chunk_t b) +{ + chunk_t rdn_a, rdn_b, attribute_a, attribute_b; + chunk_t oid_a, oid_b, value_a, value_b; + asn1_t type_a, type_b; + bool next_a, next_b; + + /* same lengths for the DNs */ + if (a.len != b.len) + { + return FALSE; + } + /* try a binary comparison first */ + if (memcmp(a.ptr, b.ptr, b.len) == 0) + { + return TRUE; + } + + /* initialize DN parsing */ + if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS || + init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS) + { + return FALSE; + } + + /* fetch next RDN pair */ + while (next_a && next_b) + { + /* parse next RDNs and check for errors */ + if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS || + get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS) + { + return FALSE; + } + /* OIDs must agree */ + if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) + { + return FALSE; + } + /* same lengths for values */ + if (value_a.len != value_b.len) + { + return FALSE; + } + /* printableStrings and email RDNs require uppercase comparison */ + if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || + (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) + { + if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } + else + { + if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } + } + /* both DNs must have same number of RDNs */ + if (next_a || next_b) + return FALSE; + + /* the two DNs are equal! */ + return TRUE; +} + + +/** + * compare two distinguished names by comparing the individual RDNs. + * A single'*' character designates a wildcard RDN in DN b. + * TODO: Add support for different RDN order in DN !! + */ +bool match_dn(chunk_t a, chunk_t b, int *wildcards) +{ + chunk_t rdn_a, rdn_b, attribute_a, attribute_b; + chunk_t oid_a, oid_b, value_a, value_b; + asn1_t type_a, type_b; + bool next_a, next_b; + + /* initialize wildcard counter */ + *wildcards = 0; + + /* initialize DN parsing */ + if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS || + init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS) + { + return FALSE; + } + /* fetch next RDN pair */ + while (next_a && next_b) + { + /* parse next RDNs and check for errors */ + if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS || + get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS) + { + return FALSE; + } + /* OIDs must agree */ + if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) + { + return FALSE; + } + /* does rdn_b contain a wildcard? */ + if (value_b.len == 1 && *value_b.ptr == '*') + { + (*wildcards)++; + continue; + } + /* same lengths for values */ + if (value_a.len != value_b.len) + { + return FALSE; + } + /* printableStrings and email RDNs require uppercase comparison */ + if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || + (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) + { + if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } + else + { + if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } + } + /* both DNs must have same number of RDNs */ + if (next_a || next_b) + { + return FALSE; + } + /* the two DNs match! */ + return TRUE; +} + +/** + * get string representation of a general name + * TODO: Add support for gn types + */ +static char *gntoa(chunk_t blob) +{ + asn1_ctx_t ctx; + chunk_t object; + int objectID = 0; + u_int level; + char buf[128]; + + asn1_init(&ctx, blob, 0, FALSE); + + while (objectID < GN_OBJ_ROOF) + { + if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx)) + { + return NULL; + } + switch (objectID) + { + case GN_OBJ_RFC822_NAME: + case GN_OBJ_DNS_NAME: + case GN_OBJ_URI: + snprintf(buf, sizeof(buf), "%.*s", object.len, object.ptr); + return strdup(buf); + case GN_OBJ_IP_ADDRESS: + if (object.len == 4 && + inet_ntop(AF_INET, object.ptr, buf, sizeof(buf))) + { + return strdup(buf); + } + return NULL; + break; + case GN_OBJ_OTHER_NAME: + return strdup("(other name)"); + case GN_OBJ_X400_ADDRESS: + return strdup("(X400 Address)"); + case GN_OBJ_EDI_PARTY_NAME: + return strdup("(EDI party name)"); + case GN_OBJ_REGISTERED_ID: + return strdup("(registered ID)"); + case GN_OBJ_DIRECTORY_NAME: + return strdup("(directory name)"); + default: + break; + } + objectID++; + } + return NULL; +} + +/** + * Converts an LDAP-style human-readable ASCII-encoded + * ASN.1 distinguished name into binary DER-encoded format + */ +static status_t atodn(char *src, chunk_t *dn) +{ + /* finite state machine for atodn */ + typedef enum { + SEARCH_OID = 0, + READ_OID = 1, + SEARCH_NAME = 2, + READ_NAME = 3, + UNKNOWN_OID = 4 + } state_t; + + char *wrap_mode; + chunk_t oid = CHUNK_INITIALIZER; + chunk_t name = CHUNK_INITIALIZER; + chunk_t names[25]; /* max to 25 rdns */ + int name_count = 0; + int whitespace = 0; + int pos = 0; + asn1_t rdn_type; + state_t state = SEARCH_OID; + status_t status = SUCCESS; + + do + { + switch (state) + { + case SEARCH_OID: + if (*src != ' ' && *src != '/' && *src != ',') + { + oid.ptr = src; + oid.len = 1; + state = READ_OID; + } + break; + case READ_OID: + if (*src != ' ' && *src != '=') + { + oid.len++; + } + else + { + for (pos = 0; pos < X501_RDN_ROOF; pos++) + { + if (strlen(x501rdns[pos].name) == oid.len && + strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0) + { + break; /* found a valid OID */ + } + } + if (pos == X501_RDN_ROOF) + { + status = NOT_SUPPORTED; + state = UNKNOWN_OID; + break; + } + /* reset oid and change state */ + oid = CHUNK_INITIALIZER; + state = SEARCH_NAME; + } + break; + case SEARCH_NAME: + if (*src != ' ' && *src != '=') + { + name.ptr = src; + name.len = 1; + whitespace = 0; + state = READ_NAME; + } + break; + case READ_NAME: + if (*src != ',' && *src != '/' && *src != '\0') + { + name.len++; + if (*src == ' ') + { + whitespace++; + } + else + { + whitespace = 0; + } + } + else + { + name.len -= whitespace; + rdn_type = (x501rdns[pos].type == ASN1_PRINTABLESTRING + && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type; + + if (name_count < 25) + { + names[name_count++] = + asn1_wrap(ASN1_SET, "m", + asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_wrap(ASN1_OID, "c", x501rdns[pos].oid), + asn1_wrap(rdn_type, "c", name) + ) + ); + } + else + { + status = OUT_OF_RES; + } + /* reset name and change state */ + name = CHUNK_INITIALIZER; + state = SEARCH_OID; + } + break; + case UNKNOWN_OID: + break; + } + } while (*src++ != '\0'); + + + /* build the distinguished name sequence */ + wrap_mode = alloca(26); + memset(wrap_mode, 0, 26); + memset(wrap_mode, 'm', name_count); + *dn = asn1_wrap(ASN1_SEQUENCE, wrap_mode, + names[0], names[1], names[2], names[3], names[4], + names[5], names[6], names[7], names[8], names[9], + names[10], names[11], names[12], names[13], names[14], + names[15], names[16], names[17], names[18], names[19], + names[20], names[21], names[22], names[23], names[24]); + if (status != SUCCESS) + { + free(dn->ptr); + *dn = CHUNK_INITIALIZER; + } + return status; +} + +/** + * Implementation of identification_t.get_encoding. + */ +static chunk_t get_encoding(private_identification_t *this) +{ + return this->encoded; +} + +/** + * Implementation of identification_t.get_type. + */ +static id_type_t get_type(private_identification_t *this) +{ + return this->type; +} + +/** + * Implementation of identification_t.get_string. + */ +static char *get_string(private_identification_t *this) +{ + return this->string; +} + +/** + * Implementation of identification_t.contains_wildcards. + */ +static bool contains_wildcards(private_identification_t *this) +{ + if (this->type == ID_ANY || + memchr(this->encoded.ptr, '*', this->encoded.len) != NULL) + { + return TRUE; + } + return FALSE; +} + +/** + * Default implementation of identification_t.equals and identification_t.belongs_to. + * compares encoded chunk for equality. + */ +static bool equals_binary(private_identification_t *this,private_identification_t *other) +{ + if (this->type == other->type) + { + if (this->encoded.len == other->encoded.len && + memcmp(this->encoded.ptr, other->encoded.ptr, this->encoded.len) == 0) + { + return TRUE; + } + } + return FALSE; +} + +/** + * Special implementation of identification_t.equals for ID_DER_ASN1_DN + */ +static bool equals_dn(private_identification_t *this, private_identification_t *other) +{ + return same_dn(this->encoded, other->encoded); +} + +/** + * Special implementation of identification_t.belongs_to for ID_RFC822_ADDR/ID_FQDN. + * checks for a wildcard in other-string, and compares it against this-string. + */ +static bool belongs_to_wc_string(private_identification_t *this, private_identification_t *other) +{ + char *this_str, *other_str, *pos; + + if (other->type == ID_ANY) + { + return TRUE; + } + + if (this->type == other->type) + { + /* try a binary comparison first */ + if (equals_binary(this, other)) + { + return TRUE; + } + } + if (other->encoded.len > 0 && + *(other->encoded.ptr) == '*') + { + if (other->encoded.len == 1) + { + /* other contains just a wildcard, and therefore matches anything */ + return TRUE; + } + /* We strdup chunks, since they are NOT null-terminated */ + this_str = strndupa(this->encoded.ptr, this->encoded.len); + other_str = strndupa(other->encoded.ptr + 1, other->encoded.len - 1); + pos = strstr(this_str, other_str); + if (pos != NULL) + { + /* ok, other is contained in this, but there may be more characters, so check it */ + if (strlen(pos) == strlen(other_str)) + { + return TRUE; + } + } + } + + return FALSE; +} + +/** + * Special implementation of identification_t.belongs_to for ID_ANY. + * ANY matches only another ANY, but nothing other + */ +static bool belongs_to_any(private_identification_t *this, private_identification_t *other) +{ + if (other->type == ID_ANY) + { + return TRUE; + } + return FALSE; +} + +/** + * Special implementation of identification_t.belongs_to for ID_DER_ASN1_DN. + * ANY matches any, even ANY, thats why its there... + */ +static bool belongs_to_dn(private_identification_t *this, private_identification_t *other) +{ + int wildcards; + + if (other->type == ID_ANY) + { + return TRUE; + } + + if (this->type == other->type) + { + return match_dn(this->encoded, other->encoded, &wildcards); + } + return FALSE; +} + +/** + * Implementation of identification_t.clone. + */ +static identification_t *clone(private_identification_t *this) +{ + private_identification_t *clone = identification_create(); + + clone->type = this->type; + clone->encoded = chunk_clone(this->encoded); + clone->string = malloc(strlen(this->string) + 1); + strcpy(clone->string, this->string); + + return &clone->public; +} + +/** + * Implementation of identification_t.destroy. + */ +static void destroy(private_identification_t *this) +{ + free(this->string); + free(this->encoded.ptr); + free(this); +} + +/** + * Generic constructor used for the other constructors. + */ +static private_identification_t *identification_create() +{ + private_identification_t *this = malloc_thing(private_identification_t); + + this->public.get_encoding = (chunk_t (*) (identification_t*))get_encoding; + this->public.get_type = (id_type_t (*) (identification_t*))get_type; + this->public.get_string = (char* (*) (identification_t*))get_string; + this->public.contains_wildcards = (bool (*) (identification_t *this))contains_wildcards; + this->public.clone = (identification_t* (*) (identification_t*))clone; + this->public.destroy = (void (*) (identification_t*))destroy; + /* we use these as defaults, the may be overloaded for special ID types */ + this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary; + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))equals_binary; + + this->string = NULL; + this->encoded = CHUNK_INITIALIZER; + + return this; +} + +/* + * Described in header. + */ +identification_t *identification_create_from_string(char *string) +{ + private_identification_t *this = identification_create(); + + if (strchr(string, '=') != NULL) + { + /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN. + * convert from LDAP style or openssl x509 -subject style to ASN.1 DN + * discard optional @ character in front of DN + */ + if (atodn((*string == '@') ? string + 1 : string, &this->encoded) != SUCCESS) + { + free(this); + return NULL; + } + this->string = strdup(string); + this->type = ID_DER_ASN1_DN; + this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn; + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn; + return &this->public; + } + else if (strchr(string, '@') == NULL) + { + if (strcmp(string, "%any") == 0 || + strcmp(string, "0.0.0.0") == 0 || + strcmp(string, "*") == 0 || + strcmp(string, "::") == 0|| + strcmp(string, "0::0") == 0) + { + /* any ID will be accepted */ + this->type = ID_ANY; + this->string = strdup("%any"); + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any; + return &this->public; + } + else + { + /* TODO: Pluto resolve domainnames without '@' to IPv4/6 address. Is this really needed? */ + + if (strchr(string, ':') == NULL) + { + /* try IPv4 */ + struct in_addr address; + chunk_t chunk = {(void*)&address, sizeof(address)}; + + if (inet_pton(AF_INET, string, &address) <= 0) + { + free(this); + return NULL; + } + this->encoded = chunk_clone(chunk); + this->string = strdup(string); + this->type = ID_IPV4_ADDR; + return &(this->public); + } + else + { + /* try IPv6 */ + struct in6_addr address; + chunk_t chunk = {(void*)&address, sizeof(address)}; + + if (inet_pton(AF_INET6, string, &address) <= 0) + { + free(this); + return NULL; + } + this->encoded = chunk_clone(chunk); + this->string = strdup(string); + this->type = ID_IPV6_ADDR; + return &(this->public); + } + } + } + else + { + if (*string == '@') + { + if (*(string + 1) == '#') + { + /* TODO: Pluto handles '#' as hex encoded ASN1/KEY ID. Do we need this, too? */ + free(this); + return NULL; + } + else + { + this->type = ID_FQDN; + this->string = strdup(string + 1); /* discard @ */ + this->encoded.ptr = strdup(string + 1); + this->encoded.len = strlen(string + 1); + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string; + return &(this->public); + } + } + else + { + this->type = ID_RFC822_ADDR; + this->string = strdup(string); + this->encoded.ptr = strdup(string); + this->encoded.len = strlen(string); + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string; + return &(this->public); + } + } +} + +/* + * Described in header. + */ +identification_t *identification_create_from_encoding(id_type_t type, chunk_t encoded) +{ + private_identification_t *this = identification_create(); + char buf[256]; + chunk_t buf_chunk = chunk_from_buf(buf); + char *pos; + + this->type = type; + switch (type) + { + case ID_ANY: + this->string = strdup("%any"); + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_any; + break; + case ID_IPV4_ADDR: + if (encoded.len < sizeof(struct in_addr) || + inet_ntop(AF_INET, encoded.ptr, buf, sizeof(buf)) == NULL) + { + this->string = strdup("(invalid ID_IPV4_ADDR)"); + } + else + { + this->string = strdup(buf); + } + break; + case ID_IPV6_ADDR: + if (encoded.len < sizeof(struct in6_addr) || + inet_ntop(AF_INET6, encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL) + { + this->string = strdup("(invalid ID_IPV6_ADDR)"); + } + else + { + this->string = strdup(buf); + } + break; + case ID_FQDN: + snprintf(buf, sizeof(buf), "@%.*s", encoded.len, encoded.ptr); + this->string = strdup(buf); + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string; + break; + case ID_RFC822_ADDR: + snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr); + this->string = strdup(buf); + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string; + break; + case ID_DER_ASN1_DN: + snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr); + /* TODO: whats returned on failure */ + dntoa(encoded, &buf_chunk); + this->string = strdup(buf); + this->public.equals = (bool (*) (identification_t*,identification_t*))equals_dn; + this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn; + break; + case ID_DER_ASN1_GN: + this->string = gntoa(encoded); + break; + case ID_KEY_ID: + this->string = strdup("(unparsed KEY_ID)"); + break; + default: + snprintf(buf, sizeof(buf), "(invalid ID type: %d)", type); + this->string = strdup(buf); + break; + } + + /* apply encoded chunk */ + if (type != ID_ANY) + { + this->encoded = chunk_clone(encoded); + } + + /* remove unprintable chars in string */ + for (pos = this->string; *pos != '\0'; pos++) + { + if (!isprint(*pos)) + { + *pos = '?'; + } + } + return &(this->public); +} diff --git a/src/charon/lib/utils/identification.h b/src/charon/lib/utils/identification.h new file mode 100644 index 000000000..309b6858c --- /dev/null +++ b/src/charon/lib/utils/identification.h @@ -0,0 +1,245 @@ +/** + * @file identification.h + * + * @brief Interface of identification_t. + * + */ + +/* + * 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. + */ + + +#ifndef IDENTIFICATION_H_ +#define IDENTIFICATION_H_ + + +#include "types.h" + +typedef enum id_type_t id_type_t; + +/** + * @brief ID Types in a ID payload. + * + * @ingroup utils + */ +enum id_type_t { + + /** + * ID data is a single four (4) octet IPv4 address. + */ + ID_IPV4_ADDR = 1, + + /** + * ID data is a fully-qualified domain name string. + * An example of a ID_FQDN is, "example.com". + * The string MUST not contain any terminators (e.g., NULL, CR, etc.). + */ + ID_FQDN = 2, + + /** + * ID data is a fully-qualified RFC822 email address string, An example of + * a ID_RFC822_ADDR is, "jsmith@example.com". The string MUST + * not contain any terminators. + */ + ID_RFC822_ADDR = 3, + + /** + * ID data is a single sixteen (16) octet IPv6 address. + */ + ID_IPV6_ADDR = 5, + + /** + * ID data is the binary DER encoding of an ASN.1 X.500 Distinguished Name + * [X.501]. + */ + ID_DER_ASN1_DN = 9, + + /** + * ID data is the binary DER encoding of an ASN.1 X.500 GeneralName + * [X.509]. + */ + ID_DER_ASN1_GN = 10, + + /** + * ID data is an opaque octet stream which may be used to pass vendor- + * specific information necessary to do certain proprietary + * types of identification. + */ + ID_KEY_ID = 11, + + /** + * Special type of PRIVATE USE which matches to any other id. + */ + ID_ANY = 201, +}; + +/** + * String mappings for id_type_t. + */ +extern mapping_t id_type_m[]; + +typedef struct identification_t identification_t; + +/** + * @brief Generic identification, such as used in ID payload. + * + * The following types are possible: + * - ID_IPV4_ADDR + * - ID_FQDN + * - ID_RFC822_ADDR + * - ID_IPV6_ADDR + * - ID_DER_ASN1_DN + * - ID_DER_ASN1_GN + * - ID_KEY_ID + * + * @b Constructors: + * - identification_create_from_string() + * - identification_create_from_encoding() + * + * @todo Support for ID_DER_ASN1_GN is minimal right now. Comparison + * between them and ID_IPV4_ADDR/RFC822_ADDR would be nice. + * + * @ingroup utils + */ +struct identification_t { + + /** + * @brief Get the encoding of this id, to send over + * the network. + * + * @warning Result points to internal data, do NOT free! + * + * @param this the identification_t object + * @return a chunk containing the encoded bytes + */ + chunk_t (*get_encoding) (identification_t *this); + + /** + * @brief Get the type of this identification. + * + * @param this the identification_t object + * @return id_type_t + */ + id_type_t (*get_type) (identification_t *this); + + /** + * @brief Get a string representation of this id. + * + * @warning Result points to internal data, do NOT free! + * + * @param this the identification_t object + * @return string + */ + char *(*get_string) (identification_t *this); + + /** + * @brief Check if two identification_t objects are equal. + * + * @param this the identification_t object + * @param other other identification_t object + * @return TRUE if the IDs are equal + */ + bool (*equals) (identification_t *this,identification_t *other); + + /** + * @brief Check if an ID belongs to a wildcard ID. + * + * An identification_t may contain wildcards, such as + * *@strongswan.org. This call checks if a given ID + * (e.g. tester@strongswan.org) belongs to a such wildcard + * ID. Returns TRUE if + * - IDs are identical + * - other is of type ID_ANY + * - other contains a wildcard and matches this + * + * @param this the ID without wildcard + * @param other the ID containing a wildcard + * @return TRUE if other belongs to this + */ + bool (*belongs_to) (identification_t *this, identification_t *other); + + /** + * @brief Check if an ID is a wildcard ID. + * + * If the ID represents multiple IDs (with wildcards, or + * as the type ID_ANY), TRUE is returned. If it is unique, + * FALSE is returned. + * + * @param this identification_t object + * @return TRUE if ID contains wildcards + */ + bool (*contains_wildcards) (identification_t *this); + + /** + * @brief Clone a identification_t instance. + * + * @param this the identification_t object to clone + * @return clone of this + */ + identification_t *(*clone) (identification_t *this); + + /** + * @brief Destroys a identification_t object. + * + * @param this identification_t object + */ + void (*destroy) (identification_t *this); +}; + +/** + * @brief Creates an identification_t object from a string. + * + * @param string input string, which will be converted + * @return + * - created identification_t object, or + * - NULL if unsupported string supplied. + * + * The input string may be e.g. one of the following: + * - ID_IPV4_ADDR: 192.168.0.1 + * - ID_IPV6_ADDR: 2001:0db8:85a3:08d3:1319:8a2e:0370:7345 + * - ID_FQDN: @www.strongswan.org (@indicates FQDN) + * - ID_RFC822_ADDR: alice@wonderland.org + * - ID_DER_ASN1_DN: C=CH, O=Linux strongSwan, CN=bob + * + * In favour of pluto, domainnames are prepended with an @, since + * pluto resolves domainnames without an @ to IPv4 addresses. Since + * we use a seperate host_t class for addresses, this doesn't + * make sense for us. + * + * A distinguished name may contain one or more of the following RDNs: + * ND, UID, DC, CN, S, SN, serialNumber, C, L, ST, O, OU, T, D, + * N, G, I, ID, EN, EmployeeNumber, E, Email, emailAddress, UN, + * unstructuredName, TCGID. + * + * @ingroup utils + */ +identification_t * identification_create_from_string(char *string); + +/** + * @brief Creates an identification_t object from an encoded chunk. + * + * @param type type of this id, such as ID_IPV4_ADDR + * @param encoded encoded bytes, such as from identification_t.get_encoding + * @return identification_t object + * + * In contrast to identification_create_from_string(), this constructor never + * returns NULL, even when the conversion to a sring representation fails. + * + * @ingroup utils + */ +identification_t * identification_create_from_encoding(id_type_t type, chunk_t encoded); + + +#endif /* IDENTIFICATION_H_ */ diff --git a/src/charon/lib/utils/iterator.h b/src/charon/lib/utils/iterator.h new file mode 100644 index 000000000..de81db8e9 --- /dev/null +++ b/src/charon/lib/utils/iterator.h @@ -0,0 +1,153 @@ +/** + * @file iterator.h + * + * @brief Interface iterator_t. + * + */ + +/* + * 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. + */ + +#ifndef ITERATOR_H_ +#define ITERATOR_H_ + +typedef struct iterator_t iterator_t; + +/** + * @brief Iterator interface, allows iteration over collections. + * + * iterator_t defines an interface for iterating over collections. + * It allows searching, deleting, updating and inserting. + * + * Thanks to JMP for iterator lessons :-) + * + * @b Constructors: + * - via linked_list_t.create_iterator, or + * - any other class which supports the iterator_t interface + * + * @see linked_list_t + * + * @ingroup utils + */ +struct iterator_t { + + /** + * @brief Iterate over all items. + * + * The easy way to iterate over items. + * + * @param this calling object + * @param[out] value item + * @return + * - TRUE, if more elements are avaiable, + * - FALSE otherwise + */ + bool (*iterate) (iterator_t *this, void** value); + + /** + * @brief Moves to the next element, if available. + * + * A newly created iterator_t object doesn't point to any item. + * Call iterator_t.has_next first to point it to the first item. + * + * @param this calling object + * @return + * - TRUE, if more elements are avaiable, + * - FALSE otherwise + */ + bool (*has_next) (iterator_t *this); + + /** + * @brief Returns the current value at the iterator position. + * + * @param this calling object + * @param[out] value value is set to the current value at iterator position + * @return + * - SUCCESS + * - FAILED if iterator on an invalid position + */ + status_t (*current) (iterator_t *this, void **value); + + /** + * @brief Inserts a new item before the given iterator position. + * + * The iterator position is not changed after inserting + * + * @param this calling iterator + * @param[in] item value to insert in list + */ + void (*insert_before) (iterator_t *this, void *item); + + /** + * @brief Inserts a new item after the given iterator position. + * + * The iterator position is not changed after inserting. + * + * @param this calling iterator + * @param[in] item value to insert in list + */ + void (*insert_after) (iterator_t *this, void *item); + + /** + * @brief Replace the current item at current iterator position. + * + * The iterator position is not changed after replacing. + * + * @param this calling iterator + * @param[out] old_item old value will be written here(can be NULL) + * @param[in] new_item new value + * + * @return + * - SUCCESS + * - FAILED if iterator is on an invalid position + */ + status_t (*replace) (iterator_t *this, void **old_item, void *new_item); + + /** + * @brief Removes an element from list at the given iterator position. + * + * The position of the iterator is set in the following order: + * - to the item before, if available + * - otherwise to the item after, if available + * - otherwise it gets reseted + * + * @param linked_list calling object + * @return + * - SUCCESS + * - FAILED if iterator is on an invalid position + */ + status_t (*remove) (iterator_t *iterator); + + /** + * @brief Resets the iterator position. + * + * After reset, the iterator_t objects doesn't point to an element. + * A call to iterator_t.has_next is necessary to do any other operations + * with the resetted iterator. + * + * @param this calling object + */ + void (*reset) (iterator_t *this); + + /** + * @brief Destroys an iterator. + * + * @param this iterator to destroy + * + */ + void (*destroy) (iterator_t *this); +}; + +#endif /*ITERATOR_H_*/ diff --git a/src/charon/lib/utils/leak_detective.c b/src/charon/lib/utils/leak_detective.c new file mode 100644 index 000000000..780ba4c05 --- /dev/null +++ b/src/charon/lib/utils/leak_detective.c @@ -0,0 +1,540 @@ +/** + * @file leak_detective.c + * + * @brief Allocation hooks to find memory leaks. + */ + +/* + * 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. + */ + +#include <stddef.h> +#include <string.h> +#include <stdio.h> +#include <malloc.h> +#include <execinfo.h> +#include <signal.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <dlfcn.h> +#include <unistd.h> +#include <syslog.h> +#include <pthread.h> + +#include "leak_detective.h" + +#include <types.h> +#include <utils/logger_manager.h> + +#ifdef LEAK_DETECTIVE + +/** + * Magic value which helps to detect memory corruption + */ +#define MEMORY_HEADER_MAGIC 0xF1367ADF + +static void install_hooks(void); +static void uninstall_hooks(void); +static void *malloc_hook(size_t, const void *); +static void *realloc_hook(void *, size_t, const void *); +static void free_hook(void*, const void *); +static void load_excluded_functions(); + +typedef struct memory_header_t memory_header_t; + +/** + * Header which is prepended to each allocated memory block + */ +struct memory_header_t { + /** + * Magci byte which must(!) hold MEMORY_HEADER_MAGIC + */ + u_int32_t magic; + + /** + * Number of bytes following after the header + */ + size_t bytes; + + /** + * Stack frames at the time of allocation + */ + void *stack_frames[STACK_FRAMES_COUNT]; + + /** + * Number of stacks frames obtained in stack_frames + */ + int stack_frame_count; + + /** + * Pointer to previous entry in linked list + */ + memory_header_t *previous; + + /** + * Pointer to next entry in linked list + */ + memory_header_t *next; +}; + +/** + * first mem header is just a dummy to chain + * the others on it... + */ +static memory_header_t first_header = { + magic: MEMORY_HEADER_MAGIC, + bytes: 0, + stack_frame_count: 0, + previous: NULL, + next: NULL +}; + +/** + * logger for the leak detective + */ +static logger_t *logger; + +/** + * standard hooks, used to temparily remove hooking + */ +static void *old_malloc_hook, *old_realloc_hook, *old_free_hook; + +/** + * are the hooks currently installed? + */ +static bool installed = FALSE; + +/** + * Mutex to exclusivly uninstall hooks, access heap list + */ +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + +/** + * log stack frames queried by backtrace() + * TODO: Dump symbols of static functions!!! + */ +static void log_stack_frames(void **stack_frames, int stack_frame_count) +{ + char **strings; + size_t i; + + strings = backtrace_symbols (stack_frames, stack_frame_count); + + logger->log(logger, ERROR, " dumping %d stack frame addresses.", stack_frame_count); + + for (i = 0; i < stack_frame_count; i++) + { + logger->log(logger, ERROR, " %s", strings[i]); + } + free (strings); +} + +/** + * Report leaks at library destruction + */ +void report_leaks() +{ + memory_header_t *hdr; + int leaks = 0; + + /* reaquire a logger is necessary, this will force ((destructor)) + * order to work correctly */ + logger = logger_manager->get_logger(logger_manager, LEAK_DETECT); + for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) + { + logger->log(logger, ERROR, "Leak (%d bytes at %p)", hdr->bytes, hdr + 1); + log_stack_frames(hdr->stack_frames, hdr->stack_frame_count); + leaks++; + } + + switch (leaks) + { + case 0: + logger->log(logger, CONTROL, "No leaks detected"); + break; + case 1: + logger->log(logger, ERROR, "One leak detected"); + break; + default: + logger->log(logger, ERROR, "%d leaks detected", leaks); + break; + } +} + +/** + * Installs the malloc hooks, enables leak detection + */ +static void install_hooks() +{ + if (!installed) + { + old_malloc_hook = __malloc_hook; + old_realloc_hook = __realloc_hook; + old_free_hook = __free_hook; + __malloc_hook = malloc_hook; + __realloc_hook = realloc_hook; + __free_hook = free_hook; + installed = TRUE; + } +} + +/** + * Uninstalls the malloc hooks, disables leak detection + */ +static void uninstall_hooks() +{ + if (installed) + { + __malloc_hook = old_malloc_hook; + __free_hook = old_free_hook; + __realloc_hook = old_realloc_hook; + installed = FALSE; + } +} + +/** + * Hook function for malloc() + */ +void *malloc_hook(size_t bytes, const void *caller) +{ + memory_header_t *hdr; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + hdr = malloc(bytes + sizeof(memory_header_t)); + + hdr->magic = MEMORY_HEADER_MAGIC; + hdr->bytes = bytes; + hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT); + + /* insert at the beginning of the list */ + hdr->next = first_header.next; + if (hdr->next) + { + hdr->next->previous = hdr; + } + hdr->previous = &first_header; + first_header.next = hdr; + install_hooks(); + pthread_mutex_unlock(&mutex); + return hdr + 1; +} + +/** + * Hook function for free() + */ +void free_hook(void *ptr, const void *caller) +{ + void *stack_frames[STACK_FRAMES_COUNT]; + int stack_frame_count; + memory_header_t *hdr = ptr - sizeof(memory_header_t); + + /* allow freeing of NULL */ + if (ptr == NULL) + { + return; + } + + pthread_mutex_lock(&mutex); + if (hdr->magic != MEMORY_HEADER_MAGIC) + { + pthread_mutex_unlock(&mutex); + /* TODO: since pthread_join cannot be excluded cleanly, we are not whining about bad frees */ + return; + logger->log(logger, ERROR, "freeing of invalid memory (%p)", ptr); + stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); + log_stack_frames(stack_frames, stack_frame_count); + return; + } + /* remove magic from hdr */ + hdr->magic = 0; + + /* remove item from list */ + if (hdr->next) + { + hdr->next->previous = hdr->previous; + } + hdr->previous->next = hdr->next; + + uninstall_hooks(); + free(hdr); + install_hooks(); + pthread_mutex_unlock(&mutex); +} + +/** + * Hook function for realloc() + */ +void *realloc_hook(void *old, size_t bytes, const void *caller) +{ + void *new; + memory_header_t *hdr = old - sizeof(memory_header_t); + void *stack_frames[STACK_FRAMES_COUNT]; + int stack_frame_count; + + /* allow reallocation of NULL */ + if (old == NULL) + { + return malloc_hook(bytes, caller); + } + if (hdr->magic != MEMORY_HEADER_MAGIC) + { + logger->log(logger, ERROR, "reallocation of invalid memory (%p)", old); + stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); + log_stack_frames(stack_frames, stack_frame_count); + kill(getpid(), SIGKILL); + return NULL; + } + + /* malloc and free is done with hooks */ + new = malloc_hook(bytes, caller); + memcpy(new, old, min(bytes, hdr->bytes)); + free_hook(old, caller); + + return new; +} + + +/** + * Setup leak detective + */ +void leak_detective_init() +{ + logger = logger_manager->get_logger(logger_manager, LEAK_DETECT); + load_excluded_functions(); + install_hooks(); +} + +/** + * Clean up leak detective + */ +void leak_detective_cleanup() +{ + uninstall_hooks(); + report_leaks(); +} + + +/** + * The following glibc functions are excluded from leak detection, since + * they use static allocated buffers or other ugly allocation hacks. + * For this to work, the linker must link libstrongswan preferred to + * the other (overriden) libs. + */ +struct excluded_function { + char *lib_name; + char *function_name; + void *handle; + void *lib_function; +} excluded_functions[] = { + {"libc.so.6", "inet_ntoa", NULL, NULL}, + {"libpthread.so.0", "pthread_create", NULL, NULL}, + {"libpthread.so.0", "pthread_cancel", NULL, NULL}, + {"libpthread.so.0", "pthread_join", NULL, NULL}, + {"libpthread.so.0", "_pthread_cleanup_push",NULL, NULL}, + {"libpthread.so.0", "_pthread_cleanup_pop", NULL, NULL}, + {"libc.so.6", "mktime", NULL, NULL}, + {"libc.so.6", "vsyslog", NULL, NULL}, + {"libc.so.6", "strerror", NULL, NULL}, +}; +#define INET_NTOA 0 +#define PTHREAD_CREATE 1 +#define PTHREAD_CANCEL 2 +#define PTHREAD_JOIN 3 +#define PTHREAD_CLEANUP_PUSH 4 +#define PTHREAD_CLEANUP_POP 5 +#define MKTIME 6 +#define VSYSLOG 7 +#define STRERROR 8 + + +/** + * Load libraries and function pointers for excluded functions + */ +static void load_excluded_functions() +{ + int i; + + for (i = 0; i < sizeof(excluded_functions)/sizeof(struct excluded_function); i++) + { + void *handle, *function; + handle = dlopen(excluded_functions[i].lib_name, RTLD_LAZY); + if (handle == NULL) + { + kill(getpid(), SIGSEGV); + } + + function = dlsym(handle, excluded_functions[i].function_name); + + if (function == NULL) + { + dlclose(handle); + kill(getpid(), SIGSEGV); + } + excluded_functions[i].handle = handle; + excluded_functions[i].lib_function = function; + } +} + +char *inet_ntoa(struct in_addr in) +{ + char *(*_inet_ntoa)(struct in_addr) = excluded_functions[INET_NTOA].lib_function; + char *result; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + result = _inet_ntoa(in); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return result; +} + +int pthread_create(pthread_t *__restrict __threadp, __const pthread_attr_t *__restrict __attr, + void *(*__start_routine) (void *), void *__restrict __arg) +{ + int (*_pthread_create) (pthread_t *__restrict __threadp, + __const pthread_attr_t *__restrict __attr, + void *(*__start_routine) (void *), + void *__restrict __arg) = excluded_functions[PTHREAD_CREATE].lib_function; + int result; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + result = _pthread_create(__threadp, __attr, __start_routine, __arg); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return result; +} + + +int pthread_cancel(pthread_t __th) +{ + int (*_pthread_cancel) (pthread_t) = excluded_functions[PTHREAD_CANCEL].lib_function; + int result; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + result = _pthread_cancel(__th); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return result; +} + +// /* TODO: join has probs, since it dellocates memory +// * allocated (somewhere) with leak_detective :-(. +// * We should exclude all pthread_ functions to fix it !? */ +// int pthread_join(pthread_t __th, void **__thread_return) +// { +// int (*_pthread_join) (pthread_t, void **) = excluded_functions[PTHREAD_JOIN].lib_function; +// int result; +// +// pthread_mutex_lock(&mutex); +// uninstall_hooks(); +// +// result = _pthread_join(__th, __thread_return); +// +// install_hooks(); +// pthread_mutex_unlock(&mutex); +// return result; +// } +// +// void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, +// void (*__routine) (void *), +// void *__arg) +// { +// int (*__pthread_cleanup_push) (struct _pthread_cleanup_buffer *__buffer, +// void (*__routine) (void *), +// void *__arg) = +// excluded_functions[PTHREAD_CLEANUP_PUSH].lib_function; +// +// pthread_mutex_lock(&mutex); +// uninstall_hooks(); +// +// __pthread_cleanup_push(__buffer, __routine, __arg); +// +// install_hooks(); +// pthread_mutex_unlock(&mutex); +// return; +// } +// +// void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, int __execute) +// { +// int (*__pthread_cleanup_pop) (struct _pthread_cleanup_buffer *__buffer, int __execute) = +// excluded_functions[PTHREAD_CLEANUP_POP].lib_function; +// +// pthread_mutex_lock(&mutex); +// uninstall_hooks(); +// +// __pthread_cleanup_pop(__buffer, __execute); +// +// install_hooks(); +// pthread_mutex_unlock(&mutex); +// return; +// } + +time_t mktime(struct tm *tm) +{ + time_t (*_mktime)(struct tm *tm) = excluded_functions[MKTIME].lib_function; + time_t result; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + result = _mktime(tm); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return result; +} + +void vsyslog (int __pri, __const char *__fmt, __gnuc_va_list __ap) +{ + void (*_vsyslog) (int __pri, __const char *__fmt, __gnuc_va_list __ap) = excluded_functions[VSYSLOG].lib_function; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + _vsyslog(__pri, __fmt, __ap); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return; +} + + + +char *strerror(int errnum) +{ + char* (*_strerror) (int) = excluded_functions[STRERROR].lib_function; + char *result; + + pthread_mutex_lock(&mutex); + uninstall_hooks(); + + result = _strerror(errnum); + + install_hooks(); + pthread_mutex_unlock(&mutex); + return result; +} + +#endif /* LEAK_DETECTION */ diff --git a/src/charon/lib/utils/leak_detective.h b/src/charon/lib/utils/leak_detective.h new file mode 100644 index 000000000..13c0d01ab --- /dev/null +++ b/src/charon/lib/utils/leak_detective.h @@ -0,0 +1,50 @@ +/** + * @file leak_detective.h + * + * @brief malloc/free hooks to detect leaks. + */ + +/* + * 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 LEAK_DETECTIVE_H_ +#define LEAK_DETECTIVE_H_ + + +#ifdef LEAK_DETECTIVE + +/** + * Max number of stack frames to include in a backtrace. + */ +#define STACK_FRAMES_COUNT 30 + +/** + * Initialize leak detective, activates it + */ +void leak_detective_init(); + +/** + * Cleanup leak detective, deactivates it + */ +void leak_detective_cleanup(); + +#else /* !LEAK_DETECTIVE */ + +#define leak_detective_init() {} +#define leak_detective_cleanup() {} + +#endif /* LEAK_DETECTIVE */ + +#endif /* LEAK_DETECTIVE_H_ */ diff --git a/src/charon/lib/utils/linked_list.c b/src/charon/lib/utils/linked_list.c new file mode 100644 index 000000000..64443434b --- /dev/null +++ b/src/charon/lib/utils/linked_list.c @@ -0,0 +1,727 @@ +/** + * @file linked_list.c + * + * @brief Implementation of linked_list_t. + * + */ + +/* + * 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 <stdlib.h> + +#include "linked_list.h" + + + +typedef struct linked_list_element_t linked_list_element_t; + +/** + * @brief Element in a linked list. + * + * This element holds a pointer to the value it represents. + */ +struct linked_list_element_t { + + /** + * Value of a list item. + */ + void *value; + + /** + * Previous list element. + * + * NULL if first element in list. + */ + linked_list_element_t *previous; + + /** + * Next list element. + * + * NULL if last element in list. + */ + linked_list_element_t *next; + + /** + * Destroys a linked_list_element object. + * + * @param linked_list_element_t calling object + */ + void (*destroy) (linked_list_element_t *this); +}; + +/** + * Implementation of linked_list_element_t.destroy. + */ +static void linked_list_element_destroy(linked_list_element_t *this) +{ + free(this); +} + +/** + * @brief Creates an empty linked list object. + * + * @warning Only the pointer to the value is stored. + * + * @param[in] value value of item to be set + * @return linked_list_element_t object + */ + +linked_list_element_t *linked_list_element_create(void *value) +{ + linked_list_element_t *this = malloc_thing(linked_list_element_t); + + this->destroy = linked_list_element_destroy; + + this->previous=NULL; + this->next=NULL; + this->value = value; + + return (this); +} + + +typedef struct private_linked_list_t private_linked_list_t; + +/** + * Private data of a linked_list_t object. + * + */ +struct private_linked_list_t { + /** + * Public part of linked list. + */ + linked_list_t public; + + /** + * Number of items in the list. + */ + int count; + + /** + * First element in list. + * NULL if no elements in list. + */ + linked_list_element_t *first; + + /** + * Last element in list. + * NULL if no elements in list. + */ + linked_list_element_t *last; +}; + + +typedef struct private_iterator_t private_iterator_t; + +/** + * Private variables and functions of linked list iterator. + */ +struct private_iterator_t { + /** + * Public part of linked list iterator. + */ + iterator_t public; + + /** + * Associated linked list. + */ + private_linked_list_t * list; + + /** + * Current element of the iterator. + */ + linked_list_element_t *current; + + /** + * Direction of iterator. + */ + bool forward; +}; + +/** + * Implementation of iterator_t.has_next. + */ +static bool iterate(private_iterator_t *this, void** value) +{ + if (this->list->count == 0) + { + return FALSE; + } + if (this->current == NULL) + { + this->current = (this->forward) ? this->list->first : this->list->last; + *value = this->current->value; + return TRUE; + } + if (this->forward) + { + if (this->current->next == NULL) + { + return FALSE; + } + this->current = this->current->next; + *value = this->current->value; + return TRUE; + } + /* backward */ + if (this->current->previous == NULL) + { + return FALSE; + } + this->current = this->current->previous; + *value = this->current->value; + return TRUE; +} + +/** + * Implementation of iterator_t.has_next. + */ +static bool iterator_has_next(private_iterator_t *this) +{ + if (this->list->count == 0) + { + return FALSE; + } + if (this->current == NULL) + { + this->current = (this->forward) ? this->list->first : this->list->last; + return TRUE; + } + if (this->forward) + { + if (this->current->next == NULL) + { + return FALSE; + } + this->current = this->current->next; + return TRUE; + } + /* backward */ + if (this->current->previous == NULL) + { + return FALSE; + } + this->current = this->current->previous; + return TRUE; +} + +/** + * Implementation of iterator_t.current. + */ +static status_t iterator_current(private_iterator_t *this, void **value) +{ + if (this->current == NULL) + { + return NOT_FOUND; + } + *value = this->current->value; + return SUCCESS; +} + +/** + * Implementation of iterator_t.reset. + */ +static void iterator_reset(private_iterator_t *this) +{ + this->current = NULL; +} + +/** + * Implementation of iterator_t.remove. + */ +static status_t remove(private_iterator_t *this) +{ + linked_list_element_t *new_current; + + if (this->current == NULL) + { + return NOT_FOUND; + } + + if (this->list->count == 0) + { + return NOT_FOUND; + } + /* find out the new iterator position */ + if (this->current->previous != NULL) + { + new_current = this->current->previous; + } + else if (this->current->next != NULL) + { + new_current = this->current->next; + } + else + { + new_current = NULL; + } + + /* now delete the entry :-) */ + if (this->current->previous == NULL) + { + if (this->current->next == NULL) + { + this->list->first = NULL; + this->list->last = NULL; + } + else + { + this->current->next->previous = NULL; + this->list->first = this->current->next; + } + } + else if (this->current->next == NULL) + { + this->current->previous->next = NULL; + this->list->last = this->current->previous; + } + else + { + this->current->previous->next = this->current->next; + this->current->next->previous = this->current->previous; + } + + this->list->count--; + this->current->destroy(this->current); + /* set the new iterator position */ + this->current = new_current; + return SUCCESS; +} + +/** + * Implementation of iterator_t.insert_before. + */ +static void insert_before(private_iterator_t * iterator, void *item) +{ + if (iterator->current == NULL) + { + iterator->list->public.insert_first(&(iterator->list->public), item); + } + + linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item); + + if (iterator->current->previous == NULL) + { + iterator->current->previous = element; + element->next = iterator->current; + iterator->list->first = element; + } + else + { + iterator->current->previous->next = element; + element->previous = iterator->current->previous; + iterator->current->previous = element; + element->next = iterator->current; + } + + iterator->list->count++; +} + +/** + * Implementation of iterator_t.replace. + */ +static status_t replace (private_iterator_t *this, void **old_item, void *new_item) +{ + if (this->current == NULL) + { + return NOT_FOUND; + } + if (old_item != NULL) + { + *old_item = this->current->value; + } + this->current->value = new_item; + + return SUCCESS; +} + +/** + * Implementation of iterator_t.insert_after. + */ +static void insert_after(private_iterator_t * iterator, void *item) +{ + if (iterator->current == NULL) + { + iterator->list->public.insert_first(&(iterator->list->public),item); + return; + } + + linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item); + + if (iterator->current->next == NULL) + { + iterator->current->next = element; + element->previous = iterator->current; + iterator->list->last = element; + } + else + { + iterator->current->next->previous = element; + element->next = iterator->current->next; + iterator->current->next = element; + element->previous = iterator->current; + } + iterator->list->count++; +} + +/** + * Implementation of iterator_t.destroy. + */ +static void iterator_destroy(private_iterator_t *this) +{ + free(this); +} + +/** + * Implementation of linked_list_t.get_count. + */ +static int get_count(private_linked_list_t *this) +{ + return this->count; +} + +/** + * Implementation of linked_list_t.call_on_items. + */ +static void call_on_items(private_linked_list_t *this, void(*func)(void*)) +{ + iterator_t *iterator; + void *item; + + iterator = this->public.create_iterator(&(this->public),TRUE); + + while (iterator->has_next(iterator)) + { + iterator->current(iterator, &item); + (*func)(item); + } + iterator->destroy(iterator); +} + +/** + * Implementation of linked_list_t.insert_first. + */ +static void insert_first(private_linked_list_t *this, void *item) +{ + linked_list_element_t *element; + + element =(linked_list_element_t *) linked_list_element_create(item); + + if (this->count == 0) + { + /* first entry in list */ + this->first = element; + this->last = element; + element->previous = NULL; + element->next = NULL; + } + else + { + linked_list_element_t *old_first_element = this->first; + element->next = old_first_element; + element->previous = NULL; + old_first_element->previous = element; + this->first = element; + } + + this->count++; +} + +/** + * Implementation of linked_list_t.remove_first. + */ +static status_t remove_first(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + linked_list_element_t *element = this->first; + + if (element->next != NULL) + { + element->next->previous = NULL; + } + this->first = element->next; + + if (item != NULL) + { + *item = element->value; + } + + this->count--; + + element->destroy(element); + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.get_first. + */ +static status_t get_first(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + *item = this->first->value; + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.insert_last. + */ +static void insert_last(private_linked_list_t *this, void *item) +{ + linked_list_element_t *element = (linked_list_element_t *) linked_list_element_create(item); + + if (this->count == 0) + { + /* first entry in list */ + this->first = element; + this->last = element; + element->previous = NULL; + element->next = NULL; + } + else + { + + linked_list_element_t *old_last_element = this->last; + element->previous = old_last_element; + element->next = NULL; + old_last_element->next = element; + this->last = element; + } + + this->count++; +} + +/** + * Implementation of linked_list_t.remove_last. + */ +static status_t remove_last(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + linked_list_element_t *element = this->last; + + if (element->previous != NULL) + { + element->previous->next = NULL; + } + this->last = element->previous; + + if (item != NULL) + { + *item = element->value; + } + + this->count--; + + element->destroy(element); + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.insert_at_position. + */ +static status_t insert_at_position (private_linked_list_t *this,size_t position, void *item) +{ + linked_list_element_t *current_element; + int i; + + if (this->count <= position) + { + return INVALID_ARG; + } + + current_element = this->first; + + for (i = 0; i < position;i++) + { + current_element = current_element->next; + } + + if (current_element == NULL) + { + this->public.insert_last(&(this->public),item); + return SUCCESS; + } + + linked_list_element_t *element =(linked_list_element_t *) linked_list_element_create(item); + + + if (current_element->previous == NULL) + { + current_element->previous = element; + element->next = current_element; + this->first = element; + } + else + { + current_element->previous->next = element; + element->previous = current_element->previous; + current_element->previous = element; + element->next = current_element; + } + + + this->count++; + return SUCCESS; +} + +/** + * Implementation of linked_list_t.remove_at_position. + */ +static status_t remove_at_position (private_linked_list_t *this,size_t position, void **item) +{ + iterator_t *iterator; + int i; + + if (this->count <= position) + { + return INVALID_ARG; + } + + iterator = this->public.create_iterator(&(this->public),TRUE); + + iterator->has_next(iterator); + for (i = 0; i < position;i++) + { + iterator->has_next(iterator); + } + iterator->current(iterator,item); + iterator->remove(iterator); + iterator->destroy(iterator); + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.get_at_position. + */ +static status_t get_at_position (private_linked_list_t *this,size_t position, void **item) +{ + int i; + iterator_t *iterator; + status_t status; + if (this->count <= position) + { + return INVALID_ARG; + } + + iterator = this->public.create_iterator(&(this->public),TRUE); + + iterator->has_next(iterator); + for (i = 0; i < position;i++) + { + iterator->has_next(iterator); + } + status = iterator->current(iterator,item); + iterator->destroy(iterator); + return status; +} + +/** + * Implementation of linked_list_t.get_last. + */ +static status_t get_last(private_linked_list_t *this, void **item) +{ + if (this->count == 0) + { + return NOT_FOUND; + } + + *item = this->last->value; + + return SUCCESS; +} + +/** + * Implementation of linked_list_t.create_iterator. + */ +static iterator_t *create_iterator (private_linked_list_t *linked_list,bool forward) +{ + private_iterator_t *this = malloc_thing(private_iterator_t); + + this->public.iterate = (bool (*) (iterator_t *this, void **value)) iterate; + this->public.has_next = (bool (*) (iterator_t *this)) iterator_has_next; + this->public.current = (status_t (*) (iterator_t *this, void **value)) iterator_current; + this->public.insert_before = (void (*) (iterator_t *this, void *item)) insert_before; + this->public.insert_after = (void (*) (iterator_t *this, void *item)) insert_after; + this->public.replace = (status_t (*) (iterator_t *, void **, void *)) replace; + this->public.remove = (status_t (*) (iterator_t *this)) remove; + this->public.reset = (void (*) (iterator_t *this)) iterator_reset; + this->public.destroy = (void (*) (iterator_t *this)) iterator_destroy; + + this->forward = forward; + this->current = NULL; + this->list = linked_list; + + return &(this->public); +} + +/** + * Implementation of linked_list_t.destroy. + */ +static void linked_list_destroy(private_linked_list_t *this) +{ + void * value; + /* Remove all list items before destroying list */ + while (this->public.remove_first(&(this->public),&value) != NOT_FOUND) + { + /* values are not destroyed so memory leaks are possible + * if list is not empty when deleting */ + } + free(this); +} + +/* + * Described in header. + */ +linked_list_t *linked_list_create() +{ + private_linked_list_t *this = malloc_thing(private_linked_list_t); + + this->public.get_count = (int (*) (linked_list_t *)) get_count; + this->public.create_iterator = (iterator_t * (*) (linked_list_t *,bool )) create_iterator; + this->public.call_on_items = (void (*) (linked_list_t *, void(*func)(void*)))call_on_items; + this->public.get_first = (status_t (*) (linked_list_t *, void **item)) get_first; + this->public.get_last = (status_t (*) (linked_list_t *, void **item)) get_last; + this->public.insert_first = (void (*) (linked_list_t *, void *item)) insert_first; + this->public.insert_last = (void (*) (linked_list_t *, void *item)) insert_last; + this->public.remove_first = (status_t (*) (linked_list_t *, void **item)) remove_first; + this->public.remove_last = (status_t (*) (linked_list_t *, void **item)) remove_last; + this->public.insert_at_position =(status_t (*) (linked_list_t *,size_t, void *)) insert_at_position; + this->public.remove_at_position =(status_t (*) (linked_list_t *,size_t, void **)) remove_at_position; + this->public.get_at_position =(status_t (*) (linked_list_t *,size_t, void **)) get_at_position; + + this->public.destroy = (void (*) (linked_list_t *)) linked_list_destroy; + + this->count = 0; + this->first = NULL; + this->last = NULL; + + return (&(this->public)); +} diff --git a/src/charon/lib/utils/linked_list.h b/src/charon/lib/utils/linked_list.h new file mode 100644 index 000000000..8647f064d --- /dev/null +++ b/src/charon/lib/utils/linked_list.h @@ -0,0 +1,203 @@ +/** + * @file linked_list.h + * + * @brief Interface of linked_list_t. + * + */ + +/* + * 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. + */ + +#ifndef LINKED_LIST_H_ +#define LINKED_LIST_H_ + +#include <types.h> +#include <utils/iterator.h> + + +typedef struct linked_list_t linked_list_t; + +/** + * @brief Class implementing a double linked list (named only as linked list). + * + * @warning Access to an object of this type is not thread-save. + * + * @b Costructors: + * - linked_list_create() + * + * @see + * - job_queue_t + * - event_queue_t + * - send_queue_t + * + * @ingroup utils + */ +struct linked_list_t { + + /** + * @brief Gets the count of items in the list. + * + * @param linked_list calling object + * @return number of items in list + */ + int (*get_count) (linked_list_t *linked_list); + + /** + * @brief Creates a iterator for the given list. + * + * @warning Created iterator_t object has to get destroyed by the caller. + * + * @param linked_list calling object + * @param forward iterator direction (TRUE: front to end) + * @return new iterator_t object + */ + iterator_t * (*create_iterator) (linked_list_t *linked_list, bool forward); + + /** + * @brief Call a function with list element as argument. + * + * This method accepts a function, which will be called for + * each list element once. The function must accept the list + * element as the first argument. Handy for destruction of + * list elements. + * + * @todo Additional vararg which are passed to the + * function would be nice... + * + * @param linked_list calling object + * @param func function to call + */ + void (*call_on_items) (linked_list_t *linked_list, void(*func)(void*)); + + /** + * @brief Inserts a new item at the beginning of the list. + * + * @param linked_list calling object + * @param[in] item item value to insert in list + */ + void (*insert_first) (linked_list_t *linked_list, void *item); + + /** + * @brief Removes the first item in the list and returns its value. + * + * @param linked_list calling object + * @param[out] item returned value of first item, or NULL + * @return + * - SUCCESS + * - NOT_FOUND, if list is empty + */ + status_t (*remove_first) (linked_list_t *linked_list, void **item); + + /** + * @brief Returns the value of the first list item without removing it. + * + * @param linked_list calling object + * @param[out] item item returned value of first item + * @return + * - SUCCESS + * - NOT_FOUND, if list is empty + */ + status_t (*get_first) (linked_list_t *linked_list, void **item); + + /** + * @brief Inserts a new item at the end of the list. + * + * @param linked_list calling object + * @param[in] item item value to insert into list + */ + void (*insert_last) (linked_list_t *linked_list, void *item); + + /** + * @brief Inserts a new item at a given position in the list. + * + * @param linked_list calling object + * @param position position starting at 0 to insert new entry + * @param[in] item item value to insert into list + * @return + * - SUCCESS + * - INVALID_ARG if position not existing + */ + status_t (*insert_at_position) (linked_list_t *linked_list,size_t position, void *item); + + /** + * @brief Removes an item from a given position in the list. + * + * @param linked_list calling object + * @param position position starting at 0 to remove entry from + * @param[out] item removed item will be stored at this location + * @return + * - SUCCESS + * - INVALID_ARG if position not existing + */ + status_t (*remove_at_position) (linked_list_t *linked_list,size_t position, void **item); + + /** + * @brief Get an item from a given position in the list. + * + * @param linked_list calling object + * @param position position starting at 0 to get entry from + * @param[out] item item will be stored at this location + * @return + * - SUCCESS + * - INVALID_ARG if position not existing + */ + status_t (*get_at_position) (linked_list_t *linked_list,size_t position, void **item); + + /** + * @brief Removes the last item in the list and returns its value. + * + * @param linked_list calling object + * @param[out] item returned value of last item, or NULL + * @return + * - SUCCESS + * - NOT_FOUND if list is empty + */ + status_t (*remove_last) (linked_list_t *linked_list, void **item); + + /** + * @brief Returns the value of the last list item without removing it. + * + * @param linked_list calling object + * @param[out] item returned value of last item + * @return + * - SUCCESS + * - NOT_FOUND if list is empty + */ + status_t (*get_last) (linked_list_t *linked_list, void **item); + + /** + * @brief Destroys a linked_list object. + * + * @warning All items are removed before deleting the list. The + * associated values are NOT destroyed. + * Destroying an list which is not empty may cause + * memory leaks! + * + * @param linked_list calling object + */ + void (*destroy) (linked_list_t *linked_list); +}; + +/** + * @brief Creates an empty linked list object. + * + * @return linked_list_t object. + * + * @ingroup utils + */ +linked_list_t *linked_list_create(); + + +#endif /*LINKED_LIST_H_*/ diff --git a/src/charon/lib/utils/logger.c b/src/charon/lib/utils/logger.c new file mode 100644 index 000000000..fdaeddff0 --- /dev/null +++ b/src/charon/lib/utils/logger.c @@ -0,0 +1,342 @@ +/** + * @file logger.c + * + * @brief Implementation of logger_t. + * + */ + +/* + * 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 <syslog.h> +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include <pthread.h> + +#include "logger.h" + + +/** + * Maximum length of a log entry (only used for logger_s.log). + */ +#define MAX_LOG 8192 + +/** + * Maximum number of logged bytes per line + */ +#define MAX_BYTES 16 + +typedef struct private_logger_t private_logger_t; + +/** + * @brief Private data of a logger_t object. + */ +struct private_logger_t { + /** + * Public data. + */ + logger_t public; + /** + * Detail-level of logger. + */ + log_level_t level; + /** + * Name of logger. + */ + char *name; + /** + * File to write log output to. + * NULL for syslog. + */ + FILE *output; + + /** + * Should a thread_id be included in the log? + */ + bool log_thread_id; +}; + +/** + * prepend the logging prefix to string and store it in buffer + */ +static void prepend_prefix(private_logger_t *this, log_level_t loglevel, const char *string, char *buffer) +{ + char log_type, log_details; + char thread_id[10] = ""; + + if (loglevel & CONTROL) + { + log_type = 'C'; + } + else if (loglevel & ERROR) + { + log_type = 'E'; + } + else if (loglevel & RAW) + { + log_type = 'R'; + } + else if (loglevel & PRIVATE) + { + log_type = 'P'; + } + else if (loglevel & AUDIT) + { + log_type = 'A'; + } + else + { + log_type = '-'; + } + + if (loglevel & (LEVEL3 - LEVEL2)) + { + log_details = '3'; + } + else if (loglevel & (LEVEL2 - LEVEL1)) + { + log_details = '2'; + } + else if (loglevel & LEVEL1) + { + log_details = '1'; + } + else + { + log_details = '0'; + } + + if (this->log_thread_id) + { + snprintf(thread_id, sizeof(thread_id), " @%d", (int)pthread_self()); + } + snprintf(buffer, MAX_LOG, "[%c%c:%s]%s %s", log_type, log_details, this->name, thread_id, string); +} + +/** + * Convert a charon-loglevel to a syslog priority + */ +static int get_priority(log_level_t loglevel) +{ + if (loglevel & AUDIT) + { + return LOG_AUTHPRIV|LOG_INFO; + } + return LOG_DAEMON|LOG_DEBUG; +} + +/** + * Implementation of logger_t.log. + * + * Yes, logg is written wrong :-). + */ +static void logg(private_logger_t *this, log_level_t loglevel, const char *format, ...) +{ + if ((this->level & loglevel) == loglevel) + { + char buffer[MAX_LOG]; + va_list args; + + + if (this->output == NULL) + { + /* syslog */ + prepend_prefix(this, loglevel, format, buffer); + va_start(args, format); + vsyslog(get_priority(loglevel), buffer, args); + va_end(args); + } + else + { + /* File output */ + prepend_prefix(this, loglevel, format, buffer); + va_start(args, format); + vfprintf(this->output, buffer, args); + va_end(args); + fprintf(this->output, "\n"); + } + + } +} + +/** + * Implementation of logger_t.log_bytes. + */ +static void log_bytes(private_logger_t *this, log_level_t loglevel, const char *label, const char *bytes, size_t len) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + + if ((this->level & loglevel) == loglevel) + { + char thread_id[10] = ""; + char buffer[MAX_LOG]; + char ascii_buffer[MAX_BYTES+1]; + + char *buffer_pos = buffer; + const char format[] = "%s %d bytes @ %p"; + const char *bytes_pos = bytes; + const char *bytes_roof = bytes + len; + + int line_start = 0; + int i = 0; + + if (this->log_thread_id) + { + snprintf(thread_id, sizeof(thread_id), " @%d", (int)pthread_self()); + } + + /* since me can't do multi-line output to syslog, + * we must do multiple syslogs. To avoid + * problems in output order, lock this by a mutex. + */ + pthread_mutex_lock(&mutex); + + prepend_prefix(this, loglevel, format, buffer); + + if (this->output == NULL) + { + syslog(get_priority(loglevel), buffer, label, len, bytes); + } + else + { + fprintf(this->output, buffer, label, len, bytes); + fprintf(this->output, "\n"); + } + + while (bytes_pos < bytes_roof) + { + static char hexdig[] = "0123456789ABCDEF"; + + *buffer_pos++ = hexdig[(*bytes_pos >> 4) & 0xF]; + *buffer_pos++ = hexdig[ *bytes_pos & 0xF]; + + ascii_buffer[i++] = (*bytes_pos > 31 && *bytes_pos < 127) + ? *bytes_pos : '.'; + + if (++bytes_pos == bytes_roof || i == MAX_BYTES) + { + int padding = 3 * (MAX_BYTES - i); + + while (padding--) + { + *buffer_pos++ = ' '; + } + *buffer_pos++ = '\0'; + ascii_buffer[i] = '\0'; + + if (this->output == NULL) + { + syslog(get_priority(loglevel), "[ :%5d]%s %s %s", line_start, thread_id, buffer, ascii_buffer); + } + else + { + fprintf(this->output, "[ :%5d]%s %s %s\n", line_start, thread_id, buffer, ascii_buffer); + } + buffer_pos = buffer; + line_start += MAX_BYTES; + i = 0; + } + else + { + *buffer_pos++ = ' '; + } + } + pthread_mutex_unlock(&mutex); + } +} + +/** + * Implementation of logger_t.log_chunk. + */ +static void log_chunk(logger_t *this, log_level_t loglevel, const char *label, chunk_t chunk) +{ + this->log_bytes(this, loglevel, label, chunk.ptr, chunk.len); +} + +/** + * Implementation of logger_t.enable_level. + */ +static void enable_level(private_logger_t *this, log_level_t log_level) +{ + this->level |= log_level; +} + +/** + * Implementation of logger_t.disable_level. + */ +static void disable_level(private_logger_t *this, log_level_t log_level) +{ + this->level &= ~log_level; +} + +/** + * Implementation of logger_t.set_output. + */ +static void set_output(private_logger_t *this, FILE * output) +{ + this->output = output; +} + +/** + * Implementation of logger_t.get_level. + */ +static log_level_t get_level(private_logger_t *this) +{ + return this->level; +} + +/** + * Implementation of logger_t.destroy. + */ +static void destroy(private_logger_t *this) +{ + free(this->name); + free(this); +} + +/* + * Described in header. + */ +logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output) +{ + private_logger_t *this = malloc_thing(private_logger_t); + + /* public functions */ + this->public.log = (void(*)(logger_t*,log_level_t,const char*,...))logg; + this->public.log_bytes = (void(*)(logger_t*, log_level_t, const char*, const char*,size_t))log_bytes; + this->public.log_chunk = log_chunk; + this->public.enable_level = (void(*)(logger_t*,log_level_t))enable_level; + this->public.disable_level = (void(*)(logger_t*,log_level_t))disable_level; + this->public.get_level = (log_level_t(*)(logger_t*))get_level; + this->public.set_output = (void(*)(logger_t*,FILE*))set_output; + this->public.destroy = (void(*)(logger_t*))destroy; + + if (logger_name == NULL) + { + logger_name = ""; + } + + /* private variables */ + this->level = log_level; + this->log_thread_id = log_thread_id; + this->name = malloc(strlen(logger_name) + 1); + + strcpy(this->name,logger_name); + this->output = output; + + return (logger_t*)this; +} diff --git a/src/charon/lib/utils/logger.h b/src/charon/lib/utils/logger.h new file mode 100644 index 000000000..dec73078e --- /dev/null +++ b/src/charon/lib/utils/logger.h @@ -0,0 +1,198 @@ +/** + * @file logger.h + * + * @brief Interface of logger_t. + * + */ + +/* + * 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. + */ + +#ifndef LOGGER_H_ +#define LOGGER_H_ + +#include <stdio.h> + +#include <types.h> + +typedef enum log_level_t log_level_t; + +/** + * @brief Log Levels supported by the logger object. + * + * Logleves are devided in two different kinds: + * - levels to specify the type of the log + * - levels to specify the detail-level of the log + * + * Use combinations of these to build detailed loglevels, such + * as CONTROL|LEVEL2 fore a detailed cotrol level, or + * use RAW to see all raw data dumps (except private). + * + * @ingroup utils + */ +enum log_level_t { + /** + * Control flow. + */ + CONTROL = 1, + /** + * Error reporting. + */ + ERROR = 2, + /** + * Logs important for the sysadmin. + */ + AUDIT = 4, + /** + * Raw data dumps. + */ + RAW = 8, + /** + * Private data dumps. + */ + PRIVATE = 16, + + /** + * Log most important output, can be omitted. + */ + LEVEL0 = 0, + /** + * Log more detailed output. + */ + LEVEL1 = 32, + /** + * Log even more detailed output. + */ + LEVEL2 = LEVEL1 + 64, + /** + * Use maximum detailed output. + */ + LEVEL3 = LEVEL2 + 128, + + /** + * Summary for all types with all detail-levels. + */ + FULL = LEVEL3 + CONTROL + ERROR + RAW + PRIVATE + AUDIT +}; + +typedef struct logger_t logger_t; + +/** + * @brief Class to simplify logging. + * + * @b Constructors: + * - logger_create() + * + * @ingroup utils + */ +struct logger_t { + + /** + * @brief Log an entry, using printf()-like params. + * + * All specified loglevels must be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of log_level_t's + * @param format printf like format string + * @param ... printf like parameters + */ + void (*log) (logger_t *this, log_level_t log_level, const char *format, ...); + + /** + * @brief Log some bytes, useful for debugging. + * + * All specified loglevels must be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of log_level_t's + * @param label a labeling name, logged with the bytes + * @param bytes pointer to the bytes to dump + * @param len number of bytes to dump + */ + void (*log_bytes) (logger_t *this, log_level_t loglevel, const char *label, const char *bytes, size_t len); + + /** + * @brief Log a chunk, useful for debugging. + * + * All specified loglevels must be activated that + * the log is done. + * + * @param this logger_t object + * @param loglevel or'ed set of log_level_t's + * @param label a labeling name, logged with the bytes + * @param chunk chunk to log + */ + void (*log_chunk) (logger_t *this, log_level_t loglevel, const char *label, chunk_t chunk); + + /** + * @brief Enables a loglevel for the current logger_t object. + * + * @param this logger_t object + * @param log_level loglevel to enable + */ + void (*enable_level) (logger_t *this, log_level_t log_level); + + /** + * @brief Disables a loglevel for the current logger_t object. + * + * @param this logger_t object + * @param log_level loglevel to enable + */ + void (*disable_level) (logger_t *this, log_level_t log_level); + + /** + * @brief Set the output of the logger. + * + * Use NULL for syslog. + * + * @param this logger_t object + * @param output file, where log output should be written + */ + void (*set_output) (logger_t *this, FILE *output); + + /** + * @brief Get the currently used loglevel. + * + * @param this logger_t object + * @return currently used loglevel + */ + log_level_t (*get_level) (logger_t *this); + + /** + * @brief Destroys a logger_t object. + * + * @param this logger_t object + */ + void (*destroy) (logger_t *this); +}; + +/** + * @brief Constructor to create a logger_t object. + * + * @param logger_name name for the logger_t object + * @param log_level or'ed set of log_levels to assign to the new logger_t object + * @param log_thread_id TRUE if thread id should also be logged + * @param output FILE * if log has to go on a file output, NULL for syslog + * @return logger_t object + * + * @ingroup utils + */ +logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output); + + +#endif /*LOGGER_H_*/ diff --git a/src/charon/lib/utils/logger_manager.c b/src/charon/lib/utils/logger_manager.c new file mode 100644 index 000000000..ecbe1a6c1 --- /dev/null +++ b/src/charon/lib/utils/logger_manager.c @@ -0,0 +1,220 @@ +/** + * @file logger_manager.c + * + * @brief Implementation of logger_manager_t. + * + */ + +/* + * 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 "logger_manager.h" + +#include <daemon.h> +#include <definitions.h> +#include <utils/linked_list.h> + +/** + * String mappings for logger_context_t + */ +mapping_t logger_context_t_mappings[] = { + {PARSER, "PARSER"}, + {GENERATOR, "GENERATOR"}, + {IKE_SA, "IKE_SA"}, + {IKE_SA_MANAGER, "IKE_SA_MANAGER"}, + {CHILD_SA, "CHILD_SA"}, + {MESSAGE, "MESSAGE"}, + {THREAD_POOL, "THREAD_POOL"}, + {WORKER, "WORKER"}, + {SCHEDULER, "SCHEDULER"}, + {SENDER, "SENDER"}, + {RECEIVER, "RECEIVER"}, + {SOCKET, "SOCKET"}, + {TESTER, "TESTER"}, + {DAEMON, "DAEMON"}, + {CONFIG, "CONFIG"}, + {ENCRYPTION_PAYLOAD, "ENCRYPTION_PAYLOAD"}, + {PAYLOAD, "PAYLOAD"}, + {DER_DECODER, "DER_DECODER"}, + {DER_ENCODER, "DER_ENCODER"}, + {ASN1, "ASN1"}, + {XFRM, "XFRM"}, + {LEAK_DETECT, "LEAK_DETECT"}, + {MAPPING_END, NULL}, +}; + +struct { + char *name; + log_level_t level; + bool log_thread_ids; +} logger_defaults[] = { + { "PARSR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* PARSER */ + { "GNRAT", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* GENERATOR */ + { "IKESA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* IKE_SA */ + { "SAMGR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* IKE_SA_MANAGER */ + { "CHDSA", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* CHILD_SA */ + { "MESSG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* MESSAGE */ + { "TPOOL", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* THREAD_POOL */ + { "WORKR", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* WORKER */ + { "SCHED", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* SCHEDULER */ + { "SENDR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* SENDER */ + { "RECVR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* RECEIVER */ + { "SOCKT", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* SOCKET */ + { "TESTR", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* TESTER */ + { "DAEMN", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* DAEMON */ + { "CONFG", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* CONFIG */ + { "ENCPL", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* ENCRYPTION_PAYLOAD */ + { "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|LEVEL0, TRUE }, /* ASN1 */ + { "XFRM ", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* XFRM */ + { "LEAKD", ERROR|CONTROL|AUDIT|LEVEL0, FALSE}, /* LEAK_DETECT */ +}; + + +typedef struct private_logger_manager_t private_logger_manager_t; + +/** + * Private data of logger_manager_t object. + */ +struct private_logger_manager_t { + /** + * Public data. + */ + logger_manager_t public; + + /** + * Array of loggers, one for each context + */ + logger_t *loggers[LOGGER_CONTEXT_ROOF]; +}; + +/** + * The one and only instance of the logger manager + */ +static private_logger_manager_t private_logger_manager; + +/** + * Exported pointer for the logger manager + */ +logger_manager_t *logger_manager = (logger_manager_t *)&private_logger_manager; + +/** + * Implementation of logger_manager_t.get_logger. + */ +static logger_t *get_logger(private_logger_manager_t *this, logger_context_t context) +{ + return this->loggers[context]; +} + +/** + * Implementation of logger_manager_t.get_log_level. + */ +static log_level_t get_log_level (private_logger_manager_t *this, logger_context_t context) +{ + return this->loggers[context]->get_level(this->loggers[context]); +} + +/** + * Implementation of private_logger_manager_t.enable_log_level. + */ +static void enable_log_level(private_logger_manager_t *this, logger_context_t context, log_level_t level) +{ + if (context == ALL_LOGGERS) + { + for (context = 0; context < LOGGER_CONTEXT_ROOF; context++) + { + this->loggers[context]->enable_level(this->loggers[context], level); + } + } + else + { + this->loggers[context]->enable_level(this->loggers[context], level); + } +} + +/** + * Implementation of private_logger_manager_t.disable_log_level. + */ +static void disable_log_level(private_logger_manager_t *this, logger_context_t context, log_level_t level) +{ + if (context == ALL_LOGGERS) + { + for (context = 0; context < LOGGER_CONTEXT_ROOF; context++) + { + this->loggers[context]->disable_level(this->loggers[context], level); + } + } + else + { + this->loggers[context]->disable_level(this->loggers[context], level); + } +} + +/** + * Implementation of private_logger_manager_t.set_output. + */ +static void set_output(private_logger_manager_t *this, logger_context_t context, FILE *output) +{ + if (context == ALL_LOGGERS) + { + for (context = 0; context < LOGGER_CONTEXT_ROOF; context++) + { + this->loggers[context]->set_output(this->loggers[context], output); + } + } + else + { + this->loggers[context]->set_output(this->loggers[context], output); + } +} + + +/** + * Creates the instance of the logger manager at library startup + */ +void logger_manager_init() +{ + int i; + + logger_manager->get_logger = (logger_t *(*)(logger_manager_t*,logger_context_t context))get_logger; + logger_manager->get_log_level = (log_level_t (*)(logger_manager_t *, logger_context_t)) get_log_level; + logger_manager->enable_log_level = (void (*)(logger_manager_t *, logger_context_t, log_level_t)) enable_log_level; + logger_manager->disable_log_level = (void (*)(logger_manager_t *, logger_context_t, log_level_t)) disable_log_level; + logger_manager->set_output = (void (*)(logger_manager_t *, logger_context_t, FILE*)) set_output; + + for (i = 0; i < LOGGER_CONTEXT_ROOF; i++) + { + private_logger_manager.loggers[i] = logger_create(logger_defaults[i].name, + logger_defaults[i].level, + logger_defaults[i].log_thread_ids, + INITIAL_LOG_OUTPUT); + } + +} + +/** + * Destroy the logger manager at library exit + */ +void logger_manager_cleanup() +{ + int i; + for (i = 0; i < LOGGER_CONTEXT_ROOF; i++) + { + private_logger_manager.loggers[i]->destroy(private_logger_manager.loggers[i]); + } +} diff --git a/src/charon/lib/utils/logger_manager.h b/src/charon/lib/utils/logger_manager.h new file mode 100644 index 000000000..a3ff5a37e --- /dev/null +++ b/src/charon/lib/utils/logger_manager.h @@ -0,0 +1,160 @@ +/** + * @file logger_manager.h + * + * @brief Interface of logger_manager_t. + * + */ + +/* + * 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. + */ + +#ifndef LOGGER_MANAGER_H_ +#define LOGGER_MANAGER_H_ + +#include <pthread.h> + +#include <utils/logger.h> + +#define INITIAL_LOG_OUTPUT stdout + +typedef enum logger_context_t logger_context_t; + +/** + * @brief Context of a specific logger. + * + * @ingroup utils + */ +enum logger_context_t { + ALL_LOGGERS = -1, + PARSER = 0, + GENERATOR, + IKE_SA, + IKE_SA_MANAGER, + CHILD_SA, + MESSAGE, + THREAD_POOL, + WORKER, + SCHEDULER, + SENDER, + RECEIVER, + SOCKET, + TESTER, + DAEMON, + CONFIG, + ENCRYPTION_PAYLOAD, + PAYLOAD, + DER_DECODER, + DER_ENCODER, + ASN1, + XFRM, + LEAK_DETECT, + LOGGER_CONTEXT_ROOF, +}; + + +typedef struct logger_manager_t logger_manager_t; + +/** + * @brief Class to manage logger_t objects. + * + * The logger manager manages all logger_t object in a list and + * allows their manipulation. Via a logger_context_t, the loglevel + * of a specific logging type can be adjusted at runtime. + * This class differs from others, as it has no constructor or destroy + * function. The one and only instance "logger_manager" is created at + * library start and destroyed at exit. + * + * @b Constructors: + * - none, logger_manager is the single instance + * use logger_manager_init/logger_manager_cleanup + * + * @see logger_t + * + * @ingroup utils + */ +struct logger_manager_t { + + /** + * @brief Gets a logger_t object for a specific logger context. + * + * @param this logger_manager_t object + * @param context logger_context to use the logger for + * @param name name for the new logger. Context name is already included + * and has not to be specified (so NULL is allowed) + * @return logger_t object + */ + logger_t *(*get_logger) (logger_manager_t *this, logger_context_t context); + + /** + * @brief Returns the set log_level of a specific context. + * + * @param this calling object + * @param context context to check level + * @return log_level for the given logger_context + */ + log_level_t (*get_log_level) (logger_manager_t *this, logger_context_t context); + + /** + * @brief Enables a logger level of a specific context. + * + * Use context ALL_LOGGERS to manipulate all loggers. + * + * @param this calling object + * @param context context to set level + * @param log_level logger level to eanble + */ + void (*enable_log_level) (logger_manager_t *this, logger_context_t context,log_level_t log_level); + + /** + * @brief Disables a logger level of a specific context. + * + * Use context ALL_LOGGERS to manipulate all loggers. + * + * @param this calling object + * @param context context to set level + * @param log_level logger level to disable + */ + void (*disable_log_level) (logger_manager_t *this, logger_context_t context,log_level_t log_level); + + /** + * @brief Sets the output of a logger. + * + * Use context ALL_LOGGERS to redirect all loggers. + * + * @param this calling object + * @param context context to set output + * @param log_level logger level to disable + */ + void (*set_output) (logger_manager_t *this, logger_context_t context, FILE *output); +}; + +/** + * The single and global instance of the logger_manager + */ +extern logger_manager_t *logger_manager; + +/** + * Initialize the logger manager with all its logger. + * Has to be called before logger_manager is accessed. + */ +void logger_manager_init(); + +/** + * Free any resources hold by the logger manager. Do + * not access logger_manager after this call. + */ +void logger_manager_cleanup(); + +#endif /*LOGGER_MANAGER_H_*/ diff --git a/src/charon/lib/utils/randomizer.c b/src/charon/lib/utils/randomizer.c new file mode 100644 index 000000000..09e81894e --- /dev/null +++ b/src/charon/lib/utils/randomizer.c @@ -0,0 +1,164 @@ +/** + * @file randomizer.c + * + * @brief Implementation of randomizer_t. + * + */ + +/* + * 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 <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "randomizer.h" + + +typedef struct private_randomizer_t private_randomizer_t; + +/** + * Private data of an randomizer_t object. + */ +struct private_randomizer_t { + + /** + * Public randomizer_t interface. + */ + randomizer_t public; + + /** + * @brief Reads a specific number of bytes from random or pseudo random device. + * + * @param this calling object + * @param pseudo_random TRUE, if from pseudo random bytes should be read, + * FALSE for true random bytes + * @param bytes number of bytes to read + * @param[out] buffer pointer to buffer where to write the data in. + * Size of buffer has to be at least bytes. + */ + status_t (*get_bytes_from_device) (private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer); +}; + + +/** + * Implementation of private_randomizer_t.get_bytes_from_device. + */ +static status_t get_bytes_from_device(private_randomizer_t *this,bool pseudo_random, size_t bytes, u_int8_t *buffer) +{ + size_t ndone; + int device; + size_t got; + char * device_name; + + device_name = pseudo_random ? PSEUDO_RANDOM_DEVICE : RANDOM_DEVICE; + + device = open(device_name, 0); + if (device < 0) { + return FAILED; + } + ndone = 0; + + /* read until nbytes are read */ + while (ndone < bytes) + { + got = read(device, buffer + ndone, bytes - ndone); + if (got <= 0) { + close(device); + return FAILED; + } + ndone += got; + } + close(device); + return SUCCESS; +} + +/** + * Implementation of randomizer_t.get_random_bytes. + */ +static status_t get_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer) +{ + return this->get_bytes_from_device(this, FALSE, bytes, buffer); +} + +/** + * Implementation of randomizer_t.allocate_random_bytes. + */ +static status_t allocate_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk) +{ + status_t status; + chunk->len = bytes; + chunk->ptr = malloc(bytes); + status = this->get_bytes_from_device(this, FALSE, bytes, chunk->ptr); + if (status != SUCCESS) + { + free(chunk->ptr); + } + return status; +} + +/** + * Implementation of randomizer_t.get_pseudo_random_bytes. + */ +static status_t get_pseudo_random_bytes(private_randomizer_t *this,size_t bytes, u_int8_t *buffer) +{ + return (this->get_bytes_from_device(this, TRUE, bytes, buffer)); +} + +/** + * Implementation of randomizer_t.allocate_pseudo_random_bytes. + */ +static status_t allocate_pseudo_random_bytes(private_randomizer_t *this, size_t bytes, chunk_t *chunk) +{ + status_t status; + chunk->len = bytes; + chunk->ptr = malloc(bytes); + status = this->get_bytes_from_device(this, TRUE, bytes, chunk->ptr); + if (status != SUCCESS) + { + free(chunk->ptr); + } + return status; +} + +/** + * Implementation of randomizer_t.destroy. + */ +static void destroy(private_randomizer_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +randomizer_t *randomizer_create(void) +{ + private_randomizer_t *this = malloc_thing(private_randomizer_t); + + /* public functions */ + this->public.get_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_random_bytes; + this->public.allocate_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_random_bytes; + this->public.get_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, u_int8_t *)) get_pseudo_random_bytes; + this->public.allocate_pseudo_random_bytes = (status_t (*) (randomizer_t *,size_t, chunk_t *)) allocate_pseudo_random_bytes; + this->public.destroy = (void (*) (randomizer_t *))destroy; + + /* private functions */ + this->get_bytes_from_device = get_bytes_from_device; + + return &(this->public); +} diff --git a/src/charon/lib/utils/randomizer.h b/src/charon/lib/utils/randomizer.h new file mode 100644 index 000000000..55519550e --- /dev/null +++ b/src/charon/lib/utils/randomizer.h @@ -0,0 +1,110 @@ +/** + * @file randomizer.h + * + * @brief Interface of randomizer_t. + * + */ + +/* + * 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. + */ + +#ifndef RANDOMIZER_H_ +#define RANDOMIZER_H_ + +#include <types.h> + + +/** + * Device to read real random bytes + */ +#define RANDOM_DEVICE "/dev/random" + +/** + * Device to read pseudo random bytes + */ +#define PSEUDO_RANDOM_DEVICE "/dev/urandom" + +typedef struct randomizer_t randomizer_t; + +/** + * @brief Class used to get random and pseudo random values. + * + * @b Constructors: + * - randomizer_create() + * + * @ingroup utils + */ +struct randomizer_t { + + /** + * @brief Reads a specific number of bytes from random device. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to read + * @param[out] buffer pointer to buffer where to write the data in. + * Size of buffer has to be at least bytes. + * @return SUCCESS, or FAILED + */ + status_t (*get_random_bytes) (randomizer_t *this, size_t bytes, u_int8_t *buffer); + + /** + * @brief Allocates space and writes in random bytes. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to allocate + * @param[out] chunk chunk which will hold the allocated random bytes + * @return SUCCESS, or FAILED + */ + status_t (*allocate_random_bytes) (randomizer_t *this, size_t bytes, chunk_t *chunk); + + /** + * @brief Reads a specific number of bytes from pseudo random device. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to read + * @param[out] buffer pointer to buffer where to write the data in. + * size of buffer has to be at least bytes. + * @return SUCCESS, or FAILED + */ + status_t (*get_pseudo_random_bytes) (randomizer_t *this,size_t bytes, u_int8_t *buffer); + + /** + * @brief Allocates space and writes in pseudo random bytes. + * + * @param this calling randomizer_t object + * @param bytes number of bytes to allocate + * @param[out] chunk chunk which will hold the allocated random bytes + * @return SUCCESS, or FAILED + */ + status_t (*allocate_pseudo_random_bytes) (randomizer_t *this, size_t bytes, chunk_t *chunk); + + /** + * @brief Destroys a randomizer_t object. + * + * @param this randomizer_t object to destroy + */ + void (*destroy) (randomizer_t *this); +}; + +/** + * @brief Creates a randomizer_t object. + * + * @return created randomizer_t, or + * + * @ingroup utils + */ +randomizer_t *randomizer_create(); + +#endif /*RANDOMIZER_H_*/ diff --git a/src/charon/lib/utils/tester.c b/src/charon/lib/utils/tester.c new file mode 100644 index 000000000..a7599dd82 --- /dev/null +++ b/src/charon/lib/utils/tester.c @@ -0,0 +1,256 @@ +/** + * @file tester.c + * + * @brief Implementation of tester_t. + * + */ + +/* + * 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 <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <sys/time.h> + +#include "tester.h" + +#include <utils/linked_list.h> +#include <queues/job_queue.h> + + +typedef struct private_tester_t private_tester_t; + +/** + * @brief Private Data of tester_t class. + * + */ +struct private_tester_t { + + /** + * Protected interface of tester_t. + */ + protected_tester_t protected; + + /** + * Runs a specific test. + * + * @param tester associated tester object + * @param test_function test function to perform + * @param test_name name for the given test + */ + void (*run_test) (private_tester_t *tester, void (*test_function) (protected_tester_t * tester), char * test_name); + + /** + * Returns the difference of to timeval structs in microseconds. + * + * @warning this function is also defined in the event queue + * in later improvements, this function can be added to a general + * class type! + * + * @param end_time end time + * @param start_time start time + * + * @TODO make object function or move to utils! + * + * @return difference in microseconds + */ + long (*time_difference) (private_tester_t *tester,struct timeval *end_time, struct timeval *start_time); + + /** + * Output is written into this file. + */ + FILE* output; + + /** + * Number of already performed tests. + */ + int tests_count; + + /** + * Number of failed tests. + */ + int failed_tests_count; + + /** + * Number of failed asserts in current test. + */ + int failed_asserts_count; + + /** + * TRUE if also succeeded asserts should be written to output. + */ + bool display_succeeded_asserts; + + /** + * Mutex to make this class thread-save. + */ + pthread_mutex_t mutex; +}; + +/** + * Implementation of tester_t.perform_tests. + */ +static void perform_tests(private_tester_t *this,test_t **tests) +{ + int current_test = 0; + fprintf(this->output,"\nStart testing...\n\n"); + fprintf(this->output,"_____________________________________________________________________\n"); + fprintf(this->output,"Testname | running time\n"); + fprintf(this->output,"_______________________________________________________|_____________\n"); + + while (tests[current_test] != NULL) + { + this->run_test(this,tests[current_test]->test_function,tests[current_test]->test_name); + current_test++; + } + fprintf(this->output,"=====================================================================\n"); + fprintf(this->output,"End testing. %d of %d tests succeeded\n",this->tests_count - this->failed_tests_count,this->tests_count); + fprintf(this->output,"=====================================================================\n"); +} + +/** + * Implementation of tester_t.perform_test. + */ +static void perform_test(private_tester_t *this, test_t *test) +{ + test_t *tests[] = {test, NULL}; + return (perform_tests(this,tests)); +} + +/** + * Returns the difference of to timeval structs in microseconds. + * + * @warning this function is also defined in the event queue + * in later improvements, this function can be added to a general + * class type! + * + * @param end_time end time + * @param start_time start time + * + * @TODO make object function or move to utils! + * + * @return difference in microseconds + */ +static long time_difference(private_tester_t *this,struct timeval *end_time, struct timeval *start_time) +{ + long seconds, microseconds; + + seconds = (end_time->tv_sec - start_time->tv_sec); + microseconds = (end_time->tv_usec - start_time->tv_usec); + return ((seconds * 1000000) + microseconds); +} + + +/** + * Implementation of private_tester_t.run_test. + */ +static void run_test(private_tester_t *this, void (*test_function) (protected_tester_t * tester), char * test_name) +{ + struct timeval start_time, end_time; + long timediff; + this->tests_count++; + this->failed_asserts_count = 0; + fprintf(this->output,"%-55s\n", test_name); + gettimeofday(&start_time,NULL); + test_function(&(this->protected)); + gettimeofday(&end_time,NULL); + timediff = this->time_difference(this,&end_time, &start_time); + + if (this->failed_asserts_count > 0) + { + fprintf(this->output," => Test failed: %-37s|%10ld us\n",test_name,timediff); + }else + { + fprintf(this->output,"\033[1A\033[55C|%10ld us\033[1B\033[80D",timediff); + } + if (this->failed_asserts_count > 0) + { + this->failed_tests_count++; + } +} + + +/** + * Implementation of tester_t.assert_true. + */ +static void assert_true(private_tester_t *this, bool to_be_true,char * assert_name) +{ + if (assert_name == NULL) + { + assert_name = "unknown"; + } + + pthread_mutex_lock(&(this->mutex)); + if (!to_be_true) + { + this->failed_asserts_count++; + fprintf(this->output," check '%s' failed!\n", assert_name); + }else + { + if (this->display_succeeded_asserts) + { + fprintf(this->output," check '%s' succeeded\n", assert_name); + } + } + pthread_mutex_unlock(&(this->mutex)); +} + +/** + * Implementation of tester_t.assert_false. + */ +static void assert_false(private_tester_t *this, bool to_be_false,char * assert_name) +{ + this->protected.assert_true(&(this->protected),(!to_be_false),assert_name); +} + +/** + * Implementation of tester_t.destroy. + */ +static void destroy(private_tester_t *tester) +{ + private_tester_t *this = (private_tester_t*) tester; + pthread_mutex_destroy(&(this->mutex)); + free(this); +} + +/* + * Described in header. + */ +tester_t *tester_create(FILE *output, bool display_succeeded_asserts) +{ + private_tester_t *this = malloc_thing(private_tester_t); + + /* public functions */ + this->protected.public.destroy = (void (*) (tester_t *))destroy; + this->protected.public.perform_tests = (void (*) (tester_t *, test_t**)) perform_tests; + this->protected.public.perform_test = (void (*) (tester_t *, test_t*))perform_test; + this->protected.assert_true = (void (*) (protected_tester_t *, bool, char*)) assert_true; + this->protected.assert_false = (void (*) (protected_tester_t *, bool, char*)) assert_false; + + /* private functions */ + this->run_test = run_test; + this->time_difference = time_difference; + + /* private data */ + this->display_succeeded_asserts = display_succeeded_asserts; + this->failed_tests_count = 0; + this->tests_count = 0; + this->output = output; + pthread_mutex_init(&(this->mutex),NULL); + + return &(this->protected.public); +} diff --git a/src/charon/lib/utils/tester.h b/src/charon/lib/utils/tester.h new file mode 100644 index 000000000..3decb2039 --- /dev/null +++ b/src/charon/lib/utils/tester.h @@ -0,0 +1,148 @@ +/** + * @file tester.h + * + * @brief Interface of tester_t. + * + */ + +/* + * 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. + */ + +#ifndef TESTER_H_ +#define TESTER_H_ + +#include <stdio.h> + +#include <types.h> + + +/* must be defined here cause it is used in test_t */ +typedef struct protected_tester_t protected_tester_t; + +typedef struct test_t test_t; + +/** + * @brief Representing a specified test. + * + * @ingroup utils + */ +struct test_t { + /** + * Testfunction called for this test. + * + * @param tester associated tester_t object + */ + void (*test_function) (protected_tester_t * tester); + + /** + * Name of the test. + */ + char * test_name; +}; + + +typedef struct tester_t tester_t; + +/** + * @brief A class to perform tests. + * + * @b Constructors: + * - tester_create() + * + * @ingroup utils + */ +struct tester_t { + /** + * @brief Test all testcases in array tests with specific tester_t object. + * + * @param tester tester_t object + * @param tests pointer to an array of test_t-pointers. + * The last item has to be NULL to mark end of array. + */ + void (*perform_tests) (tester_t *tester,test_t **tests); + + /** + * @brief Run a specific test case. + * + * @param this tester_t object + * @param test pointer to a test_t object which will be performed + */ + void (*perform_test) (tester_t *tester, test_t *test); + + /** + * @brief Destroys a tester_t object. + * + * @param tester tester_t object + */ + void (*destroy) (tester_t *tester); +}; + + +/** + * @brief A class used in a specific testcase. + * + * For each testcase an object of this type is passed to the testfunction. The testfunction uses this + * object to check specific asserts with protected_tester_t.assert_true and protected_tester_t.assert_false. + * + * @b Constructors: + * - tester_create() + * + * @ingroup utils + */ +struct protected_tester_t { + + /** + * Public functions of a tester_t object + */ + tester_t public; + + /** + * @brief Is called in a testcase to check a specific situation for TRUE. + * + * Log-Values to the tester output are protected from multiple access. + * + * @param this tester_t object + * @param to_be_true assert which has to be TRUE + * @param assert_name name of the assertion + */ + void (*assert_true) (protected_tester_t *tester, bool to_be_true, char *assert_name); + + /** + * @brief Is called in a testcase to check a specific situation for FALSE. + * + * Log-Values to the tester output are protected from multiple access. + * + * @param this tester_t object + * @param to_be_false assert which has to be FALSE + * @param assert_name name of the assertion + */ + void (*assert_false) (protected_tester_t *tester, bool to_be_false, char *assert_name); +}; + + +/** + * @brief Creates a tester_t object used to perform tests with. + * + * @param output test output is written to this output. + * @param display_succeeded_asserts has to be TRUE, if all asserts should be displayed, + * FALSE otherwise + * + * @return tester_t object + * + * @ingroup utils + */ +tester_t *tester_create(FILE *output, bool display_succeeded_asserts); + +#endif /*TESTER_H_*/ |