diff --git a/lib/asn1/Makefile.am b/lib/asn1/Makefile.am index 8dbff2262..94d24fc47 100644 --- a/lib/asn1/Makefile.am +++ b/lib/asn1/Makefile.am @@ -390,7 +390,10 @@ crmf_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/cr $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_template_asn1 || (rm -f crmf_template_asn1_files ; exit 1) krb5_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt - $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/krb5.opt $(srcdir)/krb5.asn1 krb5_template_asn1 || (rm -f krb5_template_asn1_files ; exit 1) + $(ASN1_COMPILE) --one-code-file --template \ + --option-file=$(srcdir)/krb5.opt \ + --decorate='Principal:PrincipalNameAttrs:nameattrs?' \ + $(srcdir)/krb5.asn1 krb5_template_asn1 || (rm -f krb5_template_asn1_files ; exit 1) ocsp_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_template_asn1 || (rm -f ocsp_template_asn1_files ; exit 1) @@ -429,7 +432,10 @@ crmf_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_asn1 || (rm -f crmf_asn1_files ; exit 1) krb5_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt - $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/krb5.opt $(srcdir)/krb5.asn1 krb5_asn1 || (rm -f krb5_asn1_files ; exit 1) + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) \ + --option-file=$(srcdir)/krb5.opt \ + --decorate='Principal:PrincipalNameAttrs:nameattrs?' \ + $(srcdir)/krb5.asn1 krb5_asn1 || (rm -f krb5_asn1_files ; exit 1) ocsp_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_asn1 || (rm -f ocsp_asn1_files ; exit 1) @@ -462,10 +468,17 @@ x690sample_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 $(ASN1_COMPILE) --one-code-file $(srcdir)/x690sample.asn1 x690sample_asn1 || (rm -f x690sample_asn1_files ; exit 1) test_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 - $(ASN1_COMPILE) --one-code-file --template --sequence=TESTSeqOf $(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1) + $(ASN1_COMPILE) --one-code-file \ + --template \ + --sequence=TESTSeqOf \ + --decorate='TESTDecorated:TESTuint32:version2?' \ + $(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1) test_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 - $(ASN1_COMPILE) --one-code-file --sequence=TESTSeqOf $(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1) + $(ASN1_COMPILE) --one-code-file \ + --decorate='TESTDecorated:TESTuint32:version2?' \ + --sequence=TESTSeqOf \ + $(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1) EXTRA_DIST = \ diff --git a/lib/asn1/NTMakefile b/lib/asn1/NTMakefile index c15e4665b..379ecfa13 100644 --- a/lib/asn1/NTMakefile +++ b/lib/asn1/NTMakefile @@ -202,6 +202,7 @@ $(gen_files_krb5) $(OBJ)\krb5_asn1.hx: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5 $(BINDIR)\asn1_compile.exe \ --template \ --one-code-file \ + --decorate="Principal:PrincipalNameAttrs:nameattrs?" \ --option-file=$(SRCDIR)\krb5.opt \ $(SRCDIR)\krb5.asn1 krb5_asn1 \ || ($(RM) $(OBJ)\krb5_asn1.h ; exit /b 1) @@ -315,6 +316,7 @@ $(gen_files_test) $(OBJ)\test_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ + --decorate='TESTDecorated:TESTuint32:version2?' \ --one-code-file --sequence=TESTSeqOf \ $(SRCDIR)\test.asn1 test_asn1 \ || ($(RM) $(OBJ)\test_asn1.h ; exit /b 1) @@ -324,7 +326,8 @@ $(gen_files_test_template) $(OBJ)\test_template_asn1.hx: $(BINDIR)\asn1_compile. cd $(OBJ) $(BINDIR)\asn1_compile.exe \ --template \ - --one-code-file --template \ + --decorate='TESTDecorated:TESTuint32:version2?' \ + --one-code-file \ --sequence=TESTSeqOf \ $(SRCDIR)\test.asn1 test_template_asn1 \ || ($(RM) $(OBJ)\test_template_asn1.h ; exit /b 1) diff --git a/lib/asn1/README.md b/lib/asn1/README.md index 6762a407d..a00dde722 100644 --- a/lib/asn1/README.md +++ b/lib/asn1/README.md @@ -843,7 +843,23 @@ In recent times the following features have been added: ## Compiler Usage -First, see the manual page `asn1_compile.1`: +The various options for the Heimdal ASN.1 compiler are described in its manual +page, which is included below. + +The `--option-file=FILE` option is particularly useful, as it allows additional +compiler options to be read from a file. + +The `--preserve-binary=TYPE-NAME` option is critical for signature validation +as it causes the decoder to save the encoding of the given type so that +signature validation code can easily find the original encoding and thus avoid +having to re-encode or resort to other hacks. E.g., we use this for preserving +the original encoding of the `tbsCertificate` field of `Certificate`. + +The `--sequence=TYPE-NAME` causes the compiler to generate additional utility +functions for adding or removing items from the named type when it is a +`SEQUENCE OF` or `SET OF` type. + +See the manual page `asn1_compile.1`: ``` ASN1_COMPILE(1) HEIMDAL General Commands Manual ASN1_COMPILE(1) @@ -856,6 +872,7 @@ SYNOPSIS [--encode-rfc1510-bit-string] [--decode-dce-ber] [--support-ber] [--preserve-binary=TYPE-NAME] [--sequence=TYPE-NAME] [--one-code-file] [--gen-name=NAME] + [--decorate=TYPE-NAME:FIELD-TYPE:field-name[?]] [--option-file=FILE] [--original-order] [--no-parse-units] [--type-file=C-HEADER-FILE] [--version] [--help] [FILE.asn1 [NAME]] @@ -870,7 +887,7 @@ DESCRIPTION Use the “template” backend instead of the “codegen” backend (which is the default backend). The template backend generates “templates” which are akin to bytecode, and which are interpreted - at run-time. The codegen backend generates C code for all func‐ + at run-time. The codegen backend generates C code for all func- tions directly, with no template interpretation. The template backend scales better than the codegen backend because as we add support for more encoding rules the templates stay mostly the @@ -897,13 +914,22 @@ DESCRIPTION --preserve-binary=TYPE-NAME Generate ‘_save’ fields in structs to preserve the original encoding of some sub-value. This is useful for cryptographic - applications to avoid having to re-encode values to check signa‐ + applications to avoid having to re-encode values to check signa- tures, etc. --sequence=TYPE-NAME Generate add/remove functions for ‘SET OF’ and ‘SEQUENCE OF’ types. + --decorate=TYPE-NAME:FIELD-TYPE:field-name[?] + Add to the TYPE-NAME SET or SEQUENCE type a field of the given + FIELD-TYPE and field-name, but do not encode or decode this + field. If the field-name ends in a question mark, then treat the + field as OPTIONAL for the purposes of copy/free function stubs. + This is useful for adding fields to existing types that can be + used for internal bookkeeping but which do not affect interoper- + ability because they are not encoded. + --one-code-file Generate a single source code file. Otherwise a separate code file will be generated for every type. @@ -916,7 +942,7 @@ DESCRIPTION --original-order Attempt to preserve the original order of type definition in the - ASN.1 module. By default the compiler generates types in a topo‐ + ASN.1 module. By default the compiler generates types in a topo- logical sort order. --no-parse-units @@ -1065,9 +1091,9 @@ SYNOPSIS [-l -v | --version] [-l -h | --help] [FILE [TypeName...]] DESCRIPTION - asn1_print Dumps ASN.1 DER-encoded values. If one or more TypeName argu‐ - ments are given, then asn1_print will print the value in a JSON-like for‐ - mat using its knowledge of the ASN.1 modules defining those types, stop‐ + asn1_print Dumps ASN.1 DER-encoded values. If one or more TypeName argu- + ments are given, then asn1_print will print the value in a JSON-like for- + mat using its knowledge of the ASN.1 modules defining those types, stop- ping at the first type for which it can successfully decode the value. If TypeNames are given, they must be the names of ASN.1 types exported by an ASN.1 modules that are compiled into asn1_print. Use the diff --git a/lib/asn1/asn1-template.h b/lib/asn1/asn1-template.h index a8501e76f..e75734ea2 100644 --- a/lib/asn1/asn1-template.h +++ b/lib/asn1/asn1-template.h @@ -169,6 +169,7 @@ #define A1_OP_OPENTYPE_ID (0xb0000000) #define A1_OP_OPENTYPE (0xc0000000) #define A1_OP_NAME (0xd0000000) +#define A1_OP_TYPE_DECORATE (0xe0000000) #define A1_FLAG_MASK (0x0f000000) #define A1_FLAG_OPTIONAL (0x01000000) diff --git a/lib/asn1/asn1_compile.1 b/lib/asn1/asn1_compile.1 index 206111981..74cf314f1 100644 --- a/lib/asn1/asn1_compile.1 +++ b/lib/asn1/asn1_compile.1 @@ -48,6 +48,7 @@ .Op Fl Fl support-ber .Op Fl Fl preserve-binary=TYPE-NAME .Op Fl Fl sequence=TYPE-NAME +.Op Fl Fl decorate=TYPE-NAME:FIELD-TYPE:field-name[?] .Op Fl Fl one-code-file .Op Fl Fl gen-name=NAME .Op Fl Fl option-file=FILE @@ -109,6 +110,21 @@ Generate add/remove functions for and .Sq SEQUENCE OF types. +.It Fl Fl decorate=TYPE-NAME:FIELD-TYPE:field-name[?] +Add to the +.Va TYPE-NAME +SET or SEQUENCE type a field of the given +.Va FIELD-TYPE +and +.Va field-name , +but do not encode or decode this field. +If the +.Va field-name +ends in a question mark, then treat the field as OPTIONAL for +the purposes of copy/free function stubs. +This is useful for adding fields to existing types that can be used +for internal bookkeeping but which do not affect interoperability +because they are not encoded. .It Fl Fl one-code-file Generate a single source code file. Otherwise a separate code file will be generated for every type. diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index bce81954c..f49f5e8ed 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -100,9 +100,9 @@ test_principal (void) Principal values[] = { - { { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, "SU.SE" }, - { { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, "SU.SE" }, - { { KRB5_NT_SRV_HST, { 2, datan_princ } }, "E.KTH.SE" } + { { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, "SU.SE", NULL }, + { { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, "SU.SE", NULL }, + { { KRB5_NT_SRV_HST, { 2, datan_princ } }, "E.KTH.SE", NULL } }; int i, ret; int ntests = sizeof(tests) / sizeof(*tests); @@ -1016,6 +1016,50 @@ test_choice (void) return ret; } +/* Test --decorate=TYPE:FIELD-TYPE:field-name[?] */ +static int +test_decorated(void) +{ + TESTNotDecorated tnd; + TESTDecorated td; + size_t len, size; + void *ptr; + int ret; + + memset(&td, 0, sizeof(td)); + memset(&tnd, 0, sizeof(tnd)); + + td.version = 3; + if ((td.version2 = malloc(sizeof(*td.version2))) == NULL) + errx(1, "out of memory"); + *td.version2 = 5; + ASN1_MALLOC_ENCODE(TESTDecorated, ptr, len, &td, &size, ret); + if (ret) { + warnx("could not encode a TESTDecorated struct"); + return 1; + } + ret = decode_TESTNotDecorated(ptr, len, &tnd, &size); + if (ret) { + warnx("could not decode a TESTDecorated struct as TESTNotDecorated"); + return 1; + } + if (size != len) { + warnx("TESTDecorated encoded size mismatch"); + return 1; + } + if (td.version != tnd.version) { + warnx("TESTDecorated did not decode as a TESTNotDecorated correctly"); + return 1; + } + free_TESTDecorated(&td); + if (td.version2) { + warnx("free_TESTDecorated() did not work correctly"); + return 1; + } + return 0; +} + + static int cmp_TESTImplicit (void *a, void *b) { @@ -2493,6 +2537,8 @@ main(int argc, char **argv) DO_ONE(test_default); + DO_ONE(test_decorated); + #if ASN1_IOS_SUPPORTED DO_ONE(test_ios); #endif diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index 9af97a34a..8e323188f 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -1355,6 +1355,8 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t case TSet: case TSequence: { Member *m; + char *ft, *fn; + int deco_opt; getnewbasename(&newbasename, typedefp || level == 0, basename, name); @@ -1395,6 +1397,13 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t fprintf(jsonfile, ",\"opentype\":"); define_open_type(level, newbasename, name, basename, t, t); } + if (decorate_type(newbasename, &ft, &fn, &deco_opt)) { + space(level + 1); + fprintf(headerfile, "%s %s%s;\n", ft, deco_opt ? "*" : "", fn); + fprintf(jsonfile, ",\"decorate\":{\"type\":\"%s\",\"name\":\"%s\", \"optional\":%s}", ft, fn, deco_opt ? "true" : "false"); + free(ft); + free(fn); + } space(level); fprintf (headerfile, "} %s;\n", name); break; diff --git a/lib/asn1/gen_copy.c b/lib/asn1/gen_copy.c index cc9a9a32f..243aa2b0c 100644 --- a/lib/asn1/gen_copy.c +++ b/lib/asn1/gen_copy.c @@ -229,6 +229,9 @@ void generate_type_copy (const Symbol *s) { int preserve = preserve_type(s->name) ? TRUE : FALSE; + int save_used_fail = used_fail; + int deco_opt; + char *ft, *fn; used_fail = 0; @@ -238,6 +241,19 @@ generate_type_copy (const Symbol *s) "memset(to, 0, sizeof(*to));\n", s->gen_name, s->gen_name, s->gen_name); copy_type ("from", "to", s->type, preserve); + if (decorate_type(s->gen_name, &ft, &fn, &deco_opt)) { + if (deco_opt) { + fprintf(codefile, "if (from->%s) {\n", fn); + fprintf(codefile, "(to)->%s = malloc(sizeof(*(to)->%s));\n", fn, fn); + fprintf(codefile, "if (copy_%s((from)->%s, (to)->%s)) goto fail;\n", ft, fn, fn); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "if (copy_%s(&(from)->%s, &(to)->%s)) goto fail;\n", ft, fn, fn); + } + used_fail++; + free(ft); + free(fn); + } fprintf (codefile, "return 0;\n"); if (used_fail) @@ -248,5 +264,6 @@ generate_type_copy (const Symbol *s) fprintf(codefile, "}\n\n"); + used_fail = save_used_fail; } diff --git a/lib/asn1/gen_free.c b/lib/asn1/gen_free.c index 76a316913..6c9424cbf 100644 --- a/lib/asn1/gen_free.c +++ b/lib/asn1/gen_free.c @@ -119,7 +119,7 @@ free_type (const char *name, const Type *t, int preserve) have_ellipsis->label, name, have_ellipsis->gen_name); fprintf(codefile, "}\n"); - } + } break; } case TSetOf: @@ -179,6 +179,8 @@ void generate_type_free (const Symbol *s) { int preserve = preserve_type(s->name) ? TRUE : FALSE; + int deco_opt; + char *ft, *fn; fprintf (codefile, "void ASN1CALL\n" "free_%s(%s *data)\n" @@ -186,6 +188,19 @@ generate_type_free (const Symbol *s) s->gen_name, s->gen_name); free_type ("data", s->type, preserve); + if (decorate_type(s->gen_name, &ft, &fn, &deco_opt)) { + if (deco_opt) { + fprintf(codefile, "if ((data)->%s) {\n", fn); + fprintf(codefile, "free_%s((data)->%s);\n", ft, fn); + fprintf(codefile, "free((data)->%s);\n", fn); + fprintf(codefile, "(data)->%s = NULL;\n", fn); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "free_%s(&(data)->%s);\n", ft, fn); + } + free(ft); + free(fn); + } fprintf (codefile, "}\n\n"); } diff --git a/lib/asn1/gen_locl.h b/lib/asn1/gen_locl.h index 36281f7e5..ccef2acd2 100644 --- a/lib/asn1/gen_locl.h +++ b/lib/asn1/gen_locl.h @@ -144,6 +144,7 @@ int is_tagged_type(const Type *); int preserve_type(const char *); int seq_type(const char *); +int decorate_type(const char *, char **, char **, int *); void generate_header_of_codefile(const char *); void close_codefile(void); diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c index a1c38edae..af1e44ee6 100644 --- a/lib/asn1/gen_template.c +++ b/lib/asn1/gen_template.c @@ -1063,6 +1063,8 @@ template_members(struct templatehead *temp, Member *m; size_t i = 0, typeididx = 0, opentypeidx = 0; int is_array_of_open_type = 0; + int deco_opt; + char *ft, *fn; if (isstruct && t->actual_parameter) get_open_type_defn_fields(t, &typeidmember, &opentypemember, @@ -1102,6 +1104,17 @@ template_members(struct templatehead *temp, typeidfield, opentypefield, opentypemember, is_array_of_open_type); + if (decorate_type(basetype, &ft, &fn, &deco_opt)) { + char *poffset2; + + poffset2 = partial_offset(basetype, fn, 1, isstruct); + add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s", + deco_opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(ft); + free(fn); + } + if (isstruct) template_names(temp, basetype, t); break; @@ -1114,6 +1127,8 @@ template_members(struct templatehead *temp, Member *m; size_t i = 0, typeididx = 0, opentypeidx = 0; int is_array_of_open_type = 0; + int deco_opt; + char *ft, *fn; if (isstruct && t->actual_parameter) get_open_type_defn_fields(t, &typeidmember, &opentypemember, @@ -1153,6 +1168,17 @@ template_members(struct templatehead *temp, typeidfield, opentypefield, opentypemember, is_array_of_open_type); + if (decorate_type(basetype, &ft, &fn, &deco_opt)) { + char *poffset2; + + poffset2 = partial_offset(basetype, fn, 1, isstruct); + add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s", + deco_opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(ft); + free(fn); + } + if (isstruct) template_names(temp, basetype, t); break; diff --git a/lib/asn1/main.c b/lib/asn1/main.c index 7acb62427..64db63ab2 100644 --- a/lib/asn1/main.c +++ b/lib/asn1/main.c @@ -39,6 +39,7 @@ extern FILE *yyin; static getarg_strings preserve; static getarg_strings seq; +static getarg_strings decorate; int preserve_type(const char *p) @@ -53,13 +54,49 @@ preserve_type(const char *p) int seq_type(const char *p) { - int i; + size_t i; + for (i = 0; i < seq.num_strings; i++) if (strcmp(seq.strings[i], p) == 0) return 1; return 0; } +int +decorate_type(const char *p, char **field_type, char **field_name, int *opt) +{ + size_t plen = strlen(p); + size_t i; + + *field_type = NULL; + *field_name = NULL; + *opt = 0; + + for (i = 0; i < decorate.num_strings; i++) { + const char *r; + char *q; + + if (strncmp(decorate.strings[i], p, plen) != 0) + continue; + if (decorate.strings[i][plen] != ':') + errx(1, "--decorate argument missing field type"); + + p = &decorate.strings[i][plen + 1]; + if ((r = strchr(p, ':')) == NULL) + errx(1, "--decorate argument missing field name"); + r++; + *field_type = estrdup(p); + *(strchr(*field_type, ':')) = '\0'; + *field_name = estrdup(r); + if ((q = strchr(*field_name, '?'))) { + *q = '\0'; + *opt = 1; + } + return 1; + } + return 0; +} + static const char * my_basename(const char *fn) { @@ -113,6 +150,8 @@ struct getargs args[] = { "verification)", "TYPE-NAME" }, { "sequence", 0, arg_strings, &seq, "Generate add/remove functions for SEQUENCE OF types", "TYPE-NAME" }, + { "decorate", 0, arg_strings, &decorate, + "Generate private field for SEQUENCE/SET type", "TYPE-NAME:FIELD_TYPE:field_name[?]" }, { "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL }, { "gen-name", 0, arg_string, &name, "Name of generated module", "NAME" }, diff --git a/lib/asn1/template.c b/lib/asn1/template.c index 7e5a2decd..6f303d111 100644 --- a/lib/asn1/template.c +++ b/lib/asn1/template.c @@ -774,6 +774,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, return ret; break; } + case A1_OP_TYPE_DECORATE: break; case A1_OP_NAME: break; case A1_OP_DEFVAL: tdefval = t; @@ -1417,6 +1418,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { size_t newsize; @@ -1992,6 +1994,7 @@ _asn1_length(const struct asn1_template *t, const void *data) } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE: break; case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { const void *el = DPOC(data, t->offset); @@ -2253,6 +2256,7 @@ _asn1_free(const struct asn1_template *t, void *data) } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE: case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { void *el = DPO(data, t->offset); @@ -2264,7 +2268,7 @@ _asn1_free(const struct asn1_template *t, void *data) el = *pel; } - if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { _asn1_free(t->ptr, el); } else { const struct asn1_type_func *f = t->ptr; @@ -2541,6 +2545,7 @@ _asn1_print(const struct asn1_template *t, break; case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE: break; /* We could probably print this though */ case A1_OP_TYPE: case A1_OP_TYPE_EXTERN: { const void *el = DPOC(data, t->offset); @@ -2858,6 +2863,7 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to) } case A1_OP_NAME: break; case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE: 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 1fbd461e7..a76152712 100644 --- a/lib/asn1/test.asn1 +++ b/lib/asn1/test.asn1 @@ -286,4 +286,14 @@ TESTExtensible ::= SEQUENCE { extensions SEQUENCE OF TESTExtension } +TESTDecorated ::= SEQUENCE { + version TESTuint32 + -- gets decorated +} + +TESTNotDecorated ::= SEQUENCE { + version TESTuint32 + -- should have the same encoding as TESTDecorated +} + END