From 783b632f1fcecffc6ddf99e599a5661bfa21fde1 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Thu, 28 Jan 2021 00:05:14 -0600 Subject: [PATCH] asn1: Teach template backend to DEFAULT --- lib/asn1/asn1-template.h | 18 +++ lib/asn1/check-gen.c | 67 +++++++++++ lib/asn1/gen_template.c | 144 ++++++++++++++++++++--- lib/asn1/template.c | 240 +++++++++++++++++++++++++++++++++++++-- lib/asn1/test.asn1 | 10 +- 5 files changed, 453 insertions(+), 26 deletions(-) diff --git a/lib/asn1/asn1-template.h b/lib/asn1/asn1-template.h index e35385c4f..aba17d76d 100644 --- a/lib/asn1/asn1-template.h +++ b/lib/asn1/asn1-template.h @@ -38,6 +38,11 @@ #ifndef __TEMPLATE_H__ #define __TEMPLATE_H__ +/* header: + * HF flags if not a BIT STRING type + * HBF flags if a BIT STRING type + */ + /* tag: * 0..20 tag * 21 type @@ -53,6 +58,11 @@ * 28..31 op */ +/* defval: (next template entry is defaulted) + * + * DV flags (ptr is or points to defval) + */ + #define A1_OP_MASK (0xf0000000) #define A1_OP_TYPE (0x10000000) #define A1_OP_TYPE_EXTERN (0x20000000) @@ -62,10 +72,12 @@ #define A1_OP_SETOF (0x60000000) #define A1_OP_BMEMBER (0x70000000) #define A1_OP_CHOICE (0x80000000) +#define A1_OP_DEFVAL (0x90000000) #define A1_FLAG_MASK (0x0f000000) #define A1_FLAG_OPTIONAL (0x01000000) #define A1_FLAG_IMPLICIT (0x02000000) +#define A1_FLAG_DEFAULT (0x04000000) #define A1_TAG_T(CLASS,TYPE,TAG) ((A1_OP_TAG) | (((CLASS) << 22) | ((TYPE) << 21) | (TAG))) #define A1_TAG_CLASS(x) (((x) >> 22) & 0x3) @@ -87,6 +99,12 @@ #define A1_HBF_RFC1510 0x1 +#define A1_DV_BOOLEAN 0x01 +#define A1_DV_INTEGER 0x02 +#define A1_DV_INTEGER32 0x04 +#define A1_DV_INTEGER64 0x08 +#define A1_DV_UTF8STRING 0x10 + struct asn1_template { uint32_t tt; diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index 93528ec9d..6d6cc18f7 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -1888,6 +1888,71 @@ test_seqof5(void) return ret; } +static int +cmp_default(void *a, void *b) +{ + TESTDefault *aa = a; + TESTDefault *ab = b; + + COMPARE_STRING(aa,ab,name); + COMPARE_INTEGER(aa,ab,version); + COMPARE_INTEGER(aa,ab,maxint); + COMPARE_INTEGER(aa,ab,works); + return 0; +} + +static int +test_default(void) +{ + struct test_case tests[] = { + { NULL, 2, "\x30\x00", NULL }, + { NULL, 25, + "\x30\x17\x0c\x07\x68\x65\x69\x6d\x64\x61" + "\x6c\xa0\x03\x02\x01\x07\x02\x04\x7f\xff" + "\xff\xff\x01\x01\x00", + NULL + }, + { NULL, 10, + "\x30\x08\xa0\x03\x02\x01\x07\x01\x01\x00", + NULL + }, + { NULL, 17, + "\x30\x0f\x0c\x07\x68\x65\x69\x6d\x64\x61\x6c\x02\x04" + "\x7f\xff\xff\xff", + NULL + } + }; + + TESTDefault values[] = { + { "Heimdal", 8, 9223372036854775807, 1 }, + { "heimdal", 7, 2147483647, 0 }, + { "Heimdal", 7, 9223372036854775807, 0 }, + { "heimdal", 8, 2147483647, 1 }, + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "TESTDefault %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(TESTDefault), + (generic_encode)encode_TESTDefault, + (generic_length)length_TESTDefault, + (generic_decode)decode_TESTDefault, + (generic_free)free_TESTDefault, + cmp_default, + (generic_copy)copy_TESTDefault); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + + return ret; +} + static int test_x690sample(void) { @@ -2005,5 +2070,7 @@ main(int argc, char **argv) DO_ONE(test_x690sample); + DO_ONE(test_default); + return ret; } diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c index 2879a16b6..a6b1e2e31 100644 --- a/lib/asn1/gen_template.c +++ b/lib/asn1/gen_template.c @@ -54,6 +54,7 @@ */ #include "gen_locl.h" +#include static const char *symbol_name(const char *, const Type *); static void generate_template_type(const char *, const char **, const char *, const char *, const char *, @@ -182,8 +183,7 @@ bitstring_symbol(const char *basename, const Type *t) /* XXX Make sure this is sorted by `type' and can just index this by type */ -/* XXX Make this const! */ -struct { +const struct { enum typetype type; const char *(*symbol_name)(const char *, const Type *); int is_struct; @@ -499,7 +499,109 @@ compact_tag(const Type *t) } static void -template_members(struct templatehead *temp, const char *basetype, const char *name, const Type *t, int optional, int implicit, int isstruct, int need_offset) +defval(struct templatehead *temp, Member *m) +{ + switch (m->defval->type) { + case booleanvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)%u }", + m->defval->u.booleanvalue); + break; + case nullvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)0 }"); + break; + case integervalue: { + const char *dv = "A1_DV_INTEGER"; + Type *t = m->type; + + for (;;) { + if (t->range) + break; + if (t->type == TInteger && t->members) + break; + if (t->type == TEnumerated) + break; + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + errx(1, "DEFAULT values for unconstrained INTEGER members not supported"); + } + + if (t->members) + dv = "A1_DV_INTEGER32"; /* XXX Enum size assumptions! No good! */ + else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) + dv = "A1_DV_INTEGER64"; + else if (t->range->min >= 0 && t->range->max > UINT_MAX) + dv = "A1_DV_INTEGER64"; + else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) + dv = "A1_DV_INTEGER32"; + else if (t->range->min >= 0 && t->range->max <= UINT_MAX) + dv = "A1_DV_INTEGER32"; + else + errx(1, "unsupported range %lld -> %lld", + (long long)m->type->range->min, (long long)m->type->range->max); + add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)%llu }", + dv, (long long)m->defval->u.integervalue); + break; + } + case stringvalue: { + char *quoted; + + if (rk_strasvis("ed, m->defval->u.stringvalue, + VIS_CSTYLE | VIS_DQ | VIS_NL, "") < 0) + err(1, "Could not quote a string"); + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)\"%s\" }", + quoted); + free(quoted); + break; + } + case objectidentifiervalue: { + struct objid *o; + size_t sz = sizeof("{ }"); + char *s, *p; + int len; + + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(0, 0, " %d", o->value)) < 0) + err(1, "Could not format integer"); + sz += len; + } + + if ((p = s = malloc(sz)) == NULL) + err(1, "Could not allocate string"); + + len = snprintf(p, sz, "{"); + sz -= len; + p += len; + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(p, sz, " %d", o->value)) < 0 || len > sz - 1) + err(1, "Could not format integer"); + sz -= len; + p += len; + } + len = snprintf(p, sz, " }"); + sz -= len; + p += len; + + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)\"%s\" }", s); + free(s); + break; + } + default: abort(); + } +} + +static void +template_members(struct templatehead *temp, + const char *basetype, + const char *name, + const Type *t, + int optional, + int defaulted, + int implicit, + int isstruct, + int need_offset) { char *poffset = NULL; @@ -511,15 +613,17 @@ template_members(struct templatehead *temp, const char *basetype, const char *na switch (t->type) { case TType: if (use_extern(t->symbol)) { - add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s, %s, &asn1_extern_%s}", - optional ? "|A1_FLAG_OPTIONAL" : "", - implicit ? "|A1_FLAG_IMPLICIT" : "", + add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s%s, %s, &asn1_extern_%s}", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : "", poffset, t->symbol->gen_name); } else { add_line_pointer(temp, t->symbol->gen_name, poffset, - "A1_OP_TYPE %s%s", - optional ? "|A1_FLAG_OPTIONAL" : "", - implicit ? "|A1_FLAG_IMPLICIT" : ""); + "A1_OP_TYPE %s%s%s", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : ""); } break; @@ -650,7 +754,10 @@ template_members(struct templatehead *temp, const char *basetype, const char *na if (newbasename == NULL) errx(1, "malloc"); - template_members(temp, newbasename, m->gen_name, m->type, m->optional, 0, isstruct, 1); + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); free(newbasename); } @@ -676,7 +783,10 @@ template_members(struct templatehead *temp, const char *basetype, const char *na if (newbasename == NULL) errx(1, "malloc"); - template_members(temp, newbasename, m->gen_name, m->type, m->optional, 0, isstruct, 1); + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); free(newbasename); } @@ -720,11 +830,12 @@ template_members(struct templatehead *temp, const char *basetype, const char *na t->subtype, 0, subtype_is_struct, 0); add_line_pointer(temp, dupname, poffset, - "A1_TAG_T(%s,%s,%s)%s%s", + "A1_TAG_T(%s,%s,%s)%s%s%s", classname(t->tag.tagclass), prim ? "PRIM" : "CONS", valuename(t->tag.tagclass, t->tag.tagvalue), - optional ? "|A1_FLAG_OPTIONAL" : "", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", tagimplicit ? "|A1_FLAG_IMPLICIT" : ""); free(tname); @@ -900,7 +1011,9 @@ generate_template_type(const char *varname, const char *basetype, const char *name, Type *type, - int optional, int isstruct, int need_offset) + int optional, + int isstruct, + int need_offset) { struct tlist *tl; const char *d; @@ -920,7 +1033,8 @@ generate_template_type(const char *varname, implicit = (type->tag.tagenv == TE_IMPLICIT); } - template_members(&tl->template, basetype, name, type, optional, implicit, isstruct, need_offset); + template_members(&tl->template, basetype, name, type, optional, 0, + implicit, isstruct, need_offset); /* if its a sequence or set type, check if there is a ellipsis */ if (type->type == TSequence || type->type == TSet) { diff --git a/lib/asn1/template.c b/lib/asn1/template.c index 41370367b..84f4898d0 100644 --- a/lib/asn1/template.c +++ b/lib/asn1/template.c @@ -209,6 +209,7 @@ int _asn1_decode(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size) { + const struct asn1_template *tdefval = NULL; size_t elements = A1_HEADER_LEN(t); size_t oldlen = len; int ret = 0; @@ -223,6 +224,9 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, while (elements) { switch (t->tt & A1_OP_MASK) { + case A1_OP_DEFVAL: + tdefval = t; + break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { size_t newsize, elsize; @@ -250,10 +254,45 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, } if (ret) { if (t->tt & A1_FLAG_OPTIONAL) { + /* + * Optional field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ free(*pel); *pel = NULL; break; - } + } else if (t->tt & A1_FLAG_DEFAULT) { + /* + * Defaulted field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if (tdefval->tt & A1_DV_BOOLEAN) { + int *i = (void *)(char *)el; + + *i = tdefval->ptr ? 1 : 0; + } else if (tdefval->tt & A1_DV_INTEGER64) { + int64_t *i = (void *)(char *)el; + + *i = (int64_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER32) { + int32_t *i = (void *)(char *)el; + + *i = (int32_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER) { + struct heim_integer *i = (void *)(char *)el; + + if ((ret = der_copy_heim_integer(tdefval->ptr, i))) + return ret; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + char **s = el; + + if ((*s = strdup(tdefval->ptr)) == NULL) + return ENOMEM; + } else { + abort(); + } + break; + } return ret; } p += newsize; len -= newsize; @@ -269,6 +308,8 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, int subflags = flags; int replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); + data = DPO(data, t->offset); + /* * XXX If this type (chasing t->ptr through IMPLICIT tags, if this * one is too, till we find a non-TTag) is a [UNIVERSAL SET] type, @@ -283,8 +324,42 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, &dertype, A1_TAG_TAG(t->tt), &datalen, &l); if (ret) { - if (t->tt & A1_FLAG_OPTIONAL) + if (t->tt & A1_FLAG_OPTIONAL) { + data = olddata; break; + } else if (t->tt & A1_FLAG_DEFAULT) { + /* + * Defaulted field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if (tdefval->tt & A1_DV_BOOLEAN) { + int *i = (void *)(char *)data; + + *i = tdefval->ptr ? 1 : 0; + } else if (tdefval->tt & A1_DV_INTEGER64) { + int64_t *i = (void *)(char *)data; + + *i = (int64_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER32) { + int32_t *i = (void *)(char *)data; + + *i = (int32_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER) { + struct heim_integer *i = (void *)(char *)data; + + if ((ret = der_copy_heim_integer(tdefval->ptr, i))) + return ret; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + char **s = data; + + if ((*s = strdup(tdefval->ptr)) == NULL) + return ENOMEM; + } else { + abort(); + } + data = olddata; + break; + } return ret; } @@ -316,8 +391,6 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, } else if (datalen > len) return ASN1_OVERRUN; - data = DPO(data, t->offset); - if (t->tt & A1_FLAG_OPTIONAL) { void **el = (void **)data; size_t ellen = _asn1_sizeofType(t->ptr); @@ -484,7 +557,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, /* provide a saner value as default, we should have a NO element value */ *element = 1; - + for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) { /* should match first tag instead, store it in choice.tt */ ret = _asn1_decode(choice[i].ptr, 0, p, len, @@ -556,6 +629,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const while (elements) { switch (t->tt & A1_OP_MASK) { + case A1_OP_DEFVAL: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { size_t newsize; @@ -566,7 +640,40 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const if (*pel == NULL) break; el = *pel; - } + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + /* Compare tdefval to whatever's at `el' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)el; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + break; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)el; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)el; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)el; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = el; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + break; + } else { + abort(); + } + } if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { ret = _asn1_encode(t->ptr, p, len, el, &newsize); @@ -605,7 +712,46 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const break; } data = *el; - } + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + int exclude = 0; + + /* Compare tdefval to whatever's at `data' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)data; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)data; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)data; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)data; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = data; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + exclude = 1; + } else { + abort(); + } + if (exclude) { + data = olddata; + break; + } + } replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); @@ -880,6 +1026,7 @@ _asn1_length(const struct asn1_template *t, const void *data) while (elements) { switch (t->tt & A1_OP_MASK) { + case A1_OP_DEFVAL: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { const void *el = DPOC(data, t->offset); @@ -889,7 +1036,41 @@ _asn1_length(const struct asn1_template *t, const void *data) if (*pel == NULL) break; el = *pel; - } + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + + /* Compare tdefval to whatever's at `el' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)el; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + break; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)el; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)el; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)el; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = el; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + break; + } else { + abort(); + } + } if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { ret += _asn1_length(t->ptr, el); @@ -913,7 +1094,46 @@ _asn1_length(const struct asn1_template *t, const void *data) break; } data = *el; - } + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + int exclude = 0; + + /* Compare tdefval to whatever's at `data' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)data; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)data; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)data; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)data; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + exclude = 1; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = data; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + exclude = 1; + } else { + abort(); + } + if (exclude) { + data = olddata; + break; + } + } if (t->tt & A1_FLAG_IMPLICIT) oldtaglen = inner_type_taglen(t->ptr); @@ -1011,6 +1231,7 @@ _asn1_free(const struct asn1_template *t, void *data) while (elements) { switch (t->tt & A1_OP_MASK) { + case A1_OP_DEFVAL: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { void *el = DPO(data, t->offset); @@ -1121,6 +1342,7 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to) while (elements) { switch (t->tt & A1_OP_MASK) { + case A1_OP_DEFVAL: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { const void *fel = DPOC(from, t->offset); diff --git a/lib/asn1/test.asn1 b/lib/asn1/test.asn1 index 1da1ed794..3696371c2 100644 --- a/lib/asn1/test.asn1 +++ b/lib/asn1/test.asn1 @@ -26,13 +26,19 @@ TESTOutOfOrderBar ::= SEQUENCE { -- which we well might since XDR's syntax is a dual of a strict subset of -- ASN.1, and since XDR the encoding is fairly straightforward. -- --- Note that the `next' member has to be OPTIONAL or DEFAULTed for this to --- work. +-- Note that the `next' member has to be OPTIONAL for this to work. TESTCircular ::= SEQUENCE { name UTF8String, next TESTCircular OPTIONAL } +TESTDefault ::= SEQUENCE { + name UTF8String DEFAULT "Heimdal", + version [0] TESTuint32 DEFAULT 8, + maxint TESTuint64 DEFAULT 9223372036854775807, + works BOOLEAN DEFAULT TRUE +} + TESTuint32 ::= INTEGER (0..4294967295) TESTuint64 ::= INTEGER(0..9223372036854775807) TESTint64 ::= INTEGER(-9223372036854775808..9223372036854775807)