/* * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* $Id: parse.y 21597 2007-07-16 18:48:58Z lha $ */ %{ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "symbol.h" #include "lex.h" #include "gen_locl.h" #include "der.h" RCSID("$Id: parse.y 21597 2007-07-16 18:48:58Z lha $"); static Type *new_type (Typetype t); static struct constraint_spec *new_constraint_spec(enum ctype); static Type *new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype); void yyerror (const char *); static struct objid *new_objid(const char *label, int value); static void add_oid_to_tail(struct objid *, struct objid *); static void fix_labels(Symbol *s); struct string_list { char *string; struct string_list *next; }; %} %union { int constant; struct value *value; struct range *range; char *name; Type *type; Member *member; struct objid *objid; char *defval; struct string_list *sl; struct tagtype tag; struct memhead *members; struct constraint_spec *constraint_spec; } %token kw_ABSENT %token kw_ABSTRACT_SYNTAX %token kw_ALL %token kw_APPLICATION %token kw_AUTOMATIC %token kw_BEGIN %token kw_BIT %token kw_BMPString %token kw_BOOLEAN %token kw_BY %token kw_CHARACTER %token kw_CHOICE %token kw_CLASS %token kw_COMPONENT %token kw_COMPONENTS %token kw_CONSTRAINED %token kw_CONTAINING %token kw_DEFAULT %token kw_DEFINITIONS %token kw_EMBEDDED %token kw_ENCODED %token kw_END %token kw_ENUMERATED %token kw_EXCEPT %token kw_EXPLICIT %token kw_EXPORTS %token kw_EXTENSIBILITY %token kw_EXTERNAL %token kw_FALSE %token kw_FROM %token kw_GeneralString %token kw_GeneralizedTime %token kw_GraphicString %token kw_IA5String %token kw_IDENTIFIER %token kw_IMPLICIT %token kw_IMPLIED %token kw_IMPORTS %token kw_INCLUDES %token kw_INSTANCE %token kw_INTEGER %token kw_INTERSECTION %token kw_ISO646String %token kw_MAX %token kw_MIN %token kw_MINUS_INFINITY %token kw_NULL %token kw_NumericString %token kw_OBJECT %token kw_OCTET %token kw_OF %token kw_OPTIONAL %token kw_ObjectDescriptor %token kw_PATTERN %token kw_PDV %token kw_PLUS_INFINITY %token kw_PRESENT %token kw_PRIVATE %token kw_PrintableString %token kw_REAL %token kw_RELATIVE_OID %token kw_SEQUENCE %token kw_SET %token kw_SIZE %token kw_STRING %token kw_SYNTAX %token kw_T61String %token kw_TAGS %token kw_TRUE %token kw_TYPE_IDENTIFIER %token kw_TeletexString %token kw_UNION %token kw_UNIQUE %token kw_UNIVERSAL %token kw_UTCTime %token kw_UTF8String %token kw_UniversalString %token kw_VideotexString %token kw_VisibleString %token kw_WITH %token RANGE %token EEQUAL %token ELLIPSIS %token IDENTIFIER referencename %token STRING %token NUMBER %type SignedNumber %type Class tagenv %type Value %type BuiltinValue %type IntegerValue %type BooleanValue %type ObjectIdentifierValue %type CharacterStringValue %type NullValue %type DefinedValue %type ReferencedValue %type Valuereference %type Type %type BuiltinType %type BitStringType %type BooleanType %type ChoiceType %type ConstrainedType %type EnumeratedType %type IntegerType %type NullType %type OctetStringType %type SequenceType %type SequenceOfType %type SetType %type SetOfType %type TaggedType %type ReferencedType %type DefinedType %type UsefulType %type ObjectIdentifierType %type CharacterStringType %type RestrictedCharactedStringType %type Tag %type ComponentType %type NamedBit %type NamedNumber %type NamedType %type ComponentTypeList %type Enumerations %type NamedBitList %type NamedNumberList %type objid objid_list objid_element objid_opt %type range size %type referencenames %type Constraint %type ConstraintSpec %type GeneralConstraint %type ContentsConstraint %type UserDefinedConstraint %start ModuleDefinition %% ModuleDefinition: IDENTIFIER objid_opt kw_DEFINITIONS TagDefault ExtensionDefault EEQUAL kw_BEGIN ModuleBody kw_END { checkundefined(); } ; TagDefault : kw_EXPLICIT kw_TAGS | kw_IMPLICIT kw_TAGS { error_message("implicit tagging is not supported"); } | kw_AUTOMATIC kw_TAGS { error_message("automatic tagging is not supported"); } | /* empty */ ; ExtensionDefault: kw_EXTENSIBILITY kw_IMPLIED { error_message("no extensibility options supported"); } | /* empty */ ; ModuleBody : /* Exports */ Imports AssignmentList | /* empty */ ; Imports : kw_IMPORTS SymbolsImported ';' | /* empty */ ; SymbolsImported : SymbolsFromModuleList | /* empty */ ; SymbolsFromModuleList: SymbolsFromModule | SymbolsFromModuleList SymbolsFromModule ; SymbolsFromModule: referencenames kw_FROM IDENTIFIER objid_opt { struct string_list *sl; for(sl = $1; sl != NULL; sl = sl->next) { Symbol *s = addsym(sl->string); s->stype = Stype; } add_import($3); } ; AssignmentList : Assignment | Assignment AssignmentList ; Assignment : TypeAssignment | ValueAssignment ; referencenames : IDENTIFIER ',' referencenames { $$ = emalloc(sizeof(*$$)); $$->string = $1; $$->next = $3; } | IDENTIFIER { $$ = emalloc(sizeof(*$$)); $$->string = $1; $$->next = NULL; } ; TypeAssignment : IDENTIFIER EEQUAL Type { Symbol *s = addsym ($1); s->stype = Stype; s->type = $3; fix_labels(s); generate_type (s); } ; Type : BuiltinType | ReferencedType | ConstrainedType ; BuiltinType : BitStringType | BooleanType | CharacterStringType | ChoiceType | EnumeratedType | IntegerType | NullType | ObjectIdentifierType | OctetStringType | SequenceType | SequenceOfType | SetType | SetOfType | TaggedType ; BooleanType : kw_BOOLEAN { $$ = new_tag(ASN1_C_UNIV, UT_Boolean, TE_EXPLICIT, new_type(TBoolean)); } ; range : '(' Value RANGE Value ')' { if($2->type != integervalue) error_message("Non-integer used in first part of range"); if($2->type != integervalue) error_message("Non-integer in second part of range"); $$ = ecalloc(1, sizeof(*$$)); $$->min = $2->u.integervalue; $$->max = $4->u.integervalue; } | '(' Value RANGE kw_MAX ')' { if($2->type != integervalue) error_message("Non-integer in first part of range"); $$ = ecalloc(1, sizeof(*$$)); $$->min = $2->u.integervalue; $$->max = $2->u.integervalue - 1; } | '(' kw_MIN RANGE Value ')' { if($4->type != integervalue) error_message("Non-integer in second part of range"); $$ = ecalloc(1, sizeof(*$$)); $$->min = $4->u.integervalue + 2; $$->max = $4->u.integervalue; } | '(' Value ')' { if($2->type != integervalue) error_message("Non-integer used in limit"); $$ = ecalloc(1, sizeof(*$$)); $$->min = $2->u.integervalue; $$->max = $2->u.integervalue; } ; IntegerType : kw_INTEGER { $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, new_type(TInteger)); } | kw_INTEGER range { $$ = new_type(TInteger); $$->range = $2; $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$); } | kw_INTEGER '{' NamedNumberList '}' { $$ = new_type(TInteger); $$->members = $3; $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$); } ; NamedNumberList : NamedNumber { $$ = emalloc(sizeof(*$$)); ASN1_TAILQ_INIT($$); ASN1_TAILQ_INSERT_HEAD($$, $1, members); } | NamedNumberList ',' NamedNumber { ASN1_TAILQ_INSERT_TAIL($1, $3, members); $$ = $1; } | NamedNumberList ',' ELLIPSIS { $$ = $1; } /* XXX used for Enumerations */ ; NamedNumber : IDENTIFIER '(' SignedNumber ')' { $$ = emalloc(sizeof(*$$)); $$->name = $1; $$->gen_name = estrdup($1); output_name ($$->gen_name); $$->val = $3; $$->optional = 0; $$->ellipsis = 0; $$->type = NULL; } ; EnumeratedType : kw_ENUMERATED '{' Enumerations '}' { $$ = new_type(TInteger); $$->members = $3; $$ = new_tag(ASN1_C_UNIV, UT_Enumerated, TE_EXPLICIT, $$); } ; Enumerations : NamedNumberList /* XXX */ ; BitStringType : kw_BIT kw_STRING { $$ = new_type(TBitString); $$->members = emalloc(sizeof(*$$->members)); ASN1_TAILQ_INIT($$->members); $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); } | kw_BIT kw_STRING '{' NamedBitList '}' { $$ = new_type(TBitString); $$->members = $4; $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); } ; ObjectIdentifierType: kw_OBJECT kw_IDENTIFIER { $$ = new_tag(ASN1_C_UNIV, UT_OID, TE_EXPLICIT, new_type(TOID)); } ; OctetStringType : kw_OCTET kw_STRING size { Type *t = new_type(TOctetString); t->range = $3; $$ = new_tag(ASN1_C_UNIV, UT_OctetString, TE_EXPLICIT, t); } ; NullType : kw_NULL { $$ = new_tag(ASN1_C_UNIV, UT_Null, TE_EXPLICIT, new_type(TNull)); } ; size : { $$ = NULL; } | kw_SIZE range { $$ = $2; } ; SequenceType : kw_SEQUENCE '{' /* ComponentTypeLists */ ComponentTypeList '}' { $$ = new_type(TSequence); $$->members = $3; $$ = new_tag(ASN1_C_UNIV, UT_Sequence, TE_EXPLICIT, $$); } | kw_SEQUENCE '{' '}' { $$ = new_type(TSequence); $$->members = NULL; $$ = new_tag(ASN1_C_UNIV, UT_Sequence, TE_EXPLICIT, $$); } ; SequenceOfType : kw_SEQUENCE size kw_OF Type { $$ = new_type(TSequenceOf); $$->range = $2; $$->subtype = $4; $$ = new_tag(ASN1_C_UNIV, UT_Sequence, TE_EXPLICIT, $$); } ; SetType : kw_SET '{' /* ComponentTypeLists */ ComponentTypeList '}' { $$ = new_type(TSet); $$->members = $3; $$ = new_tag(ASN1_C_UNIV, UT_Set, TE_EXPLICIT, $$); } | kw_SET '{' '}' { $$ = new_type(TSet); $$->members = NULL; $$ = new_tag(ASN1_C_UNIV, UT_Set, TE_EXPLICIT, $$); } ; SetOfType : kw_SET kw_OF Type { $$ = new_type(TSetOf); $$->subtype = $3; $$ = new_tag(ASN1_C_UNIV, UT_Set, TE_EXPLICIT, $$); } ; ChoiceType : kw_CHOICE '{' /* AlternativeTypeLists */ ComponentTypeList '}' { $$ = new_type(TChoice); $$->members = $3; } ; ReferencedType : DefinedType | UsefulType ; DefinedType : IDENTIFIER { Symbol *s = addsym($1); $$ = new_type(TType); if(s->stype != Stype && s->stype != SUndefined) error_message ("%s is not a type\n", $1); else $$->symbol = s; } ; UsefulType : kw_GeneralizedTime { $$ = new_tag(ASN1_C_UNIV, UT_GeneralizedTime, TE_EXPLICIT, new_type(TGeneralizedTime)); } | kw_UTCTime { $$ = new_tag(ASN1_C_UNIV, UT_UTCTime, TE_EXPLICIT, new_type(TUTCTime)); } ; ConstrainedType : Type Constraint { /* if (Constraint.type == contentConstrant) { assert(Constraint.u.constraint.type == octetstring|bitstring-w/o-NamedBitList); // remember to check type reference too if (Constraint.u.constraint.type) { assert((Constraint.u.constraint.type.length % 8) == 0); } } if (Constraint.u.constraint.encoding) { type == der-oid|ber-oid } */ } ; Constraint : '(' ConstraintSpec ')' { $$ = $2; } ; ConstraintSpec : GeneralConstraint ; GeneralConstraint: ContentsConstraint | UserDefinedConstraint ; ContentsConstraint: kw_CONTAINING Type { $$ = new_constraint_spec(CT_CONTENTS); $$->u.content.type = $2; $$->u.content.encoding = NULL; } | kw_ENCODED kw_BY Value { if ($3->type != objectidentifiervalue) error_message("Non-OID used in ENCODED BY constraint"); $$ = new_constraint_spec(CT_CONTENTS); $$->u.content.type = NULL; $$->u.content.encoding = $3; } | kw_CONTAINING Type kw_ENCODED kw_BY Value { if ($5->type != objectidentifiervalue) error_message("Non-OID used in ENCODED BY constraint"); $$ = new_constraint_spec(CT_CONTENTS); $$->u.content.type = $2; $$->u.content.encoding = $5; } ; UserDefinedConstraint: kw_CONSTRAINED kw_BY '{' '}' { $$ = new_constraint_spec(CT_USER); } ; TaggedType : Tag tagenv Type { $$ = new_type(TTag); $$->tag = $1; $$->tag.tagenv = $2; if($3->type == TTag && $2 == TE_IMPLICIT) { $$->subtype = $3->subtype; free($3); } else $$->subtype = $3; } ; Tag : '[' Class NUMBER ']' { $$.tagclass = $2; $$.tagvalue = $3; $$.tagenv = TE_EXPLICIT; } ; Class : /* */ { $$ = ASN1_C_CONTEXT; } | kw_UNIVERSAL { $$ = ASN1_C_UNIV; } | kw_APPLICATION { $$ = ASN1_C_APPL; } | kw_PRIVATE { $$ = ASN1_C_PRIVATE; } ; tagenv : /* */ { $$ = TE_EXPLICIT; } | kw_EXPLICIT { $$ = TE_EXPLICIT; } | kw_IMPLICIT { $$ = TE_IMPLICIT; } ; ValueAssignment : IDENTIFIER Type EEQUAL Value { Symbol *s; s = addsym ($1); s->stype = SValue; s->value = $4; generate_constant (s); } ; CharacterStringType: RestrictedCharactedStringType ; RestrictedCharactedStringType: kw_GeneralString { $$ = new_tag(ASN1_C_UNIV, UT_GeneralString, TE_EXPLICIT, new_type(TGeneralString)); } | kw_UTF8String { $$ = new_tag(ASN1_C_UNIV, UT_UTF8String, TE_EXPLICIT, new_type(TUTF8String)); } | kw_PrintableString { $$ = new_tag(ASN1_C_UNIV, UT_PrintableString, TE_EXPLICIT, new_type(TPrintableString)); } | kw_VisibleString { $$ = new_tag(ASN1_C_UNIV, UT_VisibleString, TE_EXPLICIT, new_type(TVisibleString)); } | kw_IA5String { $$ = new_tag(ASN1_C_UNIV, UT_IA5String, TE_EXPLICIT, new_type(TIA5String)); } | kw_BMPString { $$ = new_tag(ASN1_C_UNIV, UT_BMPString, TE_EXPLICIT, new_type(TBMPString)); } | kw_UniversalString { $$ = new_tag(ASN1_C_UNIV, UT_UniversalString, TE_EXPLICIT, new_type(TUniversalString)); } ; ComponentTypeList: ComponentType { $$ = emalloc(sizeof(*$$)); ASN1_TAILQ_INIT($$); ASN1_TAILQ_INSERT_HEAD($$, $1, members); } | ComponentTypeList ',' ComponentType { ASN1_TAILQ_INSERT_TAIL($1, $3, members); $$ = $1; } | ComponentTypeList ',' ELLIPSIS { struct member *m = ecalloc(1, sizeof(*m)); m->name = estrdup("..."); m->gen_name = estrdup("asn1_ellipsis"); m->ellipsis = 1; ASN1_TAILQ_INSERT_TAIL($1, m, members); $$ = $1; } ; NamedType : IDENTIFIER Type { $$ = emalloc(sizeof(*$$)); $$->name = $1; $$->gen_name = estrdup($1); output_name ($$->gen_name); $$->type = $2; $$->ellipsis = 0; } ; ComponentType : NamedType { $$ = $1; $$->optional = 0; $$->defval = NULL; } | NamedType kw_OPTIONAL { $$ = $1; $$->optional = 1; $$->defval = NULL; } | NamedType kw_DEFAULT Value { $$ = $1; $$->optional = 0; $$->defval = $3; } ; NamedBitList : NamedBit { $$ = emalloc(sizeof(*$$)); ASN1_TAILQ_INIT($$); ASN1_TAILQ_INSERT_HEAD($$, $1, members); } | NamedBitList ',' NamedBit { ASN1_TAILQ_INSERT_TAIL($1, $3, members); $$ = $1; } ; NamedBit : IDENTIFIER '(' NUMBER ')' { $$ = emalloc(sizeof(*$$)); $$->name = $1; $$->gen_name = estrdup($1); output_name ($$->gen_name); $$->val = $3; $$->optional = 0; $$->ellipsis = 0; $$->type = NULL; } ; objid_opt : objid | /* empty */ { $$ = NULL; } ; objid : '{' objid_list '}' { $$ = $2; } ; objid_list : /* empty */ { $$ = NULL; } | objid_element objid_list { if ($2) { $$ = $2; add_oid_to_tail($2, $1); } else { $$ = $1; } } ; objid_element : IDENTIFIER '(' NUMBER ')' { $$ = new_objid($1, $3); } | IDENTIFIER { Symbol *s = addsym($1); if(s->stype != SValue || s->value->type != objectidentifiervalue) { error_message("%s is not an object identifier\n", s->name); exit(1); } $$ = s->value->u.objectidentifiervalue; } | NUMBER { $$ = new_objid(NULL, $1); } ; Value : BuiltinValue | ReferencedValue ; BuiltinValue : BooleanValue | CharacterStringValue | IntegerValue | ObjectIdentifierValue | NullValue ; ReferencedValue : DefinedValue ; DefinedValue : Valuereference ; Valuereference : IDENTIFIER { Symbol *s = addsym($1); if(s->stype != SValue) error_message ("%s is not a value\n", s->name); else $$ = s->value; } ; CharacterStringValue: STRING { $$ = emalloc(sizeof(*$$)); $$->type = stringvalue; $$->u.stringvalue = $1; } ; BooleanValue : kw_TRUE { $$ = emalloc(sizeof(*$$)); $$->type = booleanvalue; $$->u.booleanvalue = 0; } | kw_FALSE { $$ = emalloc(sizeof(*$$)); $$->type = booleanvalue; $$->u.booleanvalue = 0; } ; IntegerValue : SignedNumber { $$ = emalloc(sizeof(*$$)); $$->type = integervalue; $$->u.integervalue = $1; } ; SignedNumber : NUMBER ; NullValue : kw_NULL { } ; ObjectIdentifierValue: objid { $$ = emalloc(sizeof(*$$)); $$->type = objectidentifiervalue; $$->u.objectidentifiervalue = $1; } ; %% void yyerror (const char *s) { error_message ("%s\n", s); } static Type * new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype) { Type *t; if(oldtype->type == TTag && oldtype->tag.tagenv == TE_IMPLICIT) { t = oldtype; oldtype = oldtype->subtype; /* XXX */ } else t = new_type (TTag); t->tag.tagclass = tagclass; t->tag.tagvalue = tagvalue; t->tag.tagenv = tagenv; t->subtype = oldtype; return t; } static struct objid * new_objid(const char *label, int value) { struct objid *s; s = emalloc(sizeof(*s)); s->label = label; s->value = value; s->next = NULL; return s; } static void add_oid_to_tail(struct objid *head, struct objid *tail) { struct objid *o; o = head; while (o->next) o = o->next; o->next = tail; } static Type * new_type (Typetype tt) { Type *t = ecalloc(1, sizeof(*t)); t->type = tt; return t; } static struct constraint_spec * new_constraint_spec(enum ctype ct) { struct constraint_spec *c = ecalloc(1, sizeof(*c)); c->ctype = ct; return c; } static void fix_labels2(Type *t, const char *prefix); static void fix_labels1(struct memhead *members, const char *prefix) { Member *m; if(members == NULL) return; ASN1_TAILQ_FOREACH(m, members, members) { asprintf(&m->label, "%s_%s", prefix, m->gen_name); if (m->label == NULL) errx(1, "malloc"); if(m->type != NULL) fix_labels2(m->type, m->label); } } static void fix_labels2(Type *t, const char *prefix) { for(; t; t = t->subtype) fix_labels1(t->members, prefix); } static void fix_labels(Symbol *s) { char *p; asprintf(&p, "choice_%s", s->gen_name); if (p == NULL) errx(1, "malloc"); fix_labels2(s->type, p); free(p); }