diff --git a/lib/asn1/Makefile.am b/lib/asn1/Makefile.am index 61fd4b049..644cd438d 100644 --- a/lib/asn1/Makefile.am +++ b/lib/asn1/Makefile.am @@ -272,7 +272,7 @@ endif # XXX Currently using the template compiler for rfc2459.asn1 breaks rfc2459_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc2459.asn1 - $(ASN1_COMPILE) --one-code-file --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_asn1 || (rm -f rfc2459_asn1_files ; exit 1) + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_asn1 || (rm -f rfc2459_asn1_files ; exit 1) rfc4043_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4043.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/rfc4043.asn1 rfc4043_asn1 || (rm -f rfc4043_asn1_files ; exit 1) @@ -307,9 +307,8 @@ pkcs9_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs9.asn1 pkcs10_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs10.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/pkcs10.opt $(srcdir)/pkcs10.asn1 pkcs10_asn1 || (rm -f pkcs10_asn1_files ; exit 1) -# XXX Currently using the template compiler for pkcs12.asn1 breaks pkcs12_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs12.asn1 - $(ASN1_COMPILE) --one-code-file $(srcdir)/pkcs12.asn1 pkcs12_asn1 || (rm -f pkcs12_asn1_files ; exit 1) + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs12.asn1 pkcs12_asn1 || (rm -f pkcs12_asn1_files ; exit 1) digest_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/digest.asn1 digest_asn1 || (rm -f digest_asn1_files ; exit 1) @@ -317,6 +316,8 @@ digest_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 kx509_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/kx509.asn1 kx509_asn1 || (rm -f kx509_asn1_files ; exit 1) +# The template compiler doesn't support SET { ... } types yet, so it can't be +# used to compile x690sample.asn1 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) diff --git a/lib/asn1/asn1parse.y b/lib/asn1/asn1parse.y index b26bfb2ce..5a808f57d 100644 --- a/lib/asn1/asn1parse.y +++ b/lib/asn1/asn1parse.y @@ -653,14 +653,36 @@ TaggedType : Tag tagenv Type $$->tag.tagenv = $2; if (template_flag) { $$->subtype = $3; - } else { + } else if ($2 == TE_IMPLICIT) { + Type *t = $3; + + /* + * XXX We shouldn't do this... The logic for + * dealing with IMPLICIT tags belongs elsewhere. + */ + while (t->type == TType) { + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + break; + } + /* + * IMPLICIT tags of CHOICE types are EXPLICIT + * instead. + */ + if (t->type == TChoice) + $$->tag.tagenv = TE_EXPLICIT; if($3->type == TTag && $2 == TE_IMPLICIT) { $$->subtype = $3->subtype; free($3); - } else { - $$->subtype = $3; + } else { + $$->subtype = $3; } - } + } else { + $$->subtype = $3; + } } ; diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index 82a129fe4..3d763cdd0 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -1042,32 +1042,95 @@ cmp_TESTImplicit2 (void *a, void *b) return 0; } -/* -UNIV CONS Sequence 14 - CONTEXT PRIM 0 1 00 - CONTEXT CONS 1 6 - CONTEXT CONS 127 3 - UNIV PRIM Integer 1 02 - CONTEXT PRIM 2 1 03 -*/ +static int +cmp_TESTImplicit3 (void *a, void *b) +{ + TESTImplicit3 *aa = a; + TESTImplicit3 *ab = b; + + COMPARE_INTEGER(aa,ab,element); + if (aa->element == choice_TESTImplicit3_ti1) { + COMPARE_INTEGER(aa,ab,u.ti1); + } else { + COMPARE_INTEGER(aa,ab,u.ti2.element); + COMPARE_INTEGER(aa,ab,u.ti2.u.i1); + } + return 0; +} + +static int +cmp_TESTImplicit4 (void *a, void *b) +{ + TESTImplicit4 *aa = a; + TESTImplicit4 *ab = b; + + COMPARE_INTEGER(aa,ab,element); + if (aa->element == choice_TESTImplicit4_ti1) { + COMPARE_INTEGER(aa,ab,u.ti1); + } else { + COMPARE_INTEGER(aa,ab,u.ti2.element); + COMPARE_INTEGER(aa,ab,u.ti2.u.i1); + } + return 0; +} static int test_implicit (void) { int ret = 0; + /* + * UNIV CONS Sequence = 14 bytes { + * CONTEXT PRIM tag 0 = 1 bytes [0] IMPLICIT content + * CONTEXT CONS tag 1 = 6 bytes [1] + * CONTEXT CONS tag 127 = 3 bytes [127] + * UNIV PRIM Integer = integer 2 + * CONTEXT PRIM tag 2 = 1 bytes [2] IMPLICIT content + * } + */ struct test_case tests[] = { { NULL, 16, "\x30\x0e\x80\x01\x00\xa1\x06\xbf\x7f\x03\x02\x01\x02\x82\x01\x03", "implicit 1" } }; + /* + * UNIV CONS Sequence = 10 bytes { + * CONTEXT PRIM tag 0 = 1 bytes [0] IMPLICIT content + * CONTEXT PRIM tag 2 = 1 bytes [2] IMPLICIT content + * CONTEXT PRIM tag 51 = 1 bytes [51] IMPLICIT content + * } + */ struct test_case tests2[] = { { NULL, 12, "\x30\x0a\x80\x01\x01\x82\x01\x03\x9f\x33\x01\x04", "implicit 2" } }; + /* + * CONTEXT CONS tag 5 = 5 bytes [5] + * CONTEXT CONS tag 1 = 3 bytes [1] + * UNIV PRIM Integer = integer 5 + */ + struct test_case tests3[] = { + { NULL, 7, + "\xa5\x05\xa1\x03\x02\x01\x05", + "implicit 3" } + }; + /* + * Notice: same as tests3[].bytes. + * + * CONTEXT CONS tag 5 = 5 bytes [5] + * CONTEXT CONS tag 1 = 3 bytes [1] + * UNIV PRIM Integer = integer 5 + */ + struct test_case tests4[] = { + { NULL, 7, + "\xa5\x05\xa1\x03\x02\x01\x05", + "implicit 4" } + }; TESTImplicit c0; TESTImplicit2 c1; + TESTImplicit3 c2; + TESTImplicit4 c3; int ti4 = 4; memset(&c0, 0, sizeof(c0)); @@ -1082,6 +1145,18 @@ test_implicit (void) c1.ti4 = &ti4; tests2[0].val = &c1; + memset(&c2, 0, sizeof(c2)); + c2.element = choice_TESTImplicit3_ti2; + c2.u.ti2.element = choice_TESTImplicit3_ti2_i1; + c2.u.ti2.u.i1 = 5; + tests3[0].val = &c2; + + memset(&c3, 0, sizeof(c3)); + c3.element = choice_TESTImplicit4_ti2; + c3.u.ti2.element = choice_TESTChoice2_i1; + c3.u.ti2.u.i1 = 5; + tests4[0].val = &c3; + ret += generic_test(tests, sizeof(tests) / sizeof(*tests), sizeof(TESTImplicit), @@ -1102,6 +1177,26 @@ test_implicit (void) cmp_TESTImplicit2, NULL); + ret += generic_test(tests3, + sizeof(tests3) / sizeof(*tests3), + sizeof(TESTImplicit3), + (generic_encode)encode_TESTImplicit3, + (generic_length)length_TESTImplicit3, + (generic_decode)decode_TESTImplicit3, + (generic_free)free_TESTImplicit3, + cmp_TESTImplicit3, + NULL); + + ret += generic_test(tests4, + sizeof(tests4) / sizeof(*tests4), + sizeof(TESTImplicit4), + (generic_encode)encode_TESTImplicit4, + (generic_length)length_TESTImplicit4, + (generic_decode)decode_TESTImplicit4, + (generic_free)free_TESTImplicit4, + cmp_TESTImplicit4, + NULL); + return ret; } diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c index bfd49284c..1ddb07038 100644 --- a/lib/asn1/gen_template.c +++ b/lib/asn1/gen_template.c @@ -662,11 +662,20 @@ template_members(struct templatehead *temp, const char *basetype, const char *na const char *sename, *dupname; int subtype_is_struct = is_struct(t->subtype, isstruct); static unsigned long tag_counter = 0; - int tagimplicit = (t->tag.tagenv == TE_IMPLICIT); + int tagimplicit = 0; int prim = !(t->tag.tagclass != ASN1_C_UNIV && t->tag.tagenv == TE_EXPLICIT) && is_primitive_type(t->subtype); + if (t->tag.tagenv == TE_IMPLICIT) { + Type *t2 = t->subtype ? t->subtype : t->symbol->type; + + while (t2->type == TType && (t2->subtype || t2->symbol->type)) + t2 = t2->subtype ? t2->subtype : t2->symbol->type; + if (t2->type != TChoice) + tagimplicit = 1; + } + fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp"); if (subtype_is_struct) @@ -876,8 +885,14 @@ generate_template_type(const char *varname, tl = tlist_new(varname); - if (type->type == TTag) - implicit = (type->tag.tagenv == TE_IMPLICIT); + if (type->type == TTag && type->tag.tagenv == TE_IMPLICIT) { + Type *t = type->subtype ? type->subtype : type->symbol->type; + + while (t->type == TType && (t->subtype || t->symbol->type)) + t = t->subtype ? t->subtype : t->symbol->type; + if (t->type != TChoice) + implicit = (type->tag.tagenv == TE_IMPLICIT); + } template_members(&tl->template, basetype, name, type, optional, implicit, isstruct, need_offset); diff --git a/lib/asn1/rfc2459.asn1 b/lib/asn1/rfc2459.asn1 index 3ceff987c..4b493b018 100644 --- a/lib/asn1/rfc2459.asn1 +++ b/lib/asn1/rfc2459.asn1 @@ -1,5 +1,11 @@ -- $Id$ -- --- Definitions from rfc2459/rfc3280 +-- Definitions from RFCs 2459, 3280, 5280 +-- +-- Note that those RFCs come with *two* ASN.1 modules, one being a default- +-- EXPLICIT tagged module, and the other being default-IMPLICIT. Some types +-- are in one module, while others are in the other. Here the two modules +-- are merged into a single default-EXPLICIT tagged module, with IMPLICIT added +-- for all tags for types in the default-IMPLICIT module. RFC2459 DEFINITIONS ::= BEGIN @@ -320,8 +326,8 @@ KeyUsage ::= BIT STRING { -- private key usage period extension OID and syntax PrivateKeyUsagePeriod ::= SEQUENCE { - notBefore [0] GeneralizedTime OPTIONAL, - notAfter [1] GeneralizedTime OPTIONAL + notBefore [0] IMPLICIT GeneralizedTime OPTIONAL, + notAfter [1] IMPLICIT GeneralizedTime OPTIONAL -- either notBefore or notAfter MUST be present } diff --git a/lib/asn1/test.asn1 b/lib/asn1/test.asn1 index b43249ed7..1da1ed794 100644 --- a/lib/asn1/test.asn1 +++ b/lib/asn1/test.asn1 @@ -80,6 +80,16 @@ TESTImplicit2 ::= SEQUENCE { ti4[51] IMPLICIT TESTInteger OPTIONAL } +TESTImplicit3 ::= CHOICE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[5] IMPLICIT CHOICE { i1[1] INTEGER (-2147483648..2147483647) } +} + +TESTImplicit4 ::= CHOICE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[5] IMPLICIT TESTChoice2 +} + TESTAllocInner ::= SEQUENCE { ai[0] TESTInteger }