diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2008-04-26 09:24:14 +0000 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2008-04-26 09:24:14 +0000 |
commit | d3d7e46b8ce797cf790ed170c07ffb417411f376 (patch) | |
tree | 75abf99d253665b1117935609e2ac0600946893a /src | |
parent | 3444390241db7d0c598e026ba598f4263b3620ef (diff) | |
download | strongswan-d3d7e46b8ce797cf790ed170c07ffb417411f376.tar.bz2 strongswan-d3d7e46b8ce797cf790ed170c07ffb417411f376.tar.xz |
refactoring of the ASN.1 parser
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/asn1/asn1.c | 317 | ||||
-rw-r--r-- | src/libstrongswan/asn1/asn1.h | 197 | ||||
-rw-r--r-- | src/libstrongswan/asn1/asn1_parser.c | 306 | ||||
-rw-r--r-- | src/libstrongswan/asn1/asn1_parser.h | 119 | ||||
-rwxr-xr-x | src/libstrongswan/asn1/pem.c | 4 | ||||
-rwxr-xr-x | src/libstrongswan/asn1/pem.h | 6 | ||||
-rw-r--r-- | src/libstrongswan/crypto/pkcs9.c | 42 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_public_key.c | 77 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c | 44 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c | 79 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/ietf_attr_list.c | 26 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ac.c | 284 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_cert.c | 725 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_crl.c | 57 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_ocsp_response.c | 415 | ||||
-rw-r--r-- | src/libstrongswan/utils/identification.c | 12 | ||||
-rw-r--r-- | src/libstrongswan/utils/lexparser.h | 4 | ||||
-rwxr-xr-x | src/openac/openac.c | 4 |
19 files changed, 1570 insertions, 1149 deletions
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index fbd220854..9852bdf35 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -16,6 +16,7 @@ enum.c enum.h \ settings.h settings.c \ printf_hook.c printf_hook.h \ asn1/asn1.c asn1/asn1.h \ +asn1/asn1_parser.c asn1/asn1_parser.h \ asn1/oid.c asn1/oid.h \ asn1/pem.c asn1/pem.h \ crypto/crypters/crypter.c crypto/crypters/crypter.h \ diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c index cd204c698..780a589ef 100644 --- a/src/libstrongswan/asn1/asn1.c +++ b/src/libstrongswan/asn1/asn1.c @@ -1,6 +1,7 @@ /* * 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 @@ -20,12 +21,16 @@ #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 }; @@ -34,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, @@ -141,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) { @@ -190,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; @@ -222,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) { @@ -270,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; @@ -364,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; @@ -389,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); @@ -430,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); } @@ -449,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; @@ -617,32 +443,42 @@ 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 */ +}; +#define ALGORITHM_ID_ALG 1 +#define ALGORITHM_ID_PARAMETERS 2 +#define ALGORITHM_ID_ROOF 3 + +/* + * 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; - asn1_init(&ctx, blob, level0, FALSE, FALSE); + parser = asn1_parser_create(algorithmIdentifierObjects, ALGORITHM_ID_ROOF, + 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) @@ -651,8 +487,8 @@ int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters) default: break; } - objectID++; } + parser->destroy(parser); return alg; } @@ -688,10 +524,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) { @@ -724,14 +577,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; @@ -751,13 +604,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; @@ -770,7 +623,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); @@ -804,7 +657,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); @@ -841,26 +694,24 @@ static const asn1Object_t timeObjects[] = { /** * 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, TIME_ROOF, 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 3a476c99b..5c0222347 100644 --- a/src/libstrongswan/asn1/asn1.h +++ b/src/libstrongswan/asn1/asn1.h @@ -28,8 +28,6 @@ #include <stdarg.h> #include <library.h> -#include <asn1/oid.h> - /** * Definition of some primitive ASN1 types @@ -60,7 +58,6 @@ typedef enum { ASN1_CONSTRUCTED = 0x20, ASN1_SEQUENCE = 0x30, - ASN1_SET = 0x31, ASN1_CONTEXT_S_0 = 0x80, @@ -81,61 +78,155 @@ typedef enum { 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; - bool private; - 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 */ +/** + * 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; -/* 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_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, ...); + +/** Some ASN.1 analysis functions */ + +/** + * Returns some popular algorithmIdentifiers + * + * @param oid known OID index + * @return body of the corresponding OID + */ +chunk_t asn1_algorithmIdentifier(int oid); + +/** + * 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); + +/** + * 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); + +/** + * 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, ...); #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..5a32d6e64 --- /dev/null +++ b/src/libstrongswan/asn1/asn1_parser.c @@ -0,0 +1,306 @@ +/* + * 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.c 3589 2008-03-13 14:14:44Z martin $ + */ + +#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; + + /** + * Total number of syntax definition lines + */ + int roof; + + /** + * 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; + + /* Terminate if the end of the object syntax definition has been reached */ + if (++(this->line) >= this->roof) + { + return FALSE; + } + obj = this->objects[this->line]; + + 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, int roof, 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->roof = roof; + 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..4b8d58dba --- /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.h 3776 2008-04-07 10:37:14Z martin $ + */ + +/** + * @defgroup asn1_parser asn1_parser + * @{ @ingroup asn1 + */ + +#ifndef ASN1_PARSER_H_ +#define ASN1_PARSER_H_ + +#include <stdarg.h> + +#include <library.h> + +/** + * 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 + +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 roof number of syntax definition lines + * @param blob ASN.1 coded binary blob + * @return ASN.1 context + */ +asn1_parser_t* asn1_parser_create(asn1Object_t const *objects, int roof, chunk_t blob); + +#endif /* ASN1_PARSER_H_ @}*/ diff --git a/src/libstrongswan/asn1/pem.c b/src/libstrongswan/asn1/pem.c index 5cba781cb..63b30728c 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 diff --git a/src/libstrongswan/asn1/pem.h b/src/libstrongswan/asn1/pem.h index 956623c0d..8549ff7cf 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$ */ #ifndef PEM_H_ diff --git a/src/libstrongswan/crypto/pkcs9.c b/src/libstrongswan/crypto/pkcs9.c index ba2724005..42101b003 100644 --- a/src/libstrongswan/crypto/pkcs9.c +++ b/src/libstrongswan/crypto/pkcs9.c @@ -20,6 +20,7 @@ #include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <utils/linked_list.h> #include "pkcs9.h" @@ -87,7 +88,6 @@ static const asn1Object_t attributesObjects[] = { { 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */ }; - #define ATTRIBUTE_OBJ_TYPE 2 #define ATTRIBUTE_OBJ_VALUE 4 #define ATTRIBUTE_OBJ_ROOF 7 @@ -259,7 +259,7 @@ static void build_encoding(private_pkcs9_t *this) /* allocate memory for the attributes and build the encoding */ { - u_char *pos = build_asn1_object(&this->encoding, ASN1_SET, attributes_len); + u_char *pos = asn1_build_object(&this->encoding, ASN1_SET, attributes_len); iterator = this->attributes->create_iterator(this->attributes, TRUE); @@ -327,7 +327,8 @@ static chunk_t get_messageDigest(private_pkcs9_t *this) { return chunk_empty; } - if (!parse_asn1_simple_object(&value, asn1_attributeType(oid), 0, oid_names[oid].name)) + if (!asn1_parse_simple_object(&value, asn1_attributeType(oid), 0, + oid_names[oid].name)) { return chunk_empty; } @@ -394,25 +395,21 @@ pkcs9_t *pkcs9_create(void) */ static bool parse_attributes(chunk_t chunk, int level0, private_pkcs9_t* this) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; + int objectID; int oid = OID_UNKNOWN; - int objectID = 0; + bool success = TRUE; - asn1_init(&ctx, chunk, level0, FALSE, FALSE); + parser = asn1_parser_create(attributesObjects, ATTRIBUTE_OBJ_ROOF, chunk); + parser->set_top_level(parser, level0); - while (objectID < ATTRIBUTE_OBJ_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(attributesObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } - switch (objectID) { case ATTRIBUTE_OBJ_TYPE: - oid = known_oid(object); + oid = asn1_known_oid(object); break; case ATTRIBUTE_OBJ_VALUE: if (oid == OID_UNKNOWN) @@ -423,7 +420,8 @@ static bool parse_attributes(chunk_t chunk, int level0, private_pkcs9_t* this) { attribute_t *attribute = attribute_create(oid, object); - this->attributes->insert_last(this->attributes, (void*)attribute); + this->attributes->insert_last(this->attributes, + (void*)attribute); } /* parse known attributes */ { @@ -431,16 +429,22 @@ static bool parse_attributes(chunk_t chunk, int level0, private_pkcs9_t* this) if (type != ASN1_EOC) { - if (!parse_asn1_simple_object(&object, type, level+1, oid_names[oid].name)) + if (!asn1_parse_simple_object(&object, type, + parser->get_level(parser)+1, + oid_names[oid].name)) { - return FALSE; + success = FALSE; + goto end; } } } } - objectID++; } - return TRUE; + +end: + success &= parser->success(parser); + parser->destroy(parser); + return success; } diff --git a/src/libstrongswan/plugins/gmp/gmp_public_key.c b/src/libstrongswan/plugins/gmp/gmp_public_key.c index 17b2ca322..9064addb3 100644 --- a/src/libstrongswan/plugins/gmp/gmp_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_public_key.c @@ -18,8 +18,10 @@ #include "gmp_public_key.h" -#include <asn1/asn1.h> #include <debug.h> +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> /** * ASN.1 definition of a subjectPublicKeyInfo structure @@ -27,67 +29,64 @@ static const asn1Object_t pkinfoObjects[] = { { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ { 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 2 */ - { 2, "publicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 3 */ + { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_OBJ }, /* 2 */ }; -#define PKINFO 0 #define PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM 1 #define PKINFO_SUBJECT_PUBLIC_KEY 2 -#define PKINFO_PUBLIC_KEY 3 -#define PKINFO_ROOF 4 +#define PKINFO_ROOF 3 /** * Load a public key from an ASN1 encoded blob */ static public_key_t *load(chunk_t blob) { - asn1_ctx_t ctx; - chunk_t object, data = chunk_empty; - u_int level; - int objectID = 0; + asn1_parser_t *parser; + chunk_t object; + int objectID; + public_key_t *key = NULL; key_type_t type = KEY_ANY; + + parser = asn1_parser_create(pkinfoObjects, PKINFO_ROOF, blob); - asn1_init(&ctx, blob, 0, FALSE, FALSE); - - while (objectID < PKINFO_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(pkinfoObjects, &objectID, &object, &level, &ctx)) - { - free(blob.ptr); - return NULL; - } switch (objectID) { case PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM: - switch (parse_algorithmIdentifier(object, level, NULL)) + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser)+1, NULL); + + if (oid == OID_RSA_ENCRYPTION) + { + type = KEY_RSA; + } + else { - case OID_RSA_ENCRYPTION: - type = KEY_RSA; - break; - default: - break; + /* key type not supported */ + goto end; } break; + } case PKINFO_SUBJECT_PUBLIC_KEY: - if (ctx.blobs[2].len > 0 && *ctx.blobs[2].ptr == 0x00) - { /* skip initial bit string octet defining 0 unused bits */ - ctx.blobs[2].ptr++; ctx.blobs[2].len--; + if (object.len > 0 && *object.ptr == 0x00) + { + /* skip initial bit string octet defining 0 unused bits */ + object.ptr++; + object.len--; + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type, + BUILD_BLOB_ASN1_DER, + chunk_clone(object), + BUILD_END); } break; - case PKINFO_PUBLIC_KEY: - data = chunk_clone(object); - break; } - objectID++; - } + } + +end: + parser->destroy(parser); free(blob.ptr); - if (type == KEY_ANY) - { - free(data.ptr); - return NULL; - } - return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type, - BUILD_BLOB_ASN1_DER, data, BUILD_END); + return key; } typedef struct private_builder_t private_builder_t; diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c index 8a4ee55ec..e28ec3a17 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -25,7 +25,9 @@ #include "gmp_rsa_public_key.h" #include <debug.h> +#include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> /** * Public exponent to use for key generation. @@ -109,8 +111,10 @@ struct private_gmp_rsa_private_key_t { refcount_t ref; }; -/* ASN.1 definition of a PKCS#1 RSA private key */ -static const asn1Object_t privkey_objects[] = { +/** + * ASN.1 definition of a PKCS#1 RSA private key + */ +static const asn1Object_t privkeyObjects[] = { { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */ @@ -673,10 +677,11 @@ static gmp_rsa_private_key_t *generate(size_t key_size) */ static gmp_rsa_private_key_t *load(chunk_t blob) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID ; + bool success = TRUE; + private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); mpz_init(this->n); @@ -688,24 +693,17 @@ static gmp_rsa_private_key_t *load(chunk_t blob) mpz_init(this->exp2); mpz_init(this->coeff); - asn1_init(&ctx, blob, 0, FALSE, TRUE); + parser = asn1_parser_create(privkeyObjects, PRIV_KEY_ROOF, blob); + parser->set_flags(parser, FALSE, TRUE); - while (objectID < PRIV_KEY_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx)) - { - chunk_clear(&blob); - destroy(this); - return NULL; - } switch (objectID) { case PRIV_KEY_VERSION: if (object.len > 0 && *object.ptr != 0) { - chunk_clear(&blob); - destroy(this); - return NULL; + goto end; } break; case PRIV_KEY_MODULUS: @@ -733,18 +731,28 @@ static gmp_rsa_private_key_t *load(chunk_t blob) mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr); break; } - objectID++; } + +end: + success &= parser->success(parser); + parser->destroy(parser); chunk_clear(&blob); + + if (!success) + { + destroy(this); + return NULL; + } this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; + if (!gmp_rsa_public_key_build_id(this->n, this->e, &this->keyid, &this->keyid_info)) { destroy(this); return NULL; } - + if (check(this) != SUCCESS) { destroy(this); diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c index 388dcb03b..ac48865b7 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -25,35 +25,38 @@ #include "gmp_rsa_public_key.h" #include <debug.h> -#include <crypto/hashers/hasher.h> +#include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <asn1/pem.h> +#include <crypto/hashers/hasher.h> /** * defined in gmp_rsa_private_key.c */ extern chunk_t gmp_mpz_to_asn1(const mpz_t value); - -/* ASN.1 definition of RSApublicKey */ +/** + * ASN.1 definition of RSApublicKey + */ static const asn1Object_t pubkeyObjects[] = { { 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 -/* ASN.1 definition of digestInfo */ +/** + * ASN.1 definition of digestInfo + */ static const asn1Object_t digestInfoObjects[] = { { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ }; - #define DIGEST_INFO 0 #define DIGEST_INFO_ALGORITHM 1 #define DIGEST_INFO_DIGEST 2 @@ -141,7 +144,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, chunk_t data, chunk_t signature) { chunk_t em_ori, em; - bool res = FALSE; + bool success = FALSE; /* remove any preceding 0-bytes from signature */ while (signature.len && *(signature.ptr) == 0x00) @@ -199,20 +202,15 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, /* parse ASN.1-based digestInfo */ { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; hash_algorithm_t hash_algorithm = HASH_UNKNOWN; - asn1_init(&ctx, em, 0, FALSE, FALSE); + parser = asn1_parser_create(digestInfoObjects, DIGEST_INFO_ROOF, em); - while (objectID < DIGEST_INFO_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx)) - { - goto end; - } switch (objectID) { case DIGEST_INFO: @@ -221,20 +219,21 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, { DBG1("digestInfo field in signature is followed by %u surplus bytes", em.len - object.len); - goto end; + goto end_parser; } break; } case DIGEST_INFO_ALGORITHM: { - int hash_oid = parse_algorithmIdentifier(object, level+1, NULL); + int hash_oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser)+1, NULL); hash_algorithm = hasher_algorithm_from_oid(hash_oid); if (hash_algorithm == HASH_UNKNOWN || (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm)) { DBG1("wrong hash algorithm used in signature"); - goto end; + goto end_parser; } break; } @@ -248,7 +247,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, { DBG1("hash algorithm %N not supported", hash_algorithm_names, hash_algorithm); - goto end; + goto end_parser; } if (object.len != hasher->get_hash_size(hasher)) @@ -256,26 +255,29 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, DBG1("hash size in signature is %u bytes instead of %u " "bytes", object.len, hasher->get_hash_size(hasher)); hasher->destroy(hasher); - goto end; + goto end_parser; } /* build our own hash and compare */ hasher->allocate_hash(hasher, data, &hash); hasher->destroy(hasher); - res = memeq(object.ptr, hash.ptr, hash.len); + success = memeq(object.ptr, hash.ptr, hash.len); free(hash.ptr); break; } default: break; } - objectID++; } + +end_parser: + success &= parser->success(parser); + parser->destroy(parser); } end: free(em_ori.ptr); - return res; + return success; } /** @@ -465,25 +467,20 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e) */ static gmp_rsa_public_key_t *load(chunk_t blob) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; + bool success; + private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty(); mpz_init(this->n); mpz_init(this->e); - asn1_init(&ctx, blob, 0, FALSE, FALSE); + parser = asn1_parser_create(pubkeyObjects, PUB_KEY_ROOF, blob); - while (objectID < PUB_KEY_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx)) - { - free(blob.ptr); - destroy(this); - return NULL; - } switch (objectID) { case PUB_KEY_MODULUS: @@ -493,10 +490,20 @@ static gmp_rsa_public_key_t *load(chunk_t blob) mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); break; } - objectID++; } + free(blob.ptr); + success = parser->success(parser); + parser->destroy(parser); + + if (!success) + { + destroy(this); + return NULL; + } + this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8; + if (!gmp_rsa_public_key_build_id(this->n, this->e, &this->keyid, &this->keyid_info)) { diff --git a/src/libstrongswan/plugins/x509/ietf_attr_list.c b/src/libstrongswan/plugins/x509/ietf_attr_list.c index b5ecb410e..d27cf62df 100644 --- a/src/libstrongswan/plugins/x509/ietf_attr_list.c +++ b/src/libstrongswan/plugins/x509/ietf_attr_list.c @@ -16,7 +16,11 @@ #include <stdio.h> #include <debug.h> +#include <library.h> + +#include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <utils/lexparser.h> #include "ietf_attr_list.h" @@ -220,7 +224,7 @@ void ietfAttr_list_list(linked_list_t *list, FILE *out) break; case IETF_ATTRIBUTE_OID: { - int oid = known_oid(attr->value); + int oid = asn1_known_oid(attr->value); if (oid == OID_UNKNOWN) { @@ -294,7 +298,6 @@ static const asn1Object_t ietfAttrSyntaxObjects[] = { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */ }; - #define IETF_ATTR_OCTETS 4 #define IETF_ATTR_OID 6 #define IETF_ATTR_STRING 8 @@ -305,20 +308,15 @@ static const asn1Object_t ietfAttrSyntaxObjects[] = */ void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int level0) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; - asn1_init(&ctx, chunk, level0, FALSE, FALSE); + parser = asn1_parser_create(ietfAttrSyntaxObjects, IETF_ATTR_ROOF, chunk); + parser->set_top_level(parser, level0); - while (objectID < IETF_ATTR_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx)) - { - return; - } - switch (objectID) { case IETF_ATTR_OCTETS: @@ -333,8 +331,8 @@ void ietfAttr_list_create_from_chunk(chunk_t chunk, linked_list_t *list, int lev default: break; } - objectID++; } + parser->destroy(parser); } /* @@ -357,7 +355,7 @@ chunk_t ietfAttr_list_encode(linked_list_t *list) } iterator->destroy(iterator); - pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size); + pos = asn1_build_object(&ietfAttributes, ASN1_SEQUENCE, size); iterator = list->create_iterator(list, TRUE); while (iterator->iterate(iterator, (void **)&attr)) diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index 93a519412..ee4edb714 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -25,6 +25,7 @@ #include <debug.h> #include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <asn1/pem.h> #include <utils/identification.h> #include <utils/linked_list.h> @@ -177,6 +178,52 @@ static u_char ASN1_noRevAvail_ext_str[] = { static const chunk_t ASN1_noRevAvail_ext = chunk_from_buf(ASN1_noRevAvail_ext_str); /** + * declaration of function implemented in x509_cert.c + */ +extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, + linked_list_t *list); +/** + * parses a directoryName + */ +static bool parse_directoryName(chunk_t blob, int level, bool implicit, identification_t **name) +{ + bool has_directoryName; + linked_list_t *list = linked_list_create(); + + x509_parse_generalNames(blob, level, implicit, list); + has_directoryName = list->get_count(list) > 0; + + if (has_directoryName) + { + iterator_t *iterator = list->create_iterator(list, TRUE); + identification_t *directoryName; + bool first = TRUE; + + while (iterator->iterate(iterator, (void**)&directoryName)) + { + if (first) + { + *name = directoryName; + first = FALSE; + } + else + { + DBG1("more than one directory name - first selected"); + directoryName->destroy(directoryName); + } + } + iterator->destroy(iterator); + } + else + { + DBG1("no directoryName found"); + } + + list->destroy(list); + return has_directoryName; +} + +/** * ASN.1 definition of roleSyntax */ static const asn1Object_t roleSyntaxObjects[] = @@ -187,10 +234,32 @@ static const asn1Object_t roleSyntaxObjects[] = { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */ }; - #define ROLE_ROOF 4 /** + * Parses roleSyntax + */ +static void parse_roleSyntax(chunk_t blob, int level0) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + + parser = asn1_parser_create(roleSyntaxObjects, ROLE_ROOF, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + default: + break; + } + } + parser->destroy(parser); +} + +/** * ASN.1 definition of an X509 attribute certificate */ static const asn1Object_t acObjects[] = @@ -259,7 +328,6 @@ static const asn1Object_t acObjects[] = { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */ }; - #define AC_OBJ_CERTIFICATE_INFO 1 #define AC_OBJ_VERSION 2 #define AC_OBJ_HOLDER_ISSUER 5 @@ -281,102 +349,24 @@ static const asn1Object_t acObjects[] = #define AC_OBJ_ROOF 55 /** - * declaration of function implemented in x509_cert.c - */ -extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, - linked_list_t *list); -/** - * parses a directoryName - */ -static bool parse_directoryName(chunk_t blob, int level, bool implicit, identification_t **name) -{ - bool has_directoryName; - linked_list_t *list = linked_list_create(); - - x509_parse_generalNames(blob, level, implicit, list); - has_directoryName = list->get_count(list) > 0; - - if (has_directoryName) - { - iterator_t *iterator = list->create_iterator(list, TRUE); - identification_t *directoryName; - bool first = TRUE; - - while (iterator->iterate(iterator, (void**)&directoryName)) - { - if (first) - { - *name = directoryName; - first = FALSE; - } - else - { - DBG1("more than one directory name - first selected"); - directoryName->destroy(directoryName); - } - } - iterator->destroy(iterator); - } - else - { - DBG1("no directoryName found"); - } - - list->destroy(list); - return has_directoryName; -} - -/** - * parses roleSyntax - */ -static void parse_roleSyntax(chunk_t blob, int level0) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < ROLE_ROOF) - { - if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx)) - { - return; - } - - switch (objectID) - { - default: - break; - } - objectID++; - } -} - -/** * Parses an X.509 attribute certificate */ static bool parse_certificate(private_x509_ac_t *this) { - asn1_ctx_t ctx; - bool critical; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; - int type = OID_UNKNOWN; + int objectID; + int type = OID_UNKNOWN; int extn_oid = OID_UNKNOWN; - int sig_alg = OID_UNKNOWN; + int sig_alg = OID_UNKNOWN; + bool success = TRUE; + bool critical; - asn1_init(&ctx, this->encoding, 0, FALSE, FALSE); - while (objectID < AC_OBJ_ROOF) - { - if (!extract_object(acObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } + parser = asn1_parser_create(acObjects, AC_OBJ_ROOF, this->encoding); - /* those objects which will parsed further need the next higher level */ - level++; + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; switch (objectID) { @@ -389,13 +379,15 @@ static bool parse_certificate(private_x509_ac_t *this) if (this->version != 2) { DBG1("v%d attribute certificates are not supported", this->version); - return FALSE; + success = FALSE; + goto end; } break; case AC_OBJ_HOLDER_ISSUER: if (!parse_directoryName(object, level, FALSE, &this->holderIssuer)) { - return FALSE; + success = FALSE; + goto end; } break; case AC_OBJ_HOLDER_SERIAL: @@ -404,90 +396,93 @@ static bool parse_certificate(private_x509_ac_t *this) case AC_OBJ_ENTITY_NAME: if (!parse_directoryName(object, level, TRUE, &this->entityName)) { - return FALSE; + success = FALSE; + goto end; } break; case AC_OBJ_ISSUER_NAME: if (!parse_directoryName(object, level, FALSE, &this->issuerName)) { - return FALSE; + success = FALSE; + goto end; } break; case AC_OBJ_SIG_ALG: - sig_alg = parse_algorithmIdentifier(object, level, NULL); + sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case AC_OBJ_SERIAL_NUMBER: this->serialNumber = object; break; case AC_OBJ_NOT_BEFORE: - this->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME); + this->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME); break; case AC_OBJ_NOT_AFTER: - this->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME); + this->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME); break; case AC_OBJ_ATTRIBUTE_TYPE: - type = known_oid(object); + type = asn1_known_oid(object); break; case AC_OBJ_ATTRIBUTE_VALUE: + { + switch (type) { - switch (type) - { - case OID_AUTHENTICATION_INFO: - DBG2(" need to parse authenticationInfo"); - break; - case OID_ACCESS_IDENTITY: - DBG2(" need to parse accessIdentity"); - break; - case OID_CHARGING_IDENTITY: - ietfAttr_list_create_from_chunk(object, this->charging, level); - break; - case OID_GROUP: - ietfAttr_list_create_from_chunk(object, this->groups, level); - break; - case OID_ROLE: - parse_roleSyntax(object, level); - break; - default: - break; - } + case OID_AUTHENTICATION_INFO: + DBG2(" need to parse authenticationInfo"); + break; + case OID_ACCESS_IDENTITY: + DBG2(" need to parse accessIdentity"); + break; + case OID_CHARGING_IDENTITY: + ietfAttr_list_create_from_chunk(object, this->charging, level); + break; + case OID_GROUP: + ietfAttr_list_create_from_chunk(object, this->groups, level); + break; + case OID_ROLE: + parse_roleSyntax(object, level); + break; + default: + break; } break; + } case AC_OBJ_EXTN_ID: - extn_oid = known_oid(object); + extn_oid = asn1_known_oid(object); break; case AC_OBJ_CRITICAL: critical = object.len && *object.ptr; DBG2(" %s",(critical)?"TRUE":"FALSE"); break; case AC_OBJ_EXTN_VALUE: + { + switch (extn_oid) { - switch (extn_oid) - { - case OID_CRL_DISTRIBUTION_POINTS: - DBG2(" need to parse crlDistributionPoints"); - break; - case OID_AUTHORITY_KEY_ID: - this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, - level, &this->authKeySerialNumber); + case OID_CRL_DISTRIBUTION_POINTS: + DBG2(" need to parse crlDistributionPoints"); + break; + case OID_AUTHORITY_KEY_ID: + this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object, + level, &this->authKeySerialNumber); + break; + case OID_TARGET_INFORMATION: + DBG2(" need to parse targetInformation"); + break; + case OID_NO_REV_AVAIL: + this->noRevAvail = TRUE; + break; + default: break; - break; - case OID_TARGET_INFORMATION: - DBG2(" need to parse targetInformation"); - break; - case OID_NO_REV_AVAIL: - this->noRevAvail = TRUE; - break; - default: - break; - } } break; + } case AC_OBJ_ALGORITHM: - this->algorithm = parse_algorithmIdentifier(object, level, NULL); + this->algorithm = asn1_parse_algorithmIdentifier(object, level, + NULL); if (this->algorithm != sig_alg) { DBG1(" signature algorithms do not agree"); - return FALSE; + success = FALSE; + goto end; } break; case AC_OBJ_SIGNATURE: @@ -496,9 +491,12 @@ static bool parse_certificate(private_x509_ac_t *this) default: break; } - objectID++; } - return TRUE; + +end: + success &= parser->success(parser); + parser->destroy(parser); + return success; } /** @@ -544,8 +542,8 @@ static chunk_t build_v2_form(private_x509_ac_t *this) static chunk_t build_attr_cert_validity(private_x509_ac_t *this) { return asn1_wrap(ASN1_SEQUENCE, "mm", - timetoasn1(&this->notBefore, ASN1_GENERALIZEDTIME), - timetoasn1(&this->notAfter, ASN1_GENERALIZEDTIME)); + asn1_from_time(&this->notBefore, ASN1_GENERALIZEDTIME), + asn1_from_time(&this->notAfter, ASN1_GENERALIZEDTIME)); } diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 0b3ea68f5..b8046bc35 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -29,12 +29,13 @@ #include <string.h> #include <stdio.h> -#include <crypto/hashers/hasher.h> #include <library.h> #include <debug.h> #include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <asn1/pem.h> +#include <crypto/hashers/hasher.h> #include <utils/linked_list.h> #include <utils/identification.h> @@ -166,52 +167,10 @@ struct private_x509_cert_t { refcount_t ref; }; -/** - * 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 */ +static u_char ASN1_sAN_oid_buf[] = { + 0x06, 0x03, 0x55, 0x1D, 0x11 }; - -#define ON_OBJ_ID_TYPE 0 -#define ON_OBJ_VALUE 1 -#define ON_OBJ_ROOF 2 +static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_sAN_oid_buf); /** * ASN.1 definition of a basicConstraints extension @@ -222,244 +181,142 @@ static const asn1Object_t basicConstraintsObjects[] = { { 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 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_cert - */ -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_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_sAN_oid_buf[] = { - 0x06, 0x03, 0x55, 0x1D, 0x11 -}; -static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_sAN_oid_buf); - -/** - * extracts the basicConstraints extension + * Extracts the basicConstraints extension */ static bool parse_basicConstraints(chunk_t blob, int level0) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; bool isCA = FALSE; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < BASIC_CONSTRAINTS_ROOF) { + parser = asn1_parser_create(basicConstraintsObjects, BASIC_CONSTRAINTS_ROOF, + blob); + parser->set_top_level(parser, level0); - if (!extract_object(basicConstraintsObjects, &objectID, &object,&level, &ctx)) - { - break; - } + while (parser->iterate(parser, &objectID, &object)) + { if (objectID == BASIC_CONSTRAINTS_CA) { isCA = object.len && *object.ptr; DBG2(" %s", isCA ? "TRUE" : "FALSE"); } - objectID++; } + parser->destroy(parser); + return isCA; } -/* - * extracts an otherName +/** + * 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 + +/** + * Extracts an otherName */ static bool parse_otherName(chunk_t blob, int level0) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; int oid = OID_UNKNOWN; + bool success = TRUE; + + parser = asn1_parser_create(otherNameObjects,ON_OBJ_ROOF, blob); + parser->set_top_level(parser, level0); - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < ON_OBJ_ROOF) + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } switch (objectID) { case ON_OBJ_ID_TYPE: - oid = known_oid(object); + oid = asn1_known_oid(object); break; case ON_OBJ_VALUE: if (oid == OID_XMPP_ADDR) { - if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING, - level + 1, "xmppAddr")) + if (!asn1_parse_simple_object(&object, ASN1_UTF8STRING, + parser->get_level(parser)+1, "xmppAddr")) { - return FALSE; + success = FALSE; + goto end; } } break; default: break; } - objectID++; } - return TRUE; + +end: + success &= parser->success(parser); + parser->destroy(parser); + return success; } -/* - * extracts a generalName +/** + * 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 + +/** + * Extracts a generalName */ static identification_t *parse_generalName(chunk_t blob, int level0) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - int objectID = 0; - u_int level; + int objectID ; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < GN_OBJ_ROOF) + identification_t *gn = NULL; + + parser = asn1_parser_create(generalNameObjects, GN_OBJ_ROOF, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { id_type_t id_type = ID_ANY; - if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx)) - { - return NULL; - } switch (objectID) { case GN_OBJ_RFC822_NAME: @@ -478,107 +335,146 @@ static identification_t *parse_generalName(chunk_t blob, int level0) id_type = ID_IPV4_ADDR; break; case GN_OBJ_OTHER_NAME: - if (!parse_otherName(object, level + 1)) - return NULL; + if (!parse_otherName(object, parser->get_level(parser)+1)) + { + goto end; + } break; case GN_OBJ_X400_ADDRESS: case GN_OBJ_EDI_PARTY_NAME: case GN_OBJ_REGISTERED_ID: - break; default: break; } if (id_type != ID_ANY) { - identification_t *gn = identification_create_from_encoding(id_type, object); + gn = identification_create_from_encoding(id_type, object); DBG2(" '%D'", gn); - return gn; + goto end; } - objectID++; - } - return NULL; + } + +end: + parser->destroy(parser); + return gn; } +/** + * 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 /** - * extracts one or several GNs and puts them into a chained list + * Extracts one or several GNs and puts them into a chained list */ void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; - asn1_init(&ctx, blob, level0, implicit, FALSE); - while (objectID < GENERAL_NAMES_ROOF) + parser = asn1_parser_create(generalNamesObjects, GENERAL_NAMES_ROOF, blob); + parser->set_top_level(parser, level0); + parser->set_flags(parser, implicit, FALSE); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx)) - { - return; - } if (objectID == GENERAL_NAMES_GN) { - identification_t *gn = parse_generalName(object, level+1); + identification_t *gn = parse_generalName(object, + parser->get_level(parser)+1); - if (gn != NULL) + if (gn) { list->insert_last(list, (void *)gn); } } - objectID++; } - return; + parser->destroy(parser); } +/** + * ASN.1 definition of a keyIdentifier + */ +static const asn1Object_t keyIdentifierObjects[] = { + { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */ +}; +#define KEY_ID_ROOF 1 + /** - * extracts a keyIdentifier + * Extracts a keyIdentifier */ static chunk_t parse_keyIdentifier(chunk_t blob, int level0, bool implicit) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; + + chunk_t keyIdentifier = chunk_empty; - asn1_init(&ctx, blob, level0, implicit, FALSE); - if (!extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx)) + parser = asn1_parser_create(keyIdentifierObjects, KEY_ID_ROOF, blob); + parser->set_top_level(parser, level0); + parser->set_flags(parser, implicit, FALSE); + + if (parser->iterate(parser, &objectID, &object)) { - return chunk_empty; + keyIdentifier = object; } - return object; + parser->destroy(parser); + return keyIdentifier; } /** - * extracts an authoritykeyIdentifier + * ASN.1 definition of a authorityKeyIdentifier extension + */ +static const asn1Object_t authKeyIdentifierObjects[] = { + { 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 + +/** + * Extracts an authoritykeyIdentifier */ identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, chunk_t *authKeySerialNumber) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; identification_t *authKeyIdentifier = NULL; *authKeySerialNumber = chunk_empty; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < AUTH_KEY_ID_ROOF) + parser = asn1_parser_create(authKeyIdentifierObjects, AUTH_KEY_ID_ROOF,blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx)) - { - return NULL; - } switch (objectID) { case AUTH_KEY_ID_KEY_ID: { - chunk_t authKeyID = parse_keyIdentifier(object, level+1, TRUE); + chunk_t authKeyID = parse_keyIdentifier(object, + parser->get_level(parser)+1, TRUE); if (authKeyID.ptr == NULL) { - return NULL; + goto end; } authKeyIdentifier = identification_create_from_encoding( ID_PUBKEY_SHA1, authKeyID); @@ -595,34 +491,48 @@ identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0, default: break; } - objectID++; } + +end: + parser->destroy(parser); return authKeyIdentifier; } /** - * extracts an authorityInfoAcess location + * ASN.1 definition of a authorityInfoAccess extension + */ +static const asn1Object_t authInfoAccessObjects[] = { + { 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 + +/** + * Extracts an authorityInfoAcess location */ static void parse_authorityInfoAccess(chunk_t blob, int level0, private_x509_cert_t *this) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; int accessMethod = OID_UNKNOWN; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < AUTH_INFO_ACCESS_ROOF) + parser = asn1_parser_create(authInfoAccessObjects, AUTH_INFO_ACCESS_ROOF, + blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx)) - { - return; - } switch (objectID) { case AUTH_INFO_ACCESS_METHOD: - accessMethod = known_oid(object); + accessMethod = asn1_known_oid(object); break; case AUTH_INFO_ACCESS_LOCATION: { @@ -634,10 +544,12 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, identification_t *id; char *uri; - id = parse_generalName(object, level+1); + id = parse_generalName(object, + parser->get_level(parser)+1); if (id == NULL) - { /* parsing went wrong - abort */ - return; + { + /* parsing went wrong - abort */ + goto end; } DBG2(" '%D'", id); if (accessMethod == OID_OCSP && @@ -657,66 +569,100 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, default: break; } - objectID++; } + +end: + parser->destroy(parser); } /** - * extracts extendedKeyUsage OIDs + * 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 + +/** + * Extracts extendedKeyUsage OIDs - currently only OCSP_SIGING is returned */ static bool parse_extendedKeyUsage(chunk_t blob, int level0) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; + bool ocsp_signing = FALSE; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < EXT_KEY_USAGE_ROOF) + parser = asn1_parser_create(extendedKeyUsageObjects, EXT_KEY_USAGE_ROOF, + blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(extendedKeyUsageObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } if (objectID == EXT_KEY_USAGE_PURPOSE_ID && - known_oid(object) == OID_OCSP_SIGNING) + asn1_known_oid(object) == OID_OCSP_SIGNING) { - return TRUE; + ocsp_signing = TRUE; } - objectID++; } - return FALSE; + parser->destroy(parser); + return ocsp_signing; } /** - * extracts one or several crlDistributionPoints into a list + * 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 + + +/** + * Extracts one or several crlDistributionPoints into a list */ static void parse_crlDistributionPoints(chunk_t blob, int level0, private_x509_cert_t *this) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; - linked_list_t *list; - identification_t *id; - char *uri; + int objectID; + linked_list_t *list = linked_list_create(); - list = linked_list_create(); - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < CRL_DIST_POINTS_ROOF) + parser = asn1_parser_create(crlDistributionPointsObjects, + CRL_DIST_POINTS_ROOF, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(crlDistributionPointsObjects, &objectID, &object, &level, &ctx)) - { - list->destroy_offset(list, offsetof(identification_t, destroy)); - return; - } if (objectID == CRL_DIST_POINTS_FULLNAME) - { /* append extracted generalNames to existing chained list */ - x509_parse_generalNames(object, level+1, TRUE, list); + { + identification_t *id; + + /* append extracted generalNames to existing chained list */ + x509_parse_generalNames(object, parser->get_level(parser)+1, + TRUE, list); while (list->remove_last(list, (void**)&id) == SUCCESS) { + char *uri; + if (asprintf(&uri, "%D", id) > 0) { this->crl_uris->insert_last(this->crl_uris, uri); @@ -724,35 +670,81 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0, id->destroy(id); } } - objectID++; } + parser->destroy(parser); list->destroy(list); } /** + * ASN.1 definition of an X.509v3 x509_cert + */ +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_BODY }, /* 13 */ + { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 14 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ + { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 16 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ + { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 18 */ + { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 29 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 20 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 21 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 22 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 23 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 24 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 25 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 26 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 27 */ +}; +#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_EXTN_ID 21 +#define X509_OBJ_CRITICAL 22 +#define X509_OBJ_EXTN_VALUE 23 +#define X509_OBJ_ALGORITHM 26 +#define X509_OBJ_SIGNATURE 27 +#define X509_OBJ_ROOF 28 + +/** * Parses an X.509v3 certificate */ static bool parse_certificate(private_x509_cert_t *this) { - asn1_ctx_t ctx; - bool critical; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; int extn_oid = OID_UNKNOWN; - int key_alg = OID_UNKNOWN; - int sig_alg = OID_UNKNOWN; - chunk_t subjectPublicKey = chunk_empty; + int key_alg = OID_UNKNOWN; + int sig_alg = OID_UNKNOWN; + bool success = TRUE; + bool critical; - asn1_init(&ctx, this->encoding, 0, FALSE, FALSE); - while (objectID < X509_OBJ_ROOF) + parser = asn1_parser_create(certObjects, X509_OBJ_ROOF, this->encoding); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(certObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } - /* those objects which will parsed further need the next higher level */ - level++; + u_int level = parser->get_level(parser)+1; + switch (objectID) { case X509_OBJ_TBS_CERTIFICATE: @@ -766,49 +758,50 @@ static bool parse_certificate(private_x509_cert_t *this) this->serialNumber = object; break; case X509_OBJ_SIG_ALG: - sig_alg = parse_algorithmIdentifier(object, level, NULL); + sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case X509_OBJ_ISSUER: this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); DBG2(" '%D'", this->issuer); break; case X509_OBJ_NOT_BEFORE: - this->notBefore = parse_time(object, level); + this->notBefore = asn1_parse_time(object, level); break; case X509_OBJ_NOT_AFTER: - this->notAfter = parse_time(object, level); + this->notAfter = asn1_parse_time(object, level); break; case X509_OBJ_SUBJECT: this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); DBG2(" '%D'", this->subject); break; case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: - key_alg = parse_algorithmIdentifier(object, level, NULL); + key_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case X509_OBJ_SUBJECT_PUBLIC_KEY: - if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00) + if (object.len > 0 && *object.ptr == 0x00) { /* skip initial bit string octet defining 0 unused bits */ - ctx.blobs[4].ptr++; ctx.blobs[4].len--; - } - break; - case X509_OBJ_RSA_PUBLIC_KEY: - subjectPublicKey = object; - switch (key_alg) - { - case OID_RSA_ENCRYPTION: - this->public_key = lib->creds->create(lib->creds, - CRED_PUBLIC_KEY, KEY_RSA, - BUILD_BLOB_ASN1_DER, chunk_clone(subjectPublicKey), - BUILD_END); - break; - default: - DBG1("parsing key type %d failed", key_alg); - return FALSE; + object.ptr++; + object.len--; + + switch (key_alg) + { + case OID_RSA_ENCRYPTION: + this->public_key = lib->creds->create(lib->creds, + CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, + chunk_clone(object), + BUILD_END); + break; + default: + DBG1("parsing key type %d failed", key_alg); + success = FALSE; + goto end; + } } break; case X509_OBJ_EXTN_ID: - extn_oid = known_oid(object); + extn_oid = asn1_known_oid(object); break; case X509_OBJ_CRITICAL: critical = object.len && *object.ptr; @@ -850,7 +843,7 @@ static bool parse_certificate(private_x509_cert_t *this) case OID_NS_CA_REVOCATION_URL: case OID_NS_CA_POLICY_URL: case OID_NS_COMMENT: - if (!parse_asn1_simple_object(&object, ASN1_IA5STRING, + if (!asn1_parse_simple_object(&object, ASN1_IA5STRING, level, oid_names[extn_oid].name)) return FALSE; break; @@ -860,11 +853,12 @@ static bool parse_certificate(private_x509_cert_t *this) break; } case X509_OBJ_ALGORITHM: - this->algorithm = parse_algorithmIdentifier(object, level, NULL); + this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); if (this->algorithm != sig_alg) { DBG1(" signature algorithms do not agree"); - return FALSE; + success = FALSE; + goto end; } break; case X509_OBJ_SIGNATURE: @@ -873,9 +867,12 @@ static bool parse_certificate(private_x509_cert_t *this) default: break; } - objectID++; } - return TRUE; + +end: + success &= parser->success(parser); + parser->destroy(parser); + return success; } /** diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c index a0729fee9..6862caa36 100644 --- a/src/libstrongswan/plugins/x509/x509_crl.c +++ b/src/libstrongswan/plugins/x509/x509_crl.c @@ -22,7 +22,9 @@ typedef struct revoked_t revoked_t; #include <debug.h> #include <library.h> +#include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <asn1/pem.h> #include <credentials/certificates/x509.h> #include <utils/linked_list.h> @@ -168,8 +170,7 @@ static const asn1Object_t crlObjects[] = { { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ - }; - +}; #define CRL_OBJ_TBS_CERT_LIST 1 #define CRL_OBJ_VERSION 2 #define CRL_OBJ_SIG_ALG 4 @@ -193,26 +194,21 @@ static const asn1Object_t crlObjects[] = { */ static bool parse(private_x509_crl_t *this) { - asn1_ctx_t ctx; - bool critical; + asn1_parser_t *parser; + chunk_t object; chunk_t extnID; chunk_t userCertificate = chunk_empty; - revoked_t *revoked = NULL; - chunk_t object; - u_int level; + int objectID; int sig_alg = OID_UNKNOWN; - int objectID = 0; + bool success = TRUE; + bool critical; + revoked_t *revoked = NULL; - asn1_init(&ctx, this->encoding, 0, FALSE, FALSE); - while (objectID < CRL_OBJ_ROOF) - { - if (!extract_object(crlObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } + parser = asn1_parser_create(crlObjects, CRL_OBJ_ROOF, this->encoding); - /* those objects which will parsed further need the next higher level */ - level++; + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; switch (objectID) { @@ -224,17 +220,17 @@ static bool parse(private_x509_crl_t *this) DBG2(" v%d", this->version); break; case CRL_OBJ_SIG_ALG: - sig_alg = parse_algorithmIdentifier(object, level, NULL); + sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL); break; case CRL_OBJ_ISSUER: this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); DBG2(" '%D'", this->issuer); break; case CRL_OBJ_THIS_UPDATE: - this->thisUpdate = parse_time(object, level); + this->thisUpdate = asn1_parse_time(object, level); break; case CRL_OBJ_NEXT_UPDATE: - this->nextUpdate = parse_time(object, level); + this->nextUpdate = asn1_parse_time(object, level); break; case CRL_OBJ_USER_CERTIFICATE: userCertificate = object; @@ -242,7 +238,7 @@ static bool parse(private_x509_crl_t *this) case CRL_OBJ_REVOCATION_DATE: revoked = malloc_thing(revoked_t); revoked->serial = userCertificate; - revoked->date = parse_time(object, level); + revoked->date = asn1_parse_time(object, level); revoked->reason = CRL_UNSPECIFIED; this->revoked->insert_last(this->revoked, (void *)revoked); break; @@ -258,7 +254,7 @@ static bool parse(private_x509_crl_t *this) case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: case CRL_OBJ_EXTN_VALUE: { - int extn_oid = known_oid(extnID); + int extn_oid = asn1_known_oid(extnID); if (revoked && extn_oid == OID_CRL_REASON_CODE) { @@ -277,10 +273,11 @@ static bool parse(private_x509_crl_t *this) } else if (extn_oid == OID_CRL_NUMBER) { - if (!parse_asn1_simple_object(&object, ASN1_INTEGER, + if (!asn1_parse_simple_object(&object, ASN1_INTEGER, level, "crlNumber")) { - return FALSE; + success = FALSE; + goto end; } this->crlNumber = object; } @@ -288,11 +285,12 @@ static bool parse(private_x509_crl_t *this) break; case CRL_OBJ_ALGORITHM: { - this->algorithm = parse_algorithmIdentifier(object, level, NULL); + this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); if (this->algorithm != sig_alg) { DBG1(" signature algorithms do not agree"); - return FALSE; + success = FALSE; + goto end; } break; } @@ -302,9 +300,12 @@ static bool parse(private_x509_crl_t *this) default: break; } - objectID++; } - return TRUE; + +end: + success &= parser->success(parser); + parser->destroy(parser); + return success; } /** diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c index 98238c505..cdac6af03 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_response.c +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c @@ -23,6 +23,7 @@ #include <asn1/oid.h> #include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <utils/identification.h> #include <utils/linked_list.h> #include <debug.h> @@ -155,126 +156,6 @@ static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); -/* asn.1 definitions for parsing */ - -static const asn1Object_t ocspResponseObjects[] = { - { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ - { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ - { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ - { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ -}; - -#define OCSP_RESPONSE_STATUS 1 -#define OCSP_RESPONSE_TYPE 4 -#define OCSP_RESPONSE 5 -#define OCSP_RESPONSE_ROOF 7 - -static const asn1Object_t basicResponseObjects[] = { - { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | - ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ - { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ - { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ - { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ - { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 16 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ - { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ - { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ - { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ - { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ - { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */ -}; - -#define BASIC_RESPONSE_TBS_DATA 1 -#define BASIC_RESPONSE_VERSION 3 -#define BASIC_RESPONSE_ID_BY_NAME 5 -#define BASIC_RESPONSE_ID_BY_KEY 8 -#define BASIC_RESPONSE_PRODUCED_AT 10 -#define BASIC_RESPONSE_RESPONSES 11 -#define BASIC_RESPONSE_EXT_ID 15 -#define BASIC_RESPONSE_CRITICAL 16 -#define BASIC_RESPONSE_EXT_VALUE 17 -#define BASIC_RESPONSE_ALGORITHM 20 -#define BASIC_RESPONSE_SIGNATURE 21 -#define BASIC_RESPONSE_CERTIFICATE 24 -#define BASIC_RESPONSE_ROOF 27 - -static const asn1Object_t responsesObjects[] = { - { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ -}; - -#define RESPONSES_SINGLE_RESPONSE 1 -#define RESPONSES_ROOF 3 - -static const asn1Object_t singleResponseObjects[] = { - { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ - { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ - { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ - { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ - { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ - { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ - { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ - { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ - { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ - { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ - { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ - { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 24 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */ -}; - -#define SINGLE_RESPONSE_ALGORITHM 2 -#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 -#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 -#define SINGLE_RESPONSE_SERIAL_NUMBER 5 -#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 -#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 -#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 -#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 -#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 -#define SINGLE_RESPONSE_THIS_UPDATE 16 -#define SINGLE_RESPONSE_NEXT_UPDATE 18 -#define SINGLE_RESPONSE_EXT_ID 23 -#define SINGLE_RESPONSE_CRITICAL 24 -#define SINGLE_RESPONSE_EXT_VALUE 25 -#define SINGLE_RESPONSE_ROOF 28 - /** * Implementaiton of ocsp_response_t.get_status */ @@ -370,15 +251,66 @@ static enumerator_t* create_cert_enumerator(private_x509_ocsp_response_t *this) } /** - * parse a single OCSP response + * ASN.1 definition of singleResponse + */ +static const asn1Object_t singleResponseObjects[] = { + { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ + { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ + { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ + { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ + { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ + { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ + { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ + { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ + { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ + { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ + { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ + { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ + { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ + { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ + { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ + { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ + { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | + ASN1_DEF }, /* 24 */ + { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */ +}; +#define SINGLE_RESPONSE_ALGORITHM 2 +#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 +#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 +#define SINGLE_RESPONSE_SERIAL_NUMBER 5 +#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 +#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 +#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 +#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 +#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 +#define SINGLE_RESPONSE_THIS_UPDATE 16 +#define SINGLE_RESPONSE_NEXT_UPDATE 18 +#define SINGLE_RESPONSE_EXT_ID 23 +#define SINGLE_RESPONSE_CRITICAL 24 +#define SINGLE_RESPONSE_EXT_VALUE 25 +#define SINGLE_RESPONSE_ROOF 28 + +/** + * Parse a single OCSP response */ static bool parse_singleResponse(private_x509_ocsp_response_t *this, chunk_t blob, int level0) { - u_int level; - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - int objectID = 0; + int objectID; + bool success; + single_response_t *response; response = malloc_thing(single_response_t); @@ -393,18 +325,17 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this, /* if nextUpdate is missing, we give it a short lifetime */ response->nextUpdate = this->producedAt + OCSP_DEFAULT_LIFETIME; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < SINGLE_RESPONSE_ROOF) + parser = asn1_parser_create(singleResponseObjects, SINGLE_RESPONSE_ROOF, + blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx)) - { - free(response); - return FALSE; - } switch (objectID) { case SINGLE_RESPONSE_ALGORITHM: - response->hashAlgorithm = parse_algorithmIdentifier(object, level+1, NULL); + response->hashAlgorithm = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser)+1, NULL); break; case SINGLE_RESPONSE_ISSUER_NAME_HASH: response->issuerNameHash = object; @@ -422,7 +353,7 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this, response->status = VALIDATION_REVOKED; break; case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: - response->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME); + response->revocationTime = asn1_to_time(&object, ASN1_GENERALIZEDTIME); break; case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: if (object.len == 1) @@ -434,94 +365,165 @@ static bool parse_singleResponse(private_x509_ocsp_response_t *this, response->status = VALIDATION_FAILED; break; case SINGLE_RESPONSE_THIS_UPDATE: - response->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); + response->thisUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); break; case SINGLE_RESPONSE_NEXT_UPDATE: - response->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); + response->nextUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); if (response->nextUpdate > this->usableUntil) { this->usableUntil = response->nextUpdate; } break; } - objectID++; } - if (this->usableUntil == UNDEFINED_TIME) + success = parser->success(parser); + parser->destroy(parser); + + if (success) { - this->usableUntil = this->producedAt + OCSP_DEFAULT_LIFETIME; + if (this->usableUntil == UNDEFINED_TIME) + { + this->usableUntil = this->producedAt + OCSP_DEFAULT_LIFETIME; + } + this->responses->insert_last(this->responses, response); } - this->responses->insert_last(this->responses, response); - return TRUE; + return success; } /** - * parse all contained responses + * ASN.1 definition of responses + */ +static const asn1Object_t responsesObjects[] = { + { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ +}; +#define RESPONSES_SINGLE_RESPONSE 1 +#define RESPONSES_ROOF 3 + +/** + * Parse all responses */ static bool parse_responses(private_x509_ocsp_response_t *this, chunk_t blob, int level0) { - u_int level; - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - int objectID = 0; + int objectID; + bool success = TRUE; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < RESPONSES_ROOF) + parser = asn1_parser_create(responsesObjects, RESPONSES_ROOF, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } switch (objectID) { case RESPONSES_SINGLE_RESPONSE: - if (!parse_singleResponse(this, object, level+1)) + if (!parse_singleResponse(this, object, + parser->get_level(parser)+1)) { - return FALSE; + success = FALSE; + goto end; } break; default: break; } - objectID++; } - return TRUE; + +end: + success &= parser->success(parser); + parser->destroy(parser); + return success; } /** - * parse a basicOCSPResponse + * ASN.1 definition of basicResponse + */ +static const asn1Object_t basicResponseObjects[] = { + { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | + ASN1_DEF }, /* 2 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ + { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ + { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ + { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ + { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ + { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ + { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | + ASN1_DEF }, /* 16 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ + { 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ + { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ + { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ + { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ + { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */ +}; +#define BASIC_RESPONSE_TBS_DATA 1 +#define BASIC_RESPONSE_VERSION 3 +#define BASIC_RESPONSE_ID_BY_NAME 5 +#define BASIC_RESPONSE_ID_BY_KEY 8 +#define BASIC_RESPONSE_PRODUCED_AT 10 +#define BASIC_RESPONSE_RESPONSES 11 +#define BASIC_RESPONSE_EXT_ID 15 +#define BASIC_RESPONSE_CRITICAL 16 +#define BASIC_RESPONSE_EXT_VALUE 17 +#define BASIC_RESPONSE_ALGORITHM 20 +#define BASIC_RESPONSE_SIGNATURE 21 +#define BASIC_RESPONSE_CERTIFICATE 24 +#define BASIC_RESPONSE_ROOF 27 + +/** + * Parse a basicOCSPResponse */ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, chunk_t blob, int level0) { - u_int level, version; - asn1_ctx_t ctx; - bool critical; - chunk_t object, responses = chunk_empty; - int objectID = 0; + asn1_parser_t *parser; + chunk_t object; + chunk_t responses = chunk_empty; + int objectID; int extn_oid = OID_UNKNOWN; + u_int responses_level = level0; certificate_t *cert; + bool success = TRUE; + bool critical; - asn1_init(&ctx, blob, level0, FALSE, FALSE); - while (objectID < BASIC_RESPONSE_ROOF) + parser = asn1_parser_create(basicResponseObjects, BASIC_RESPONSE_ROOF, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } switch (objectID) { case BASIC_RESPONSE_TBS_DATA: this->tbsResponseData = object; break; case BASIC_RESPONSE_VERSION: - version = (object.len)? (1 + (u_int)*object.ptr) : 1; + { + u_int version = (object.len)? (1 + (u_int)*object.ptr) : 1; + if (version != OCSP_BASIC_RESPONSE_VERSION) { DBG1(" ocsp ResponseData version %d not supported", version); - return FALSE; + success = FALSE; + goto end; } break; + } case BASIC_RESPONSE_ID_BY_NAME: this->responderId = identification_create_from_encoding( ID_DER_ASN1_DN, object); @@ -533,13 +535,14 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, DBG2(" '%D'", this->responderId); break; case BASIC_RESPONSE_PRODUCED_AT: - this->producedAt = asn1totime(&object, ASN1_GENERALIZEDTIME); + this->producedAt = asn1_to_time(&object, ASN1_GENERALIZEDTIME); break; case BASIC_RESPONSE_RESPONSES: responses = object; + responses_level = parser->get_level(parser)+1; break; case BASIC_RESPONSE_EXT_ID: - extn_oid = known_oid(object); + extn_oid = asn1_known_oid(object); break; case BASIC_RESPONSE_CRITICAL: critical = object.len && *object.ptr; @@ -552,8 +555,8 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, } break; case BASIC_RESPONSE_ALGORITHM: - this->signatureAlgorithm = parse_algorithmIdentifier( - object, level+1, NULL); + this->signatureAlgorithm = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser)+1, NULL); break; case BASIC_RESPONSE_SIGNATURE: this->signature = object; @@ -561,7 +564,8 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, case BASIC_RESPONSE_CERTIFICATE: { cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,CERT_X509, - BUILD_BLOB_ASN1_DER, chunk_clone(object), + BUILD_BLOB_ASN1_DER, + chunk_clone(object), BUILD_END); if (cert) { @@ -570,34 +574,58 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this, break; } } - objectID++; } - if (!this->responderId) + +end: + success &= parser->success(parser); + parser->destroy(parser); + + if (success) { - this->responderId = identification_create_from_encoding(ID_ANY, chunk_empty); + if (!this->responderId) + { + this->responderId = identification_create_from_encoding(ID_ANY, + chunk_empty); + } + success = parse_responses(this, responses, responses_level); } - return parse_responses(this, responses, level + 1); + return success; } /** + * ASN.1 definition of ocspResponse + */ +static const asn1Object_t ocspResponseObjects[] = { + { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ + { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ + { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ + { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ + { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ + { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ +}; +#define OCSP_RESPONSE_STATUS 1 +#define OCSP_RESPONSE_TYPE 4 +#define OCSP_RESPONSE 5 +#define OCSP_RESPONSE_ROOF 7 + +/** * Parse OCSPResponse object */ static bool parse_OCSPResponse(private_x509_ocsp_response_t *this) { - asn1_ctx_t ctx; + asn1_parser_t *parser; chunk_t object; - u_int level; - int objectID = 0; + int objectID; int responseType = OID_UNKNOWN; + bool success = FALSE; ocsp_status_t status; - asn1_init(&ctx, this->encoding, 0, FALSE, FALSE); - while (objectID < OCSP_RESPONSE_ROOF) + parser = asn1_parser_create(ocspResponseObjects, OCSP_RESPONSE_ROOF, + this->encoding); + + while (parser->iterate(parser, &objectID, &object)) { - if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx)) - { - return FALSE; - } switch (objectID) { case OCSP_RESPONSE_STATUS: @@ -609,26 +637,29 @@ static bool parse_OCSPResponse(private_x509_ocsp_response_t *this) default: DBG1(" ocsp response status: %N", ocsp_status_names, status); - return FALSE; + goto end; } break; case OCSP_RESPONSE_TYPE: - responseType = known_oid(object); + responseType = asn1_known_oid(object); break; case OCSP_RESPONSE: switch (responseType) { case OID_BASIC: - return parse_basicOCSPResponse(this, object, level+1); + success = parse_basicOCSPResponse(this, object, + parser->get_level(parser)+1); default: DBG1(" ocsp response type %#B not supported", &object); - return FALSE; } break; } - objectID++; } - return FALSE; + +end: + success &= parser->success(parser); + parser->destroy(parser); + return success; } /** diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index e44ba7d6f..45f9c6f8d 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -27,6 +27,7 @@ #include "identification.h" +#include <asn1/oid.h> #include <asn1/asn1.h> ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS, @@ -393,7 +394,7 @@ static bool dntoa(chunk_t dn, chunk_t *str) } /* print OID */ - oid_code = known_oid(oid); + oid_code = asn1_known_oid(oid); if (oid_code == OID_UNKNOWN) { update_chunk(str, snprintf(str->ptr,str->len,"0x#B", &oid)); @@ -462,7 +463,7 @@ static bool same_dn(chunk_t a, chunk_t b) /* 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))) + (type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL))) { if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) { @@ -538,7 +539,7 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards) /* 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))) + (type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL))) { if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) { @@ -649,7 +650,8 @@ static status_t atodn(char *src, chunk_t *dn) { name.len -= whitespace; rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING - && !is_printablestring(name))? ASN1_T61STRING : x501rdns[i].type; + && !asn1_is_printablestring(name)) + ? ASN1_T61STRING : x501rdns[i].type; if (rdn_count < RDN_MAX) { @@ -679,7 +681,7 @@ static status_t atodn(char *src, chunk_t *dn) /* build the distinguished name sequence */ { int i; - u_char *pos = build_asn1_object(dn, ASN1_SEQUENCE, dn_len); + u_char *pos = asn1_build_object(dn, ASN1_SEQUENCE, dn_len); for (i = 0; i < rdn_count; i++) { diff --git a/src/libstrongswan/utils/lexparser.h b/src/libstrongswan/utils/lexparser.h index 1c0a9997a..1cbbc05f7 100644 --- a/src/libstrongswan/utils/lexparser.h +++ b/src/libstrongswan/utils/lexparser.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2001-2006 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 diff --git a/src/openac/openac.c b/src/openac/openac.c index f2d879f7a..210e1f676 100755 --- a/src/openac/openac.c +++ b/src/openac/openac.c @@ -418,7 +418,7 @@ int main(int argc, char **argv) { chunk_t date = { optarg, 15 }; - notBefore = asn1totime(&date, ASN1_GENERALIZEDTIME); + notBefore = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; @@ -431,7 +431,7 @@ int main(int argc, char **argv) else { chunk_t date = { optarg, 15 }; - notAfter = asn1totime(&date, ASN1_GENERALIZEDTIME); + notAfter = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; |