diff options
Diffstat (limited to 'src/libstrongswan/asn1')
-rw-r--r-- | src/libstrongswan/asn1/asn1.c | 366 | ||||
-rw-r--r-- | src/libstrongswan/asn1/asn1.h | 223 | ||||
-rw-r--r-- | src/libstrongswan/asn1/asn1_parser.c | 302 | ||||
-rw-r--r-- | src/libstrongswan/asn1/asn1_parser.h | 119 | ||||
-rw-r--r-- | src/libstrongswan/asn1/oid.c | 276 | ||||
-rw-r--r-- | src/libstrongswan/asn1/oid.h | 124 | ||||
-rw-r--r-- | src/libstrongswan/asn1/oid.txt | 70 | ||||
-rwxr-xr-x | src/libstrongswan/asn1/pem.c | 108 | ||||
-rwxr-xr-x | src/libstrongswan/asn1/pem.h | 14 | ||||
-rw-r--r-- | src/libstrongswan/asn1/ttodata.c | 433 | ||||
-rw-r--r-- | src/libstrongswan/asn1/ttodata.h | 28 |
11 files changed, 1085 insertions, 978 deletions
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c index 3f0b829a9..524abfe5e 100644 --- a/src/libstrongswan/asn1/asn1.c +++ b/src/libstrongswan/asn1/asn1.c @@ -1,10 +1,3 @@ -/** - * @file asn1.c - * - * @brief Simple ASN.1 parser - * - */ - /* * Copyright (C) 2006 Martin Will * Copyright (C) 2000-2008 Andreas Steffen @@ -21,19 +14,23 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: asn1.c 3451 2008-02-05 19:27:05Z andreas $ + * $Id: asn1.c 4047 2008-06-10 07:36:44Z tobias $ */ #include <stdio.h> #include <string.h> #include <time.h> -#include "asn1.h" - #include <library.h> #include <debug.h> -/* some common prefabricated ASN.1 constants */ +#include "oid.h" +#include "asn1.h" +#include "asn1_parser.h" + +/** + * 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 }; @@ -42,7 +39,9 @@ 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 */ +/** + * some popular algorithmIdentifiers + */ static u_char ASN1_md2_id_str[] = { 0x30, 0x0c, @@ -149,19 +148,8 @@ static const chunk_t ASN1_sha256WithRSA_id = chunk_from_buf(ASN1_sha256WithRSA_i static const chunk_t ASN1_sha384WithRSA_id = chunk_from_buf(ASN1_sha384WithRSA_id_str); static const chunk_t ASN1_sha512WithRSA_id = chunk_from_buf(ASN1_sha512WithRSA_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 +/* + * Defined in header. */ chunk_t asn1_algorithmIdentifier(int oid) { @@ -198,11 +186,10 @@ chunk_t asn1_algorithmIdentifier(int oid) } } -/** - * 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 +/* + * Defined in header. */ -int known_oid(chunk_t object) +int asn1_known_oid(chunk_t object) { int oid = 0; @@ -230,8 +217,8 @@ int known_oid(chunk_t object) return -1; } -/** - * Decodes the length in bytes of an ASN.1 object +/* + * Defined in header. */ u_int asn1_length(chunk_t *blob) { @@ -278,26 +265,9 @@ u_int asn1_length(chunk_t *blob) } /** - * 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; -} - -/** * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time */ -time_t asn1totime(const chunk_t *utctime, asn1_t type) +time_t asn1_to_time(const chunk_t *utctime, asn1_t type) { struct tm t; time_t tz_offset; @@ -372,7 +342,7 @@ time_t asn1totime(const chunk_t *utctime, asn1_t type) /** * Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format */ -chunk_t timetoasn1(const time_t *time, asn1_t type) +chunk_t asn1_from_time(const time_t *time, asn1_t type) { int offset; const char *format; @@ -397,31 +367,17 @@ chunk_t timetoasn1(const time_t *time, asn1_t type) return asn1_simple_object(type, formatted_time); } - -/** - * Initializes the internal context of the ASN.1 parser - */ -void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, - bool implicit, bool private) -{ - ctx->blobs[0] = blob; - ctx->level0 = level0; - ctx->implicit = implicit; - ctx->private = private; - memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr)); -} - -/** - * print the value of an ASN.1 simple object +/* + * Defined in header. */ -static void debug_asn1_simple_object(chunk_t object, asn1_t type, bool private) +void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private) { int oid; switch (type) { case ASN1_OID: - oid = known_oid(object); + oid = asn1_known_oid(object); if (oid != OID_UNKNOWN) { DBG2(" '%s'", oid_names[oid].name); @@ -438,7 +394,7 @@ static void debug_asn1_simple_object(chunk_t object, asn1_t type, bool private) case ASN1_UTCTIME: case ASN1_GENERALIZEDTIME: { - time_t time = asn1totime(&object, type); + time_t time = asn1_to_time(&object, type); DBG2(" '%T'", &time); } @@ -457,147 +413,9 @@ static void debug_asn1_simple_object(chunk_t object, asn1_t type, bool private) } /** - * 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_empty; - - 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 */ - DBG2("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) - { - DBG1("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) - { - DBG1("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) - { - DBG2("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)) - { - DBG1("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", - *level, obj.name, obj.type, *start_ptr); - DBG3("%b", start_ptr, (u_int)(blob->ptr - start_ptr)); - return FALSE; - } - - DBG2("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); - if (ctx->private) - { - DBG4("%B", object); - } - else - { - DBG3("%B", object); - } - } - else if (obj.flags & ASN1_BODY) - { - *object = *blob1; - debug_asn1_simple_object(*object, obj.type, ctx->private); - } - 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) +bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name) { size_t len; @@ -625,44 +443,69 @@ bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const c } DBG2("L%d - %s:", level, name); - debug_asn1_simple_object(*object, type, FALSE); + asn1_debug_simple_object(*object, type, FALSE); return TRUE; } /** - * extracts an algorithmIdentifier + * ASN.1 definition 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 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +/* parameters are optional in case of ecdsa-with-SHA1 as algorithm (RFC 3279) */ +static const asn1Object_t algorithmIdentifierObjectsOptional[] = { + { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */ + { 1, "parameters", ASN1_EOC, ASN1_RAW|ASN1_OPT }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define ALGORITHM_ID_ALG 1 +#define ALGORITHM_ID_PARAMETERS 2 + +/* + * Defined in header */ -int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters) +int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; + int objectID; int alg = OID_UNKNOWN; - int objectID = 0; + const asn1Object_t *objects = algorithmIdentifierObjectsOptional; - asn1_init(&ctx, blob, level0, FALSE, FALSE); + if (parameters != NULL) + { + objects = algorithmIdentifierObjects; + } + + parser = asn1_parser_create(objects, blob); + parser->set_top_level(parser, level0); - while (objectID < ALGORITHM_ID_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx)) - return OID_UNKNOWN; - switch (objectID) { case ALGORITHM_ID_ALG: - alg = known_oid(object); + alg = asn1_known_oid(object); break; case ALGORITHM_ID_PARAMETERS: if (parameters != NULL) + { *parameters = object; + } break; default: break; } - objectID++; } + parser->destroy(parser); return alg; - } +} /* * tests if a blob contains a valid ASN.1 set or sequence @@ -696,10 +539,27 @@ bool is_asn1(chunk_t blob) return FALSE; } +/* + * Defined in header. + */ +bool asn1_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; +} + /** * codes ASN.1 lengths up to a size of 16'777'215 bytes */ -void code_asn1_length(size_t length, chunk_t *code) +static void asn1_code_length(size_t length, chunk_t *code) { if (length < 128) { @@ -732,14 +592,14 @@ void code_asn1_length(size_t length, chunk_t *code) /** * 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* asn1_build_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); + asn1_code_length(datalen, &length); /* allocate memory for the asn.1 TLV object */ object->len = 1 + length.len + datalen; @@ -759,13 +619,13 @@ u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen) } /** - * build a simple ASN.1 object + * 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); + u_char *pos = asn1_build_object(&object, tag, content.len); memcpy(pos, content.ptr, content.len); pos += content.len; @@ -778,7 +638,7 @@ chunk_t asn1_simple_object(asn1_t tag, chunk_t content) chunk_t asn1_bitstring(const char *mode, chunk_t content) { chunk_t object; - u_char *pos = build_asn1_object(&object, ASN1_BIT_STRING, 1 + content.len); + u_char *pos = asn1_build_object(&object, ASN1_BIT_STRING, 1 + content.len); *pos++ = 0x00; memcpy(pos, content.ptr, content.len); @@ -812,7 +672,7 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...) va_end(chunks); /* allocate needed memory for construct */ - pos = build_asn1_object(&construct, type, construct.len); + pos = asn1_build_object(&construct, type, construct.len); /* copy or move the chunks */ va_start(chunks, mode); @@ -834,55 +694,39 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...) } /** - * 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); -} - -/** * 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 */ + { 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 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; #define TIME_UTC 0 #define TIME_GENERALIZED 2 -#define TIME_ROOF 4 /** * extracts and converts a UTCTIME or GENERALIZEDTIME object */ -time_t parse_time(chunk_t blob, int level0) +time_t asn1_parse_time(chunk_t blob, int level0) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; + time_t utc_time = 0; - asn1_init(&ctx, blob, level0, FALSE, FALSE); + parser= asn1_parser_create(timeObjects, blob); + parser->set_top_level(parser, level0); - while (objectID < TIME_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - 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); + utc_time = asn1_to_time(&object, (objectID == TIME_UTC) + ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME); } - objectID++; } - return 0; + parser->destroy(parser); + return utc_time; } diff --git a/src/libstrongswan/asn1/asn1.h b/src/libstrongswan/asn1/asn1.h index d9d85ba44..0f2e6e5c0 100644 --- a/src/libstrongswan/asn1/asn1.h +++ b/src/libstrongswan/asn1/asn1.h @@ -1,10 +1,3 @@ -/** - * @file asn1.h - * - * @brief Simple ASN.1 parser - * - */ - /* * Copyright (C) 2006 Martin Will * Copyright (C) 2000-2008 Andreas Steffen @@ -21,23 +14,23 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: asn1.h 3423 2008-01-22 10:32:37Z andreas $ + * $Id: asn1.h 3876 2008-04-26 09:24:14Z andreas $ + */ + +/** + * @defgroup asn1i asn1 + * @{ @ingroup asn1 */ -#ifndef _ASN1_H -#define _ASN1_H +#ifndef ASN1_H_ +#define ASN1_H_ #include <stdarg.h> -#include <gmp.h> #include <library.h> -#include <asn1/oid.h> - /** - * @brief Definition of some primitive ASN1 types - * - * @ingroup asn1 + * Definition of some primitive ASN1 types */ typedef enum { ASN1_EOC = 0x00, @@ -65,7 +58,6 @@ typedef enum { ASN1_CONSTRUCTED = 0x20, ASN1_SEQUENCE = 0x30, - ASN1_SET = 0x31, ASN1_CONTEXT_S_0 = 0x80, @@ -86,64 +78,155 @@ typedef enum { ASN1_CONTEXT_C_5 = 0xA5 } asn1_t; -/* Definition of ASN1 flags */ +#define ASN1_INVALID_LENGTH 0xffffffff -#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 +/** + * 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; -#define ASN1_INVALID_LENGTH 0xffffffff -/* definition of an ASN.1 object */ +/** Some ASN.1 analysis functions */ -typedef struct { - u_int level; - const u_char *name; - asn1_t type; - u_char flags; -} asn1Object_t; +/** + * Returns some popular algorithmIdentifiers + * + * @param oid known OID index + * @return body of the corresponding OID + */ +chunk_t asn1_algorithmIdentifier(int oid); -#define ASN1_MAX_LEVEL 10 +/** + * Converts an ASN.1 OID into a known OID index + * + * @param object body of an OID + * @return index into the oid_names[] table or OID_UNKNOWN + */ +int asn1_known_oid(chunk_t object); -typedef struct { - bool implicit; - bool private; - u_int level0; - u_int loopAddr[ASN1_MAX_LEVEL+1]; - chunk_t blobs[ASN1_MAX_LEVEL+2]; -} asn1_ctx_t; +/** + * Returns the length of an ASN.1 object + * The blob pointer is advanced past the tag length fields + * + * @param pointer to an ASN.1 coded blob + * @return length of ASN.1 object + */ +u_int asn1_length(chunk_t *blob); -/* 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; +/** + * Parses an ASN.1 algorithmIdentifier object + * + * @param blob ASN.1 coded blob + * @param level0 top-most level offset + * @param params returns optional [ASN.1 coded] parameters + * @return known OID index or OID_UNKNOWN + */ +int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *params); + +/** + * Parse the top-most level of an ASN.1 object + * + * @param object ASN.1 coded object + * @param type Expected ASN.1 type + * @param level0 top-most level offset + * @param name descriptive name of object + * @return TRUE if parsing successful + */ +bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level0, + const char* name); + +/** + * Print the value of an ASN.1 simple object + * + * @param object ASN.1 object to be printed + * @param type asn1_t type + * @param private ASN.1 data is confidential (use debug level 4) + */ +void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private); + +/** + * Converts an ASN.1 UTCTIME or GENERALIZEDTIME string to time_t + * + * @param utctime body of an ASN.1 coded time object + * @param type ASN1_UTCTIME or ASN1_GENERALIZEDTIME + * @return time_t in UTC + */ +time_t asn1_to_time(const chunk_t *utctime, asn1_t type); + +/** + * Converts time_t to an ASN.1 UTCTIME or GENERALIZEDTIME string + * + * @param time time_t in UTC + * @param type ASN1_UTCTIME or ASN1_GENERALIZEDTIME + * @return body of an ASN.1 code time object + */ +chunk_t asn1_from_time(const time_t *time, asn1_t type); + +/** + * Parse an ASN.1 UTCTIME or GENERALIZEDTIME object + * + * @param blob ASN.1 coded time object + * @param level top-most level offset + * @return time_t in UTC + */ +time_t asn1_parse_time(chunk_t blob, int level0); + +/** + * Determines if a binary blob is ASN.1 coded + * + * @param blob blob to be tested + * @return TRUE if blob is ASN.1 coded (SEQUENCE or SET) + */ +bool is_asn1(chunk_t blob); + +/** + * Determines if a character string can be coded as PRINTABLESTRING + * + * @param str character string to be tested + * @return TRUE if no special characters are contained + */ +bool asn1_is_printablestring(chunk_t str); + + +/** some ASN.1 synthesis functions */ + +/** + * Build an empty ASN.1 object with tag and length fields already filled in + * + * @param object returned object - memory is allocated by function + * @param type ASN.1 type to be created + * @param datalen size of the body to be created + * @return points to the first position in the body + */ +u_char* asn1_build_object(chunk_t *object, asn1_t type, size_t datalen); + +/** + * Build a simple ASN.1 object + * + * @param tag ASN.1 type to be created + * @param content content of the ASN.1 object + * @return chunk containing the ASN.1 coded object + */ +chunk_t asn1_simple_object(asn1_t tag, chunk_t content); + +/** + * Build an ASN.1 BITSTRING object + * + * @param mode 'c' for copy or 'm' for move + * @param content content of the BITSTRING + * @return chunk containing the ASN.1 coded BITSTRING + */ +chunk_t asn1_bitstring(const char *mode, chunk_t content); + +/** + * Build an ASN.1 object from a variable number of individual chunks + * + * @param typ ASN.1 type to be created + * @param mode for each list member: 'c' for copy or 'm' for move + * @return chunk containing the ASN.1 coded object + */ +chunk_t asn1_wrap(asn1_t type, const char *mode, ...); -/* returns some popular algorithmIdentifiers */ -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 chunk_t timetoasn1(const time_t *time, asn1_t type); -extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit, bool private); -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 time_t parse_time(chunk_t blob, int level0); - -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_bitstring(const char *mode, chunk_t content); -extern chunk_t asn1_wrap(asn1_t type, const char *mode, ...); - -#endif /* _ASN1_H */ +#endif /* ASN1_H_ @}*/ diff --git a/src/libstrongswan/asn1/asn1_parser.c b/src/libstrongswan/asn1/asn1_parser.c new file mode 100644 index 000000000..7a2028fc3 --- /dev/null +++ b/src/libstrongswan/asn1/asn1_parser.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2006 Martin Will + * Copyright (C) 2000-2008 Andreas Steffen + * + * 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. + * + * $Id: asn1_parser.c 3894 2008-04-28 18:44:21Z andreas $ + */ + +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include <library.h> +#include <debug.h> + +#include "asn1.h" +#include "asn1_parser.h" + +#define ASN1_MAX_LEVEL 10 + +typedef struct private_asn1_parser_t private_asn1_parser_t; + +/** + * Private data of an asn1_cxt_t object. + */ +struct private_asn1_parser_t { + /** + * Public interface. + */ + asn1_parser_t public; + + /** + * Syntax definition of ASN.1 object + */ + asn1Object_t const *objects; + + /** + * Current syntax definition line + */ + int line; + + /** + * Current stat of the parsing operation + */ + bool success; + + /** + * Declare object data as private - use debug level 4 to log it + */ + bool private; + + /** + * Top-most type is implicit - ignore it + */ + bool implicit; + + /** + * Top-most parsing level - defaults to 0 + */ + u_int level0; + + /** + * Jump back address for loops for each level + */ + int loopAddr[ASN1_MAX_LEVEL + 1]; + + /** + * Current parsing pointer for each level + */ + chunk_t blobs[ASN1_MAX_LEVEL + 2]; +}; + +/** + * Implementation of asn1_parser_t.iterate + */ +static bool iterate(private_asn1_parser_t *this, int *objectID, chunk_t *object) +{ + chunk_t *blob, *blob1; + u_char *start_ptr; + u_int level; + asn1Object_t obj; + + *object = chunk_empty; + + /* Advance to the next object syntax definition line */ + obj = this->objects[++(this->line)]; + + /* Terminate if the end of the object syntax definition has been reached */ + if (obj.flags & ASN1_EXIT) + { + return FALSE; + } + + if (obj.flags & ASN1_END) /* end of loop or option found */ + { + if (this->loopAddr[obj.level] && this->blobs[obj.level+1].len > 0) + { + this->line = this->loopAddr[obj.level]; /* another iteration */ + obj = this->objects[this->line]; + } + else + { + this->loopAddr[obj.level] = 0; /* exit loop or option*/ + goto end; + } + } + + level = this->level0 + obj.level; + blob = this->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 */ + DBG2("L%d - %s:", level, obj.name); + if (obj.type & ASN1_CONSTRUCTED) + { + this->line++ ; /* skip context-specific tag */ + } + goto end; + } + + /* handle ASN.1 options */ + + if ((obj.flags & ASN1_OPT) + && (blob->len == 0 || *start_ptr != obj.type)) + { + /* advance to end of missing option field */ + do + { + this->line++; + } + while (!((this->objects[this->line].flags & ASN1_END) && + (this->objects[this->line].level == obj.level))); + goto end; + } + + /* an ASN.1 object must possess at least a tag and length field */ + + if (blob->len < 2) + { + DBG1("L%d - %s: ASN.1 object smaller than 2 octets", + level, obj.name); + this->success = FALSE; + goto end; + } + + blob1->len = asn1_length(blob); + + if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len) + { + DBG1("L%d - %s: length of ASN.1 object invalid or too large", + level, obj.name); + this->success = 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) + { + DBG2("L%d - %s:", level, obj.name); + object->ptr = start_ptr; + object->len = (size_t)(blob->ptr - start_ptr); + goto end; + } + + if (*start_ptr != obj.type && !(this->implicit && this->line == 0)) + { + DBG1("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", + level, obj.name, obj.type, *start_ptr); + DBG3("%b", start_ptr, (u_int)(blob->ptr - start_ptr)); + this->success = FALSE; + goto end; + } + + DBG2("L%d - %s:", 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 */ + this->loopAddr[obj.level] = this->line + 1; + } + else + { + /* no items, advance directly to end of loop */ + do + { + this->line++; + } + while (!((this->objects[this->line].flags & ASN1_END) && + (this->objects[this->line].level == obj.level))); + goto end; + } + } + + if (obj.flags & ASN1_OBJ) + { + object->ptr = start_ptr; + object->len = (size_t)(blob->ptr - start_ptr); + if (this->private) + { + DBG4("%B", object); + } + else + { + DBG3("%B", object); + } + } + else if (obj.flags & ASN1_BODY) + { + *object = *blob1; + asn1_debug_simple_object(*object, obj.type, this->private); + } + +end: + *objectID = this->line; + return this->success; +} + +/** + * Implementation of asn1_parser_t.get_level + */ +static u_int get_level(private_asn1_parser_t *this) +{ + return this->level0 + this->objects[this->line].level; +} + +/** + * Implementation of asn1_parser_t.set_top_level + */ +static void set_top_level(private_asn1_parser_t *this, u_int level0) +{ + this->level0 = level0; +} + +/** + * Implementation of asn1_parser_t.set_flags + */ +static void set_flags(private_asn1_parser_t *this, bool implicit, bool private) +{ + this->implicit = implicit; + this->private = private; +} + +/** + * Implementation of asn1_parser_t.success + */ +static bool success(private_asn1_parser_t *this) +{ + return this->success; +} + +/** + * Implementation of asn1_parser_t.destroy + */ +static void destroy(private_asn1_parser_t *this) +{ + free(this); +} + +/** + * Defined in header. + */ +asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, chunk_t blob) +{ + private_asn1_parser_t *this = malloc_thing(private_asn1_parser_t); + + memset(this, '\0', sizeof(private_asn1_parser_t)); + this->objects = objects; + this->blobs[0] = blob; + this->line = -1; + this->success = TRUE; + + this->public.iterate = (bool (*)(asn1_parser_t*, int*, chunk_t*))iterate; + this->public.get_level = (u_int (*)(asn1_parser_t*))get_level; + this->public.set_top_level = (void (*)(asn1_parser_t*, u_int))set_top_level; + this->public.set_flags = (void (*)(asn1_parser_t*, bool, bool))set_flags; + this->public.success = (bool (*)(asn1_parser_t*))success; + this->public.destroy = (void (*)(asn1_parser_t*))destroy; + + return &this->public; +} diff --git a/src/libstrongswan/asn1/asn1_parser.h b/src/libstrongswan/asn1/asn1_parser.h new file mode 100644 index 000000000..d84a5336f --- /dev/null +++ b/src/libstrongswan/asn1/asn1_parser.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2006 Martin Will + * Copyright (C) 2000-2008 Andreas Steffen + * + * 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. + * + * $Id: asn1_parser.h 3894 2008-04-28 18:44:21Z andreas $ + */ + +/** + * @defgroup asn1_parser asn1_parser + * @{ @ingroup asn1 + */ + +#ifndef ASN1_PARSER_H_ +#define ASN1_PARSER_H_ + +#include <stdarg.h> + +#include <library.h> + +/** + * Definition of ASN.1 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_EXIT 0x80 + +typedef struct asn1Object_t asn1Object_t; + +/** + * Syntax definition of an ASN.1 object + */ +struct asn1Object_t{ + u_int level; + const u_char *name; + asn1_t type; + u_char flags; +}; + +typedef struct asn1_parser_t asn1_parser_t; + +/** + * Public interface of an ASN.1 parser + */ +struct asn1_parser_t { + + /** + * Parse the next ASN.1 object in the hierarchy and return it + * + * @param objectID current line in the object syntax definition + * @param object current object + * @return - FALSE if end of object syntax definition was reached + * or a parsing error occurred + * - TRUE otherwise + */ + bool (*iterate)(asn1_parser_t *this, int *objectID, chunk_t *object); + + /** + * Get the current parsing level + * + * @return current level + */ + u_int (*get_level)(asn1_parser_t *this); + + /** + * Set the top-most level + * + * @param level top-most level + */ + void (*set_top_level)(asn1_parser_t *this, u_int level0); + + /** + * Set implicit and private flags + * + * @param implicit top-most type of object is implicit + * @param private object data is private (use debug level 4) + */ + void (*set_flags)(asn1_parser_t *this, bool implicit, bool private); + + /** + * Show final parsing status + * + * @return TRUE if parsing was successful, FALSE otherwise + */ + bool (*success)(asn1_parser_t *this); + + /** + * Destroy the ASN.1 parser + */ + void (*destroy)(asn1_parser_t *this); +}; + +/** + * Create an ASN.1 parser + * + * @param objects syntax definition of the ASN.1 object to be parsed + * @param blob ASN.1 coded binary blob + * @return ASN.1 context + */ +asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, chunk_t blob); + +#endif /* ASN1_PARSER_H_ @}*/ diff --git a/src/libstrongswan/asn1/oid.c b/src/libstrongswan/asn1/oid.c index 63896be6b..f9eb26d1d 100644 --- a/src/libstrongswan/asn1/oid.c +++ b/src/libstrongswan/asn1/oid.c @@ -62,10 +62,10 @@ const oid_t oid_names[] = { { 0x25, 50, 0, "extendedKeyUsage" }, /* 49 */ { 0x37, 51, 0, "targetInformation" }, /* 50 */ { 0x38, 0, 0, "noRevAvail" }, /* 51 */ - {0x2A, 95, 1, "" }, /* 52 */ + {0x2A, 131, 1, "" }, /* 52 */ { 0x86, 0, 1, "" }, /* 53 */ { 0x48, 0, 1, "" }, /* 54 */ - { 0x86, 0, 1, "" }, /* 55 */ + { 0x86, 95, 1, "" }, /* 55 */ { 0xF6, 61, 1, "" }, /* 56 */ { 0x7D, 0, 1, "NortelNetworks" }, /* 57 */ { 0x07, 0, 1, "Entrust" }, /* 58 */ @@ -105,105 +105,175 @@ const oid_t oid_names[] = { { 0x05, 0, 0, "md5" }, /* 92 */ { 0x03, 0, 1, "encryptionAlgorithm" }, /* 93 */ { 0x07, 0, 0, "3des-ede-cbc" }, /* 94 */ - {0x2B, 161, 1, "" }, /* 95 */ - { 0x06, 148, 1, "dod" }, /* 96 */ - { 0x01, 0, 1, "internet" }, /* 97 */ - { 0x04, 116, 1, "private" }, /* 98 */ - { 0x01, 0, 1, "enterprise" }, /* 99 */ - { 0x82, 109, 1, "" }, /* 100 */ - { 0x37, 0, 1, "Microsoft" }, /* 101 */ - { 0x0A, 106, 1, "" }, /* 102 */ - { 0x03, 0, 1, "" }, /* 103 */ - { 0x03, 105, 0, "msSGC" }, /* 104 */ - { 0x04, 0, 0, "msEncryptingFileSystem" }, /* 105 */ - { 0x14, 0, 1, "msEnrollmentInfrastructure"}, /* 106 */ - { 0x02, 0, 1, "msCertificateTypeExtension"}, /* 107 */ - { 0x02, 0, 0, "msSmartcardLogon" }, /* 108 */ - { 0x89, 0, 1, "" }, /* 109 */ - { 0x31, 0, 1, "" }, /* 110 */ - { 0x01, 0, 1, "" }, /* 111 */ - { 0x01, 0, 1, "" }, /* 112 */ - { 0x02, 0, 1, "" }, /* 113 */ - { 0x02, 115, 0, "" }, /* 114 */ - { 0x4B, 0, 0, "TCGID" }, /* 115 */ - { 0x05, 0, 1, "security" }, /* 116 */ - { 0x05, 0, 1, "mechanisms" }, /* 117 */ - { 0x07, 0, 1, "id-pkix" }, /* 118 */ - { 0x01, 121, 1, "id-pe" }, /* 119 */ - { 0x01, 0, 0, "authorityInfoAccess" }, /* 120 */ - { 0x03, 131, 1, "id-kp" }, /* 121 */ - { 0x01, 123, 0, "serverAuth" }, /* 122 */ - { 0x02, 124, 0, "clientAuth" }, /* 123 */ - { 0x03, 125, 0, "codeSigning" }, /* 124 */ - { 0x04, 126, 0, "emailProtection" }, /* 125 */ - { 0x05, 127, 0, "ipsecEndSystem" }, /* 126 */ - { 0x06, 128, 0, "ipsecTunnel" }, /* 127 */ - { 0x07, 129, 0, "ipsecUser" }, /* 128 */ - { 0x08, 130, 0, "timeStamping" }, /* 129 */ - { 0x09, 0, 0, "ocspSigning" }, /* 130 */ - { 0x08, 133, 1, "id-otherNames" }, /* 131 */ - { 0x05, 0, 0, "xmppAddr" }, /* 132 */ - { 0x0A, 138, 1, "id-aca" }, /* 133 */ - { 0x01, 135, 0, "authenticationInfo" }, /* 134 */ - { 0x02, 136, 0, "accessIdentity" }, /* 135 */ - { 0x03, 137, 0, "chargingIdentity" }, /* 136 */ - { 0x04, 0, 0, "group" }, /* 137 */ - { 0x30, 0, 1, "id-ad" }, /* 138 */ - { 0x01, 147, 1, "ocsp" }, /* 139 */ - { 0x01, 141, 0, "basic" }, /* 140 */ - { 0x02, 142, 0, "nonce" }, /* 141 */ - { 0x03, 143, 0, "crl" }, /* 142 */ - { 0x04, 144, 0, "response" }, /* 143 */ - { 0x05, 145, 0, "noCheck" }, /* 144 */ - { 0x06, 146, 0, "archiveCutoff" }, /* 145 */ - { 0x07, 0, 0, "serviceLocator" }, /* 146 */ - { 0x02, 0, 0, "caIssuers" }, /* 147 */ - { 0x0E, 154, 1, "oiw" }, /* 148 */ - { 0x03, 0, 1, "secsig" }, /* 149 */ - { 0x02, 0, 1, "algorithms" }, /* 150 */ - { 0x07, 152, 0, "des-cbc" }, /* 151 */ - { 0x1A, 153, 0, "sha-1" }, /* 152 */ - { 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 153 */ - { 0x24, 0, 1, "TeleTrusT" }, /* 154 */ - { 0x03, 0, 1, "algorithm" }, /* 155 */ - { 0x03, 0, 1, "signatureAlgorithm" }, /* 156 */ - { 0x01, 0, 1, "rsaSignature" }, /* 157 */ - { 0x02, 159, 0, "rsaSigWithripemd160" }, /* 158 */ - { 0x03, 160, 0, "rsaSigWithripemd128" }, /* 159 */ - { 0x04, 0, 0, "rsaSigWithripemd256" }, /* 160 */ - {0x60, 0, 1, "" }, /* 161 */ - { 0x86, 0, 1, "" }, /* 162 */ - { 0x48, 0, 1, "" }, /* 163 */ - { 0x01, 0, 1, "organization" }, /* 164 */ - { 0x65, 172, 1, "gov" }, /* 165 */ - { 0x03, 0, 1, "csor" }, /* 166 */ - { 0x04, 0, 1, "nistalgorithm" }, /* 167 */ - { 0x02, 0, 1, "hashalgs" }, /* 168 */ - { 0x01, 170, 0, "id-SHA-256" }, /* 169 */ - { 0x02, 171, 0, "id-SHA-384" }, /* 170 */ - { 0x03, 0, 0, "id-SHA-512" }, /* 171 */ - { 0x86, 0, 1, "" }, /* 172 */ - { 0xf8, 0, 1, "" }, /* 173 */ - { 0x42, 186, 1, "netscape" }, /* 174 */ - { 0x01, 181, 1, "" }, /* 175 */ - { 0x01, 177, 0, "nsCertType" }, /* 176 */ - { 0x03, 178, 0, "nsRevocationUrl" }, /* 177 */ - { 0x04, 179, 0, "nsCaRevocationUrl" }, /* 178 */ - { 0x08, 180, 0, "nsCaPolicyUrl" }, /* 179 */ - { 0x0d, 0, 0, "nsComment" }, /* 180 */ - { 0x03, 184, 1, "directory" }, /* 181 */ - { 0x01, 0, 1, "" }, /* 182 */ - { 0x03, 0, 0, "employeeNumber" }, /* 183 */ - { 0x04, 0, 1, "policy" }, /* 184 */ - { 0x01, 0, 0, "nsSGC" }, /* 185 */ - { 0x45, 0, 1, "verisign" }, /* 186 */ - { 0x01, 0, 1, "pki" }, /* 187 */ - { 0x09, 0, 1, "attributes" }, /* 188 */ - { 0x02, 190, 0, "messageType" }, /* 189 */ - { 0x03, 191, 0, "pkiStatus" }, /* 190 */ - { 0x04, 192, 0, "failInfo" }, /* 191 */ - { 0x05, 193, 0, "senderNonce" }, /* 192 */ - { 0x06, 194, 0, "recipientNonce" }, /* 193 */ - { 0x07, 195, 0, "transID" }, /* 194 */ - { 0x08, 0, 0, "extensionReq" } /* 195 */ + { 0xCE, 0, 1, "" }, /* 95 */ + { 0x3D, 0, 1, "ansi-X9-62" }, /* 96 */ + { 0x02, 99, 1, "id-publicKeyType" }, /* 97 */ + { 0x01, 0, 0, "id-ecPublicKey" }, /* 98 */ + { 0x03, 129, 1, "ellipticCurve" }, /* 99 */ + { 0x00, 121, 1, "c-TwoCurve" }, /* 100 */ + { 0x01, 102, 0, "c2pnb163v1" }, /* 101 */ + { 0x02, 103, 0, "c2pnb163v2" }, /* 102 */ + { 0x03, 104, 0, "c2pnb163v3" }, /* 103 */ + { 0x04, 105, 0, "c2pnb176w1" }, /* 104 */ + { 0x05, 106, 0, "c2tnb191v1" }, /* 105 */ + { 0x06, 107, 0, "c2tnb191v2" }, /* 106 */ + { 0x07, 108, 0, "c2tnb191v3" }, /* 107 */ + { 0x08, 109, 0, "c2onb191v4" }, /* 108 */ + { 0x09, 110, 0, "c2onb191v5" }, /* 109 */ + { 0x0A, 111, 0, "c2pnb208w1" }, /* 110 */ + { 0x0B, 112, 0, "c2tnb239v1" }, /* 111 */ + { 0x0C, 113, 0, "c2tnb239v2" }, /* 112 */ + { 0x0D, 114, 0, "c2tnb239v3" }, /* 113 */ + { 0x0E, 115, 0, "c2onb239v4" }, /* 114 */ + { 0x0F, 116, 0, "c2onb239v5" }, /* 115 */ + { 0x10, 117, 0, "c2pnb272w1" }, /* 116 */ + { 0x11, 118, 0, "c2pnb304w1" }, /* 117 */ + { 0x12, 119, 0, "c2tnb359v1" }, /* 118 */ + { 0x13, 120, 0, "c2pnb368w1" }, /* 119 */ + { 0x14, 0, 0, "c2tnb431r1" }, /* 120 */ + { 0x01, 0, 1, "primeCurve" }, /* 121 */ + { 0x01, 123, 0, "prime192v1" }, /* 122 */ + { 0x02, 124, 0, "prime192v2" }, /* 123 */ + { 0x03, 125, 0, "prime192v3" }, /* 124 */ + { 0x04, 126, 0, "prime239v1" }, /* 125 */ + { 0x05, 127, 0, "prime239v2" }, /* 126 */ + { 0x06, 128, 0, "prime239v3" }, /* 127 */ + { 0x07, 0, 0, "prime256v1" }, /* 128 */ + { 0x04, 0, 1, "id-ecSigType" }, /* 129 */ + { 0x01, 0, 0, "ecdsa-with-SHA1" }, /* 130 */ + {0x2B, 231, 1, "" }, /* 131 */ + { 0x06, 184, 1, "dod" }, /* 132 */ + { 0x01, 0, 1, "internet" }, /* 133 */ + { 0x04, 152, 1, "private" }, /* 134 */ + { 0x01, 0, 1, "enterprise" }, /* 135 */ + { 0x82, 145, 1, "" }, /* 136 */ + { 0x37, 0, 1, "Microsoft" }, /* 137 */ + { 0x0A, 142, 1, "" }, /* 138 */ + { 0x03, 0, 1, "" }, /* 139 */ + { 0x03, 141, 0, "msSGC" }, /* 140 */ + { 0x04, 0, 0, "msEncryptingFileSystem" }, /* 141 */ + { 0x14, 0, 1, "msEnrollmentInfrastructure"}, /* 142 */ + { 0x02, 0, 1, "msCertificateTypeExtension"}, /* 143 */ + { 0x02, 0, 0, "msSmartcardLogon" }, /* 144 */ + { 0x89, 0, 1, "" }, /* 145 */ + { 0x31, 0, 1, "" }, /* 146 */ + { 0x01, 0, 1, "" }, /* 147 */ + { 0x01, 0, 1, "" }, /* 148 */ + { 0x02, 0, 1, "" }, /* 149 */ + { 0x02, 151, 0, "" }, /* 150 */ + { 0x4B, 0, 0, "TCGID" }, /* 151 */ + { 0x05, 0, 1, "security" }, /* 152 */ + { 0x05, 0, 1, "mechanisms" }, /* 153 */ + { 0x07, 0, 1, "id-pkix" }, /* 154 */ + { 0x01, 157, 1, "id-pe" }, /* 155 */ + { 0x01, 0, 0, "authorityInfoAccess" }, /* 156 */ + { 0x03, 167, 1, "id-kp" }, /* 157 */ + { 0x01, 159, 0, "serverAuth" }, /* 158 */ + { 0x02, 160, 0, "clientAuth" }, /* 159 */ + { 0x03, 161, 0, "codeSigning" }, /* 160 */ + { 0x04, 162, 0, "emailProtection" }, /* 161 */ + { 0x05, 163, 0, "ipsecEndSystem" }, /* 162 */ + { 0x06, 164, 0, "ipsecTunnel" }, /* 163 */ + { 0x07, 165, 0, "ipsecUser" }, /* 164 */ + { 0x08, 166, 0, "timeStamping" }, /* 165 */ + { 0x09, 0, 0, "ocspSigning" }, /* 166 */ + { 0x08, 169, 1, "id-otherNames" }, /* 167 */ + { 0x05, 0, 0, "xmppAddr" }, /* 168 */ + { 0x0A, 174, 1, "id-aca" }, /* 169 */ + { 0x01, 171, 0, "authenticationInfo" }, /* 170 */ + { 0x02, 172, 0, "accessIdentity" }, /* 171 */ + { 0x03, 173, 0, "chargingIdentity" }, /* 172 */ + { 0x04, 0, 0, "group" }, /* 173 */ + { 0x30, 0, 1, "id-ad" }, /* 174 */ + { 0x01, 183, 1, "ocsp" }, /* 175 */ + { 0x01, 177, 0, "basic" }, /* 176 */ + { 0x02, 178, 0, "nonce" }, /* 177 */ + { 0x03, 179, 0, "crl" }, /* 178 */ + { 0x04, 180, 0, "response" }, /* 179 */ + { 0x05, 181, 0, "noCheck" }, /* 180 */ + { 0x06, 182, 0, "archiveCutoff" }, /* 181 */ + { 0x07, 0, 0, "serviceLocator" }, /* 182 */ + { 0x02, 0, 0, "caIssuers" }, /* 183 */ + { 0x0E, 190, 1, "oiw" }, /* 184 */ + { 0x03, 0, 1, "secsig" }, /* 185 */ + { 0x02, 0, 1, "algorithms" }, /* 186 */ + { 0x07, 188, 0, "des-cbc" }, /* 187 */ + { 0x1A, 189, 0, "sha-1" }, /* 188 */ + { 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 189 */ + { 0x24, 197, 1, "TeleTrusT" }, /* 190 */ + { 0x03, 0, 1, "algorithm" }, /* 191 */ + { 0x03, 0, 1, "signatureAlgorithm" }, /* 192 */ + { 0x01, 0, 1, "rsaSignature" }, /* 193 */ + { 0x02, 195, 0, "rsaSigWithripemd160" }, /* 194 */ + { 0x03, 196, 0, "rsaSigWithripemd128" }, /* 195 */ + { 0x04, 0, 0, "rsaSigWithripemd256" }, /* 196 */ + { 0x81, 0, 1, "" }, /* 197 */ + { 0x04, 0, 1, "Certicom" }, /* 198 */ + { 0x00, 0, 1, "curve" }, /* 199 */ + { 0x01, 201, 0, "sect163k1" }, /* 200 */ + { 0x02, 202, 0, "sect163r1" }, /* 201 */ + { 0x03, 203, 0, "sect239k1" }, /* 202 */ + { 0x04, 204, 0, "sect113r1" }, /* 203 */ + { 0x05, 205, 0, "sect113r2" }, /* 204 */ + { 0x06, 206, 0, "secp112r1" }, /* 205 */ + { 0x07, 207, 0, "secp112r2" }, /* 206 */ + { 0x08, 208, 0, "secp160r1" }, /* 207 */ + { 0x09, 209, 0, "secp160k1" }, /* 208 */ + { 0x0A, 210, 0, "secp256k1" }, /* 209 */ + { 0x0F, 211, 0, "sect163r2" }, /* 210 */ + { 0x10, 212, 0, "sect283k1" }, /* 211 */ + { 0x11, 213, 0, "sect283r1" }, /* 212 */ + { 0x16, 214, 0, "sect131r1" }, /* 213 */ + { 0x17, 215, 0, "sect131r2" }, /* 214 */ + { 0x18, 216, 0, "sect193r1" }, /* 215 */ + { 0x19, 217, 0, "sect193r2" }, /* 216 */ + { 0x1A, 218, 0, "sect233k1" }, /* 217 */ + { 0x1B, 219, 0, "sect233r1" }, /* 218 */ + { 0x1C, 220, 0, "secp128r1" }, /* 219 */ + { 0x1D, 221, 0, "secp128r2" }, /* 220 */ + { 0x1E, 222, 0, "secp160r2" }, /* 221 */ + { 0x1F, 223, 0, "secp192k1" }, /* 222 */ + { 0x20, 224, 0, "secp224k1" }, /* 223 */ + { 0x21, 225, 0, "secp224r1" }, /* 224 */ + { 0x22, 226, 0, "secp384r1" }, /* 225 */ + { 0x23, 227, 0, "secp521r1" }, /* 226 */ + { 0x24, 228, 0, "sect409k1" }, /* 227 */ + { 0x25, 229, 0, "sect409r1" }, /* 228 */ + { 0x26, 230, 0, "sect571k1" }, /* 229 */ + { 0x27, 0, 0, "sect571r1" }, /* 230 */ + {0x60, 0, 1, "" }, /* 231 */ + { 0x86, 0, 1, "" }, /* 232 */ + { 0x48, 0, 1, "" }, /* 233 */ + { 0x01, 0, 1, "organization" }, /* 234 */ + { 0x65, 242, 1, "gov" }, /* 235 */ + { 0x03, 0, 1, "csor" }, /* 236 */ + { 0x04, 0, 1, "nistalgorithm" }, /* 237 */ + { 0x02, 0, 1, "hashalgs" }, /* 238 */ + { 0x01, 240, 0, "id-SHA-256" }, /* 239 */ + { 0x02, 241, 0, "id-SHA-384" }, /* 240 */ + { 0x03, 0, 0, "id-SHA-512" }, /* 241 */ + { 0x86, 0, 1, "" }, /* 242 */ + { 0xf8, 0, 1, "" }, /* 243 */ + { 0x42, 256, 1, "netscape" }, /* 244 */ + { 0x01, 251, 1, "" }, /* 245 */ + { 0x01, 247, 0, "nsCertType" }, /* 246 */ + { 0x03, 248, 0, "nsRevocationUrl" }, /* 247 */ + { 0x04, 249, 0, "nsCaRevocationUrl" }, /* 248 */ + { 0x08, 250, 0, "nsCaPolicyUrl" }, /* 249 */ + { 0x0d, 0, 0, "nsComment" }, /* 250 */ + { 0x03, 254, 1, "directory" }, /* 251 */ + { 0x01, 0, 1, "" }, /* 252 */ + { 0x03, 0, 0, "employeeNumber" }, /* 253 */ + { 0x04, 0, 1, "policy" }, /* 254 */ + { 0x01, 0, 0, "nsSGC" }, /* 255 */ + { 0x45, 0, 1, "verisign" }, /* 256 */ + { 0x01, 0, 1, "pki" }, /* 257 */ + { 0x09, 0, 1, "attributes" }, /* 258 */ + { 0x02, 260, 0, "messageType" }, /* 259 */ + { 0x03, 261, 0, "pkiStatus" }, /* 260 */ + { 0x04, 262, 0, "failInfo" }, /* 261 */ + { 0x05, 263, 0, "senderNonce" }, /* 262 */ + { 0x06, 264, 0, "recipientNonce" }, /* 263 */ + { 0x07, 265, 0, "transID" }, /* 264 */ + { 0x08, 0, 0, "extensionReq" } /* 265 */ }; diff --git a/src/libstrongswan/asn1/oid.h b/src/libstrongswan/asn1/oid.h index 9980221ab..a0fb95f18 100644 --- a/src/libstrongswan/asn1/oid.h +++ b/src/libstrongswan/asn1/oid.h @@ -49,37 +49,97 @@ extern const oid_t oid_names[]; #define OID_MD2 91 #define OID_MD5 92 #define OID_3DES_EDE_CBC 94 -#define OID_AUTHORITY_INFO_ACCESS 120 -#define OID_OCSP_SIGNING 130 -#define OID_XMPP_ADDR 132 -#define OID_AUTHENTICATION_INFO 134 -#define OID_ACCESS_IDENTITY 135 -#define OID_CHARGING_IDENTITY 136 -#define OID_GROUP 137 -#define OID_OCSP 139 -#define OID_BASIC 140 -#define OID_NONCE 141 -#define OID_CRL 142 -#define OID_RESPONSE 143 -#define OID_NO_CHECK 144 -#define OID_ARCHIVE_CUTOFF 145 -#define OID_SERVICE_LOCATOR 146 -#define OID_CA_ISSUERS 147 -#define OID_DES_CBC 151 -#define OID_SHA1 152 -#define OID_SHA1_WITH_RSA_OIW 153 -#define OID_SHA256 169 -#define OID_SHA384 170 -#define OID_SHA512 171 -#define OID_NS_REVOCATION_URL 177 -#define OID_NS_CA_REVOCATION_URL 178 -#define OID_NS_CA_POLICY_URL 179 -#define OID_NS_COMMENT 180 -#define OID_PKI_MESSAGE_TYPE 189 -#define OID_PKI_STATUS 190 -#define OID_PKI_FAIL_INFO 191 -#define OID_PKI_SENDER_NONCE 192 -#define OID_PKI_RECIPIENT_NONCE 193 -#define OID_PKI_TRANS_ID 194 +#define OID_EC_PUBLICKEY 98 +#define OID_C2PNB163V1 101 +#define OID_C2PNB163V2 102 +#define OID_C2PNB163V3 103 +#define OID_C2PNB176W1 104 +#define OID_C2PNB191V1 105 +#define OID_C2PNB191V2 106 +#define OID_C2PNB191V3 107 +#define OID_C2PNB191V4 108 +#define OID_C2PNB191V5 109 +#define OID_C2PNB208W1 110 +#define OID_C2PNB239V1 111 +#define OID_C2PNB239V2 112 +#define OID_C2PNB239V3 113 +#define OID_C2PNB239V4 114 +#define OID_C2PNB239V5 115 +#define OID_C2PNB272W1 116 +#define OID_C2PNB304W1 117 +#define OID_C2PNB359V1 118 +#define OID_C2PNB368W1 119 +#define OID_C2PNB431R1 120 +#define OID_PRIME192V1 122 +#define OID_PRIME192V2 123 +#define OID_PRIME192V3 124 +#define OID_PRIME239V1 125 +#define OID_PRIME239V2 126 +#define OID_PRIME239V3 127 +#define OID_PRIME256V1 128 +#define OID_ECDSA_WITH_SHA1 130 +#define OID_AUTHORITY_INFO_ACCESS 156 +#define OID_OCSP_SIGNING 166 +#define OID_XMPP_ADDR 168 +#define OID_AUTHENTICATION_INFO 170 +#define OID_ACCESS_IDENTITY 171 +#define OID_CHARGING_IDENTITY 172 +#define OID_GROUP 173 +#define OID_OCSP 175 +#define OID_BASIC 176 +#define OID_NONCE 177 +#define OID_CRL 178 +#define OID_RESPONSE 179 +#define OID_NO_CHECK 180 +#define OID_ARCHIVE_CUTOFF 181 +#define OID_SERVICE_LOCATOR 182 +#define OID_CA_ISSUERS 183 +#define OID_DES_CBC 187 +#define OID_SHA1 188 +#define OID_SHA1_WITH_RSA_OIW 189 +#define OID_SECT163K1 200 +#define OID_SECT163R1 201 +#define OID_SECT239K1 202 +#define OID_SECT113R1 203 +#define OID_SECT113R2 204 +#define OID_SECT112R1 205 +#define OID_SECT112R2 206 +#define OID_SECT160R1 207 +#define OID_SECT160K1 208 +#define OID_SECT256K1 209 +#define OID_SECT163R2 210 +#define OID_SECT283K1 211 +#define OID_SECT283R1 212 +#define OID_SECT131R1 213 +#define OID_SECT131R2 214 +#define OID_SECT193R1 215 +#define OID_SECT193R2 216 +#define OID_SECT233K1 217 +#define OID_SECT233R1 218 +#define OID_SECT128R1 219 +#define OID_SECT128R2 220 +#define OID_SECT160R2 221 +#define OID_SECT192K1 222 +#define OID_SECT224K1 223 +#define OID_SECT224R1 224 +#define OID_SECT384R1 225 +#define OID_SECT521R1 226 +#define OID_SECT409K1 227 +#define OID_SECT409R1 228 +#define OID_SECT571K1 229 +#define OID_SECT571R1 230 +#define OID_SHA256 239 +#define OID_SHA384 240 +#define OID_SHA512 241 +#define OID_NS_REVOCATION_URL 247 +#define OID_NS_CA_REVOCATION_URL 248 +#define OID_NS_CA_POLICY_URL 249 +#define OID_NS_COMMENT 250 +#define OID_PKI_MESSAGE_TYPE 259 +#define OID_PKI_STATUS 260 +#define OID_PKI_FAIL_INFO 261 +#define OID_PKI_SENDER_NONCE 262 +#define OID_PKI_RECIPIENT_NONCE 263 +#define OID_PKI_TRANS_ID 264 #endif /* OID_H_ */ diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index e6dede287..6bb765787 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -93,6 +93,42 @@ 0x05 "md5" OID_MD5 0x03 "encryptionAlgorithm" 0x07 "3des-ede-cbc" OID_3DES_EDE_CBC + 0xCE "" + 0x3D "ansi-X9-62" + 0x02 "id-publicKeyType" + 0x01 "id-ecPublicKey" OID_EC_PUBLICKEY + 0x03 "ellipticCurve" + 0x00 "c-TwoCurve" + 0x01 "c2pnb163v1" OID_C2PNB163V1 + 0x02 "c2pnb163v2" OID_C2PNB163V2 + 0x03 "c2pnb163v3" OID_C2PNB163V3 + 0x04 "c2pnb176w1" OID_C2PNB176W1 + 0x05 "c2tnb191v1" OID_C2PNB191V1 + 0x06 "c2tnb191v2" OID_C2PNB191V2 + 0x07 "c2tnb191v3" OID_C2PNB191V3 + 0x08 "c2onb191v4" OID_C2PNB191V4 + 0x09 "c2onb191v5" OID_C2PNB191V5 + 0x0A "c2pnb208w1" OID_C2PNB208W1 + 0x0B "c2tnb239v1" OID_C2PNB239V1 + 0x0C "c2tnb239v2" OID_C2PNB239V2 + 0x0D "c2tnb239v3" OID_C2PNB239V3 + 0x0E "c2onb239v4" OID_C2PNB239V4 + 0x0F "c2onb239v5" OID_C2PNB239V5 + 0x10 "c2pnb272w1" OID_C2PNB272W1 + 0x11 "c2pnb304w1" OID_C2PNB304W1 + 0x12 "c2tnb359v1" OID_C2PNB359V1 + 0x13 "c2pnb368w1" OID_C2PNB368W1 + 0x14 "c2tnb431r1" OID_C2PNB431R1 + 0x01 "primeCurve" + 0x01 "prime192v1" OID_PRIME192V1 + 0x02 "prime192v2" OID_PRIME192V2 + 0x03 "prime192v3" OID_PRIME192V3 + 0x04 "prime239v1" OID_PRIME239V1 + 0x05 "prime239v2" OID_PRIME239V2 + 0x06 "prime239v3" OID_PRIME239V3 + 0x07 "prime256v1" OID_PRIME256V1 + 0x04 "id-ecSigType" + 0x01 "ecdsa-with-SHA1" OID_ECDSA_WITH_SHA1 0x2B "" 0x06 "dod" 0x01 "internet" @@ -159,6 +195,40 @@ 0x02 "rsaSigWithripemd160" 0x03 "rsaSigWithripemd128" 0x04 "rsaSigWithripemd256" + 0x81 "" + 0x04 "Certicom" + 0x00 "curve" + 0x01 "sect163k1" OID_SECT163K1 + 0x02 "sect163r1" OID_SECT163R1 + 0x03 "sect239k1" OID_SECT239K1 + 0x04 "sect113r1" OID_SECT113R1 + 0x05 "sect113r2" OID_SECT113R2 + 0x06 "secp112r1" OID_SECT112R1 + 0x07 "secp112r2" OID_SECT112R2 + 0x08 "secp160r1" OID_SECT160R1 + 0x09 "secp160k1" OID_SECT160K1 + 0x0A "secp256k1" OID_SECT256K1 + 0x0F "sect163r2" OID_SECT163R2 + 0x10 "sect283k1" OID_SECT283K1 + 0x11 "sect283r1" OID_SECT283R1 + 0x16 "sect131r1" OID_SECT131R1 + 0x17 "sect131r2" OID_SECT131R2 + 0x18 "sect193r1" OID_SECT193R1 + 0x19 "sect193r2" OID_SECT193R2 + 0x1A "sect233k1" OID_SECT233K1 + 0x1B "sect233r1" OID_SECT233R1 + 0x1C "secp128r1" OID_SECT128R1 + 0x1D "secp128r2" OID_SECT128R2 + 0x1E "secp160r2" OID_SECT160R2 + 0x1F "secp192k1" OID_SECT192K1 + 0x20 "secp224k1" OID_SECT224K1 + 0x21 "secp224r1" OID_SECT224R1 + 0x22 "secp384r1" OID_SECT384R1 + 0x23 "secp521r1" OID_SECT521R1 + 0x24 "sect409k1" OID_SECT409K1 + 0x25 "sect409r1" OID_SECT409R1 + 0x26 "sect571k1" OID_SECT571K1 + 0x27 "sect571r1" OID_SECT571R1 0x60 "" 0x86 "" 0x48 "" diff --git a/src/libstrongswan/asn1/pem.c b/src/libstrongswan/asn1/pem.c index b752a97ab..d3176b6bc 100755 --- a/src/libstrongswan/asn1/pem.c +++ b/src/libstrongswan/asn1/pem.c @@ -1,5 +1,7 @@ /* - * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * Copyright (C) 2001-2008 Andreas Steffen + * + * 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 @@ -11,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: pem.c 3256 2007-10-07 13:42:43Z andreas $ + * $Id: pem.c 4029 2008-06-03 12:14:02Z martin $ */ #include <stdio.h> @@ -27,7 +29,6 @@ #include <library.h> #include <debug.h> #include <asn1/asn1.h> -#include <asn1/ttodata.h> #include <utils/lexparser.h> #include <crypto/hashers/hasher.h> @@ -83,7 +84,7 @@ static bool find_boundary(const char* tag, chunk_t *line) /* * decrypts a passphrase protected encrypted data block */ -static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_size, +static bool pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_size, chunk_t *iv, chunk_t *passphrase) { hasher_t *hasher; @@ -95,10 +96,18 @@ static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_s u_int8_t padding, *last_padding_pos, *first_padding_pos; if (passphrase == NULL || passphrase->len == 0) - return "missing passphrase"; + { + DBG1(" missing passphrase"); + return FALSE; + } /* build key from passphrase and IV */ - hasher = hasher_create(HASH_MD5); + hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); + if (hasher == NULL) + { + DBG1(" MD5 hash algorithm not available"); + return FALSE; + } hash.len = hasher->get_hash_size(hasher); hash.ptr = alloca(hash.len); hasher->get_hash(hasher, *passphrase, NULL); @@ -115,13 +124,23 @@ static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_s hasher->destroy(hasher); /* decrypt blob */ - crypter = crypter_create(alg, key_size); + crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); + if (crypter == NULL) + { + DBG1(" %N encryption algorithm not available", + encryption_algorithm_names, alg); + return FALSE; + } crypter->set_key(crypter, key); - if (crypter->decrypt(crypter, *blob, *iv, &decrypted) != SUCCESS) + + if (iv->len != crypter->get_block_size(crypter) || + blob->len % iv->len) { crypter->destroy(crypter); - return "data size is not multiple of block size"; + DBG1(" data size is not multiple of block size"); + return FALSE; } + crypter->decrypt(crypter, *blob, *iv, &decrypted); crypter->destroy(crypter); memcpy(blob->ptr, decrypted.ptr, blob->len); chunk_free(&decrypted); @@ -135,11 +154,14 @@ static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_s while (--last_padding_pos > first_padding_pos) { if (*last_padding_pos != padding) - return "invalid passphrase"; + { + DBG1(" invalid passphrase"); + return FALSE; + } } /* remove padding */ blob->len -= padding; - return NULL; + return TRUE; } /* Converts a PEM encoded file into its binary form @@ -147,7 +169,7 @@ static err_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, size_t key_s * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993 * RFC 934 Message Encapsulation, January 1985 */ -err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp) +bool pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp) { typedef enum { PEM_PRE = 0, @@ -223,7 +245,6 @@ err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp) encrypted = TRUE; else if (match("DEK-Info", &name)) { - size_t len = 0; chunk_t dek; if (!extract_token(&dek, ',', &value)) @@ -251,21 +272,16 @@ err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp) } else { - return "encryption algorithm not supported"; + DBG1(" encryption algorithm '%.s' not supported", + dek.len, dek.ptr); + return FALSE; } - eat_whitespace(&value); - ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len); - if (ugh) - return "error in IV"; - - iv.len = len; + iv = chunk_from_hex(value, iv.ptr); } } else /* state is PEM_BODY */ { - const char *ugh = NULL; - size_t len = 0; chunk_t data; /* remove any trailing whitespace */ @@ -280,21 +296,18 @@ err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp) *pgp = TRUE; data.ptr++; data.len--; - DBG2(" Armor checksum: %.*s", (int)data.len, data.ptr); + DBG2(" armor checksum: %.*s", (int)data.len, data.ptr); continue; } - - ugh = ttodata(data.ptr, data.len, 64, dst.ptr, blob->len - dst.len, &len); - if (ugh) + + if (blob->len - dst.len < data.len / 4 * 3) { state = PEM_ABORT; - break; - } - else - { - dst.ptr += len; - dst.len += len; } + data = chunk_from_base64(data, dst.ptr); + + dst.ptr += data.len; + dst.len += data.len; } } } @@ -302,19 +315,24 @@ err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp) blob->len = dst.len; if (state != PEM_POST) - return "file coded in unknown format, discarded"; - - return (encrypted)? pem_decrypt(blob, alg, key_size, &iv, passphrase) : NULL; + { + DBG1(" file coded in unknown format, discarded"); + return FALSE; + } + if (!encrypted) + { + return TRUE; + } + return pem_decrypt(blob, alg, key_size, &iv, passphrase); + } /* load a coded key or certificate file with autodetection * of binary DER or base64 PEM ASN.1 formats and armored PGP format */ -bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, - const char *type, chunk_t *blob, bool *pgp) +bool pem_asn1_load_file(char *filename, chunk_t *passphrase, + chunk_t *blob, bool *pgp) { - err_t ugh = NULL; - FILE *fd = fopen(filename, "r"); if (fd) @@ -326,7 +344,7 @@ bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, blob->ptr = malloc(blob->len); bytes = fread(blob->ptr, 1, blob->len, fd); fclose(fd); - DBG1(" loading %s file '%s' (%d bytes)", type, filename, bytes); + DBG2(" loading '%s' (%d bytes)", filename, bytes); *pgp = FALSE; @@ -341,9 +359,7 @@ bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, DBG4(" passphrase:", passphrase->ptr, passphrase->len); /* try PEM format */ - ugh = pem_to_bin(blob, passphrase, pgp); - - if (ugh == NULL) + if (pem_to_bin(blob, passphrase, pgp)) { if (*pgp) { @@ -355,16 +371,16 @@ bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, DBG2(" file coded in PEM format"); return TRUE; } - ugh = "file coded in unknown format, discarded"; + DBG1(" file coded in unknown format, discarded"); } /* a conversion error has occured */ - DBG1(" %s", ugh); chunk_free(blob); } else { - DBG1(" could not open %s file '%s'", type, filename); + DBG1(" reading file '%s' failed", filename); } return FALSE; } + diff --git a/src/libstrongswan/asn1/pem.h b/src/libstrongswan/asn1/pem.h index 0f4b7202c..4b76fbe80 100755 --- a/src/libstrongswan/asn1/pem.h +++ b/src/libstrongswan/asn1/pem.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * Copyright (C) 2001-2008 Andreas Steffen + * + * 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 @@ -10,6 +12,8 @@ * 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. + * + * $Id: pem.h 4011 2008-05-23 19:18:08Z andreas $ */ #ifndef PEM_H_ @@ -19,9 +23,9 @@ #include <library.h> -err_t pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp); +bool pem_to_bin(chunk_t *blob, chunk_t *passphrase, bool *pgp); -bool pem_asn1_load_file(const char *filename, chunk_t *passphrase, - const char *type, chunk_t *blob, bool *pgp); +bool pem_asn1_load_file(char *filename, chunk_t *passphrase, + chunk_t *blob, bool *pgp); -#endif /*PEM_H_*/ +#endif /*PEM_H_ @} */ diff --git a/src/libstrongswan/asn1/ttodata.c b/src/libstrongswan/asn1/ttodata.c deleted file mode 100644 index 125313c2a..000000000 --- a/src/libstrongswan/asn1/ttodata.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * 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)) - -/** - * @brief 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. - * - * @param src - * @param srclen 0 means apply strlen() - * @param base 0 means figure it out - * @param dst need not be valid if dstlen is 0 - * @param dstlen - * @param lenp where to record length (NULL is nowhere) - * @param errp error buffer - * @param flags - * @return NULL on success, else literal or errp - */ -const char *ttodatav(const char *src, size_t srclen, int base, char *dst, size_t dstlen, size_t *lenp, char *errp, 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 == '_' || *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; -} - -/** - * @brief ttodata - convert text to data - * - * @param src - * @param srclen 0 means apply strlen() - * @param base 0 means figure it out - * @param dst need not be valid if dstlen is 0 - * @param dstlen - * @param lenp where to record length (NULL is nowhere) - * @return NULL on success, else literal - */ -const char *ttodata(const char *src, size_t srclen, int base, char *dst, size_t dstlen, size_t *lenp) -{ - return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL, - (size_t)0, TTODATAV_SPACECOUNTS); -} - -/** - * @brief atodata - convert ASCII to data - * - * backward-compatibility interface - * - * @param src - * @param srclen - * @param dst - * @param dstlen - * @return 0 for failure, true length for success - */ -size_t atodata(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); - return (err)? 0:len; -} - -/** - * @brief atobytes - convert ASCII to data bytes - * - * another backward-compatibility interface - */ -const char *atobytes(const char *src, size_t srclen, char *dst, size_t dstlen, size_t *lenp) -{ - return ttodata(src, srclen, 0, dst, dstlen, lenp); -} - -/** - * @brief unhex - convert two ASCII hex digits to byte - * - * @param src known to be full length - * @param dstnumber of result bytes, or error code - * @param dstlen not large enough is a failure - * @return - */ -static int unhex(const char *src, char *dst, size_t dstlen) -{ - 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; -} - -/** - * @brief 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. - * - * @param src known to be full length - * @param dst - * @param dstlen - * @return number of result bytes, or error code - */ -static int unb64(const char *src, 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; -} - -/** - * @brief untext - convert one ASCII character to byte - * - * @param src known to be full length - * @param dst - * @param dstlen not large enough is a failure - * @return number of result bytes, or error code - */ -static int untext(const char *src, char *dst, size_t dstlen) -{ - if (dstlen < 1) - { - return SHORT; - } - *dst = *src; - return 1; -} - -/** - * @brief 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. - * - * @param src - * @param errcode - * @param errp might be NULL - * @param errlen - * @return literal or errp - */ -static const char *badch(const char *src, int errcode, char *errp, 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/libstrongswan/asn1/ttodata.h b/src/libstrongswan/asn1/ttodata.h deleted file mode 100644 index 6125c6b82..000000000 --- a/src/libstrongswan/asn1/ttodata.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 <library.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 */ - -err_t ttodata(const char *src, size_t srclen, int base, char *buf, size_t buflen, size_t *needed); - - -#endif /* TTODATA_H_ */ |