diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /third_party/heimdal/lib/asn1/asn1parse.y | |
parent | Initial commit. (diff) | |
download | samba-4f5791ebd03eaec1c7da0865a383175b05102712.tar.xz samba-4f5791ebd03eaec1c7da0865a383175b05102712.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/lib/asn1/asn1parse.y')
-rw-r--r-- | third_party/heimdal/lib/asn1/asn1parse.y | 2034 |
1 files changed, 2034 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/asn1/asn1parse.y b/third_party/heimdal/lib/asn1/asn1parse.y new file mode 100644 index 0000000..f6f6ec0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1parse.y @@ -0,0 +1,2034 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. 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$ */ + +%{ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include "symbol.h" +#include "lex.h" +#include "gen_locl.h" +#include "der.h" + +static Type *new_type (Typetype t); +/*static IOSClass *new_class(struct fieldhead *);*/ +/*static IOSObject *new_object(struct objfieldhead *);*/ +/*IOSObjectSet *new_object_set(struct objectshead *);*/ +static struct objectshead *add_object_set_spec(struct objectshead *, IOSObject *); +static ObjectField *new_field_setting(char *, Type *, struct value *); +static struct objfieldhead *add_field_setting(struct objfieldhead *, ObjectField *); +static struct fieldhead *add_field_spec(struct fieldhead *, Field *); +static Field *new_type_field(char *, int, Type *); +static Field *new_fixed_type_value_field(char *, Type *, int, int, struct value *); +static Type *parametrize_type(Type *, IOSClass *); +static Type *type_from_class_field(IOSClass *, const char *); +static void validate_object_set(IOSObjectSet *); +/*static Type *type_from_object(const char *, const char *);*/ +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 *); +#define yyerror yyerror +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; +}; + +static int default_tag_env = TE_EXPLICIT; +static unsigned long idcounter; + +/* Declarations for Bison */ +#define YYMALLOC malloc +#define YYFREE free + +%} + +%union { + int64_t constant; + struct value *value; + struct range *range; + char *name; + Type *type; + IOSClass *class; + IOSObjectSet *objectset; + IOSObject *object; + Field *field; + ObjectField *objfield; + Member *member; + IOSClass *formalparam; + struct objid *objid; + char *defval; + struct string_list *sl; + struct tagtype tag; + struct memhead *members; + struct fieldhead *fields; + struct objectshead *objects; + struct objfieldhead *objfields; + 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 <name> TYPE_IDENTIFIER referencename +%token <name> CLASS_IDENTIFIER +%token <name> VALUE_IDENTIFIER +%token <name> STRING + +%token <constant> NUMBER +%type <constant> SignedNumber +%type <constant> Class tagenv +%type <constant> DummyReference + +%type <name> Identifier + +/* + * The NULL keyword being both a value and a type causes a reduce/reduce + * conflict in the FieldSetting production since its alternatives are + * + * '&' Identifier Type + * + * and + * + * '&' Identifier Value + * + * and NULL is both a type and a value. + * + * For now we work around this by having a ValueExNull production that excludes + * the NULL value. To really get past this will require unifying the type and + * value types (e.g., via type punning). + */ +%type <value> Value ValueExNull +%type <value> BuiltinValue BuiltinValueExNull +%type <value> IntegerValue +%type <value> BooleanValue +%type <value> ObjectIdentifierValue +%type <value> CharacterStringValue +%type <value> NullValue +%type <value> DefinedValue +%type <value> ReferencedValue +%type <value> Valuereference + +%type <class> DefinedObjectClass ParamGovernor +%type <class> ObjectClassDefn +%type <class> Parameter + +%type <type> Type +%type <type> BuiltinType +%type <type> BitStringType +%type <type> BooleanType +%type <type> ChoiceType +%type <type> ConstrainedType +%type <type> UnconstrainedType +%type <type> EnumeratedType +%type <type> IntegerType +%type <type> NullType +%type <type> OctetStringType +%type <type> SequenceType +%type <type> SequenceOfType +%type <type> SetType +%type <type> SetOfType +%type <type> TaggedType +%type <type> ReferencedType +%type <type> DefinedType +%type <type> UsefulType +%type <type> ObjectIdentifierType +%type <type> CharacterStringType +%type <type> RestrictedCharactedStringType +%type <type> ObjectClassFieldType +%type <type> ParameterizedType +/*%type <type> TypeFromObject*/ + +%type <objectset> ObjectSet DefinedObjectSet +%type <objectset> ActualParameter +%type <object> Object DefinedObject ObjectDefn +%type <objfield> FieldSetting + +%type <tag> Tag + +%type <field> FieldSpec TypeFieldSpec FixedTypeValueFieldSpec +%type <fields> FieldSpecList +%type <member> ComponentType +%type <member> NamedBit +%type <member> NamedNumber +%type <member> NamedType +%type <members> ComponentTypeList +%type <members> Enumerations +%type <members> NamedBitList +%type <members> NamedNumberList +%type <objects> ObjectSetSpec +%type <objfields> FieldSettings + +%type <objid> objid objid_list objid_element objid_opt +%type <range> range size + +%type <sl> referencenames + +%type <constraint_spec> Constraint +%type <constraint_spec> ConstraintSpec +%type <constraint_spec> SubtypeConstraint +%type <constraint_spec> GeneralConstraint +%type <constraint_spec> ContentsConstraint +%type <constraint_spec> UserDefinedConstraint +%type <constraint_spec> SimpleTableConstraint TableConstraint +%type <constraint_spec> ComponentRelationConstraint + + +%start ModuleDefinition + +%% + +/* + * We have sinned by allowing types to have names that start with lower-case, + * and values that have names that start with upper-case. + * + * UPDATE: We sin no more. However, parts of this block comment are still + * relevant. + * + * That worked when we only supported basic X.680 because the rules for + * TypeAssignment and ValueAssignment are clearly unambiguous in spite of the + * case issue. + * + * We now pay the price because X.681 adds productions where the only thing we + * have to help us distinguish certain rules is the form of an identifier: the + * case of its first letter. + * + * We have cleansed our sin by not allowing wrong-case identifiers any more. + * + * Some historical instances of this sin in-tree: + * + * - DOMAIN-X500-COMPRESS (value (enum) but name starts with upper-case) + * - krb5int32 (type but name starts with lower-case) + * - krb5uint32 (type but name starts with lower-case) + * - hdb_keyset (type but name starts with lower-case) + * - hdb_entry (type but name starts with lower-case) + * - hdb_entry_alias (type but name starts with lower-case) + * - HDB_DB_FORMAT INTEGER (value (int) but name starts with upper-case) + * + * We have fixed all of these and others, in some cases leaving behind aliases + * in header files as needed. + * + * We have one shift/reduce conflict (shift ObjectClassAssignment, reduce + * TypeAssignment) and one reduce/reduce conflict (ObjectAssignment vs + * ValueAssignment) that we avoid by requiring CLASS names to start with an + * underscore. + * + * In the FieldSetting rule, also, we get a reduce/reduce conflict if we use + * `Identifier' instead of `TYPE_IDENTIFIER' for type field settings and + * `VALUE_IDENTIFIER' for value field settings, and then we can't make + * progress. + * + * Looking forward, we may not (will not) be able to distinguish ValueSet and + * ObjectSet field settings from each other either, and we may not (will not) + * be able distinguish Object and Value field settings from each other as well. + * To deal with those we will have to run-time type-tag and type-pun the C + * structures for valueset/objectset and value/object, and have one rule for + * each of those that inspects the type of the item to decide what kind of + * setting it is. + * + * Sadly, the extended syntax for ASN.1 (x.680 + x.681/2/3) appears to have + * ambiguities that cannot be resolved with bison/yacc. + */ +Identifier : TYPE_IDENTIFIER { $$ = $1; } + | VALUE_IDENTIFIER { $$ = $1; }; + +ModuleDefinition: Identifier objid_opt kw_DEFINITIONS TagDefault ExtensionDefault + EEQUAL kw_BEGIN ModuleBody kw_END + { + struct objid **o = objid2list($2); + size_t i; + + fprintf(jsonfile, + "{\"module\":\"%s\",\"tagging\":\"%s\",\"objid\":[", $1, + default_tag_env == TE_EXPLICIT ? "explicit" : "implicit"); + + for (i = 0; o && o[i]; i++) { + fprintf(jsonfile, "%s{\"value\":%d", i ? "," : "", o[i]->value); + if (o[i]->label) + fprintf(jsonfile, ",\"label\":\"%s\"", o[i]->label); + fprintf(jsonfile, "}"); + } + fprintf(jsonfile, "]}\n"); + free(o); + } + ; + +TagDefault : kw_EXPLICIT kw_TAGS + { default_tag_env = TE_EXPLICIT; } + | kw_IMPLICIT kw_TAGS + { default_tag_env = TE_IMPLICIT; } + | kw_AUTOMATIC kw_TAGS + { lex_error_message("automatic tagging is not supported"); } + | /* empty */ + ; + +ExtensionDefault: kw_EXTENSIBILITY kw_IMPLIED + { lex_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 + { + /* + * FIXME We really could use knowing what kind of thing the + * identifier identifies -- a type, a value, what? + * + * Our sin of allowing type names to start with lower-case + * and values with upper-case means we can't tell. So we + * assume it's types only, but that means we can't import + * OID values, but we really want to! + * + * One thing we could do is not force `s->stype = Stype' + * here, instead set it to a new `Sunknown' value so that + * the first place that refers to this symbol with enough + * context to imply a symbol type can set it. + */ + struct string_list *sl; + for(sl = $1; sl != NULL; sl = sl->next) { + Symbol *s = addsym(sl->string); + s->stype = Stype; + gen_template_import(s); + } + add_import($3); + } + ; + +Exports : kw_EXPORTS referencenames ';' + { + struct string_list *sl; + for(sl = $2; sl != NULL; sl = sl->next) + add_export(sl->string); + } + | kw_EXPORTS kw_ALL + | /* empty */ + ; + +AssignmentList : Assignment + | Assignment AssignmentList + ; + +Assignment : TypeAssignment + | ValueAssignment + | ParameterizedTypeAssignment + | ObjectClassAssignment + | ObjectAssignment + | ObjectSetAssignment + /* | ParameterizedAssignment // from X.683 */ + ; + +referencenames : Identifier ',' referencenames + { + $$ = emalloc(sizeof(*$$)); + $$->string = $1; + $$->next = $3; + } + | Identifier + { + $$ = emalloc(sizeof(*$$)); + $$->string = $1; + $$->next = NULL; + } + ; + +DefinedObjectClass + : CLASS_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sclass) + lex_error_message ("%s is not a class\n", $1); + $$ = s->iosclass; + }; + +ObjectClassAssignment + : CLASS_IDENTIFIER EEQUAL ObjectClassDefn + { + Symbol *s = addsym($1); + s->stype = Sclass; + s->iosclass = $3; + s->iosclass->symbol = s; + fix_labels(s); + } + | CLASS_IDENTIFIER EEQUAL DefinedObjectClass + { + Symbol *s = addsym($1); + s->stype = Sclass; + s->iosclass = $3; + } + /* | ParameterizedObjectClass */ + ; + +ObjectClassDefn : kw_CLASS '{' FieldSpecList '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->fields = $3; + $$->id = idcounter++; + }; + +ObjectAssignment: VALUE_IDENTIFIER DefinedObjectClass EEQUAL Object + { + Symbol *s = addsym($1); + s->stype = Sobj; + s->object = $4; + s->object->iosclass = $2; + if (!s->object->symbol) + s->object->symbol = s; + fix_labels(s); + } + ; + +ObjectSetAssignment + : TYPE_IDENTIFIER DefinedObjectClass EEQUAL ObjectSet + { + Symbol *s = addsym($1); + s->stype = Sobjset; + s->iosclass = $2; + s->objectset = $4; + s->objectset->symbol = s->objectset->symbol ? s->objectset->symbol : s; + s->objectset->iosclass = $2; + validate_object_set($4); + generate_template_objectset_forwards(s); + } + ; + +ObjectSet : '{' ObjectSetSpec '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->objects = $2; + $$->id = idcounter++; + } + ; + +ObjectSetSpec : DefinedObject + { $$ = add_object_set_spec(NULL, $1); } + | ObjectSetSpec '|' DefinedObject + { $$ = add_object_set_spec($1, $3); } + ; + +Object : DefinedObject + | ObjectDefn + /* | ObjectFromObject */ + /* | ParameterizedObject */ + ; + +DefinedObject : VALUE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sobj) + lex_error_message ("%s is not an object\n", $1); + $$ = s->object; + } + ; + +DefinedObjectSet: TYPE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sobjset && s->stype != SUndefined) + lex_error_message ("%s is not an object set\n", $1); + $$ = s->objectset; + } + ; + + +ObjectDefn : '{' FieldSettings '}' /* DefaultSyntax */ + { + $$ = ecalloc(1, sizeof(*$$)); + $$->objfields = $2; + $$->id = idcounter++; + } + /* | DefinedSyntax */ + ; + +FieldSettings : FieldSetting + { + $$ = add_field_setting(NULL, $1); + } + | FieldSettings ',' FieldSetting + { + $$ = add_field_setting($1, $3); + } + ; + +/* See note on `Identifier' */ +FieldSetting : '&' Identifier Type + { $$ = new_field_setting($2, $3, NULL); } + | '&' Identifier ValueExNull + { $$ = new_field_setting($2, NULL, $3); } + /* | '&' TYPE_IDENTIFIER ValueSet */ + /* | '&' VALUE_IDENTIFIER Object */ + /* | '&' TYPE_IDENTIFIER ObjectSet */ + ; + +/* Fields of a class */ +FieldSpecList : FieldSpec + { $$ = add_field_spec(NULL, $1); } + | FieldSpecList ',' FieldSpec + { $$ = add_field_spec($1, $3); }; + +/* + * Fields of a CLASS + * + * There are seven kinds of class/object fields: + * + * - type fields, + * - fixed-type value fields, + * - fixed-type value set fields, + * - variable-type value fields + * - variable-type value set fields + * - object fields + * - object set fields + * + * We care only to support the bare minimum to treat open types as a CHOICE of + * sorts and automatically encode/decode values in open types. That's: type + * fields and fixed-type value fields. + */ +FieldSpec : TypeFieldSpec + | FixedTypeValueFieldSpec + /* | VariableTypeValueFieldSpec */ + /* | VariableTypeValueSetFieldSpec */ + /* | FixedTypeValueSetFieldSpec */ + /* | ObjectFieldSpec */ + /* | ObjectSetFieldSpec */ + ; +TypeFieldSpec : '&' Identifier + { $$ = new_type_field($2, 0, NULL); } + | '&' Identifier kw_OPTIONAL + { $$ = new_type_field($2, 1, NULL); } + | '&' Identifier kw_DEFAULT Type + { $$ = new_type_field($2, 1, $4); } + ; + +FixedTypeValueFieldSpec + : '&' Identifier Type + { $$ = new_fixed_type_value_field($2, $3, 0, 0, NULL); } + | '&' Identifier Type kw_UNIQUE + { $$ = new_fixed_type_value_field($2, $3, 1, 0, NULL); } + | '&' Identifier Type kw_UNIQUE kw_OPTIONAL + { $$ = new_fixed_type_value_field($2, $3, 1, 1, NULL); } + | '&' Identifier Type kw_UNIQUE kw_DEFAULT Value + { $$ = new_fixed_type_value_field($2, $3, 1, 0, $6); } + | '&' Identifier Type kw_OPTIONAL + { $$ = new_fixed_type_value_field($2, $3, 0, 1, NULL); } + | '&' Identifier Type kw_DEFAULT Value + { $$ = new_fixed_type_value_field($2, $3, 0, 0, $5); }; + +/* + * Now we need a bit of X.683, just enough to parse PKIX. + * + * E.g., we need to parse this sort of type definition, which isn't quite the + * final type definition because the ExtensionSet will be provided later. + * + *-- <- ObjectClassDefn -> + * EXTENSION ::= CLASS { + * &id OBJECT IDENTIFIER UNIQUE, + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- FixedTypeValueFieldSpec + * + * &ExtnType, + * -- ^^^^^^^^^ + * -- TypeFieldSpec + * + * &Critical BOOLEAN DEFAULT {TRUE | FALSE } + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- FixedTypeValueFieldSpec + * } WITH SYNTAX { + * SYNTAX &ExtnType IDENTIFIED BY &id + * [CRITICALITY &Critical] + * } + * + *-- <--------- ParameterizedTypeAssignment --------> + * -- NOTE: The name of this type has to be Extension, really. + * -- But the name of the Extension type with the actual + * -- parameter provided also has to be Extension. + * -- We could disallow that and require that the various + * -- Extension types all have different names, then we'd + * -- let the one with the actual parameter in PKIX be the + * -- one named Extension. Or we could find a way to let + * -- them all share one symbol name, or at least two: + * -- the one with the formal parameter, and just one with + * -- an actual parameter. + * -- + * -- Also, IMPORTing types that have formal parameters is + * -- almost certainly going to require parsing the IMPORTed + * -- module. Until we do that, users will be able to work + * -- around that by just copying CLASSes and pameterized + * -- type definitions around. But when we do start parsing + * -- IMPORTed modules we might need to do something about + * -- many types possibly having the same names, though we + * -- might do nothing and simply say "don't do that!". + * Extension{EXTENSION:ExtensionSet} ::= SEQUENCE { + * -- ^^^^^^^^^^^^ + * -- is a DummyReference, which is a Reference, basically + * -- it is an object set variable which will have an object + * -- set value supplied where constrained types are defined + * -- from this one, possibly anonymous types where + * -- SEQUENCE/SET members of this type are defined. + * -- ^^^^^^^^^ + * -- is a ParamGovernor, really, just Governor, either a Type or + * -- DefinedObjectClass (we only need DefinedObjectClass) + * -- ^^^^^^^^^^^^^^^^^^^^^^ + * -- is a Parameter + * -- ^^^^^^^^^^^^^^^^^^^^^^^^ + * -- is a ParameterList (we need only support one param though) + * extnID EXTENSION.&id({ExtensionSet}), + * -- ^^^^^^^^^^^^^^^^ + * -- simple table constraint limiting id to OIDs + * -- from ExtensionSet + * -- ^^^^^^^^^^^^^ + * -- a reference to the id field of the EXTENSION CLASS + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING (CONTAINING + * -- ObjectClassFieldType + * -- vvvvvvvvvvvvvvvvvvv + * EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + * -- ^^^^^^^^^ + * -- AtNotation + * -- ^^^^^^^^^^^^^^ + * -- DefinedObjectSet + * -- ^^^^^^^^^^^^^^^^^^^^^^^^ + * -- ComponentRelationConstraint + * -- says that extnValue will contain + * -- a value of a type identified by + * -- the OID in extnID in the object + * -- set ExtensionSet (which is a set + * -- of {OID, type} objects) + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- ConstraintSpec + * -- ^^^^^^^^^^^^^^^^^^^ + * -- another type ref + * } + * + * Then later we'll see (ParameterizedType, a part of DefinedType): + * + * TBSCertificate ::= SEQUENCE { + * ... + * -- Here is where the object set is linked into the + * -- whole thing, making *magic* possible. This is + * -- where the real Extensions type is defined. Sadly + * -- this might mean we can't have a C type named + * -- Extensions. Hmmm. We might need an ASN.1 + * -- extension that lets use do this: + * -- + * -- Extension ::= Extension{{CertExtensions}} + * -- + * -- or + * -- + * -- Extension ::= ParameterizedExtension{{CertExtensions}} + * -- + * -- and then rename the Extension type above to this. + * -- Then we can define Extensions as a SEQUENCE OF + * -- that. + * -- + * -- <- ParameterizedType -> + * extensions [3] Extensions{{CertExtensions}} OPTIONAL + * -- ^^^^^^^^^^^^^^ + * -- ObjectSetSpec + * -- ^^^^^^^^^^^^^^^^ + * -- ObjectSet + * -- ^^^^^^^^^^^^^^^^^^ + * -- ActualParameterList + * -- ^^^^^^^^^^ + * -- Type + * } + * + * Then: + * + * -- Object set, limits what Extensions can be in TBSCertificate. + *-- <- ObjectSetAssignment -> + * CertExtensions EXTENSION ::= { + * -- ^^^^^^^^^ + * -- DefinedObjectClass + *-- ^^^^^^^^^^^^^^ + *-- objectsetreference, for us, IDENTIFIER + * ext-AuthorityKeyIdentifier | ext-SubjectKeyIdentifier | ... + * } + * + * and: + * + * -- ObjectAssignment (with defined syntax, which we're not going to support): + * -- + * -- Defines one particular object in the CertExtensions object set. + * -- We don't need th SYNTAX bits though -- ETOOMUCHWORK. + * -- This says that the OID id-ce-authorityKeyIdentifier means the extnValue + * -- is a DER-encoded AuthorityKeyIdentifier. + * ext-AuthorityKeyIdentifier EXTENSION ::= { SYNTAX + * AuthorityKeyIdentifier IDENTIFIED BY + * id-ce-authorityKeyIdentifier } + * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + * + * -- ObjectAssignment (with default syntax): + * ext-AuthorityKeyIdentifier EXTENSION ::= { + * -- fields don't have to be in order since we have the field names + * &extnId id-ce-authorityKeyIdentifier, + * &extnValue AuthorityKeyIdentifier + * } + * + * -- Plain old type def using only X.680 + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + * + * In terms of compilation, we'll want to support only the template backend, + * though we'll generate the same C types for both, the template backend and + * the codegen backend. + * + * The generators should see a type for Extension that includes a) the + * parametrization (relating members in the SEQUENCE to fields in the CLASS), + * and b) the object set CertExtensions for the _same_ class. + * + * - The C types for ASN.1 parametrized types with object set parameters + * should be laid out just as before, but with additional fields: + * + * typedef struct Extension { + * heim_oid extnID; + * int *critical; + * heim_octet_string extnValue; + * // NEW FIELDS BELOW + * enum { + * opentypechoice_unknown_Extension = 0 + * opentypechoice_Extension_id_ce_authorityKeyIdentifier, + * ... + * } _element; + * union { + * // er, what should this be named?! we have no name information + * // and naming it after its object value name is probably not a good + * // idea or not easy. We do have the OID value and possible name + * // though, so we should use that: + * AuthorityKeyIdentifier id_ce_authorityKeyIdentifier; + * ... + * } _u; + * } Extension; + * + * - The template for this should consist of new struct asn1_template entries + * following the ones for the normal fields of Extension. The first of these + * should have an OP that indicates that the following N entries correspond + * to the object set that specifies this open type, then the following N + * entries should each point to an object in the object set. Or maybe the + * object set should be a separate template -- either way. We'll also want a + * flag to indicate whether the object set is sorted (none of the type IDs + * are IMPORTed) or not (some of the type IDs are IMPORTed) so we can binary + * search the object set at encode/decode time. + * + * Hmm, we can assume the object sets are already sorted when there's + * IMPORTed IDs -- the author can do it. Yes, they're sets, but lexically + * they must be in some order. + * + * I like that, actually, requiring that the module author manually sort the + * object sets, at least when they refer to type IDs that are IMPORTed. Or + * maybe forbid object sets that use IMPORTed type IDs -- the module author + * can always copy their definitions anyways. + */ + +TypeAssignment : Identifier EEQUAL Type + { + Symbol *s = addsym($1); + s->stype = Stype; + s->type = $3; + fix_labels(s); + + /* + * Hack: make sure that non-anonymous enumeration types get + * a symbol tacked on so we can generate a template for + * their members for value printing. + */ + if (s->type->type == TTag && $3->symbol == NULL && + $3->subtype != NULL && $3->subtype->type == TInteger && + $3->subtype->symbol == NULL) { + $3->subtype->symbol = s; + } + if (original_order) + generate_type(s); + else + generate_type_header_forwards(s); + } + ; + +ParameterizedTypeAssignment + /* For now we'll only support one parameter -- enough for PKIX */ + : Identifier '{' Parameter '}' EEQUAL Type + { + char *pname = NULL; + Symbol *s; + + if (asprintf(&pname, "%s{%s:x}", $1, $3->symbol->name) == -1 || + pname == NULL) + err(1, "Out of memory"); + s = addsym(pname); + free($1); + s->stype = Sparamtype; + s->type = parametrize_type($6, $3); + s->type->symbol = s; + fix_labels(s); + } + ; + +/* + * We're not going to support governor variables for now. We don't need to. + * + * Also, we're not going to support more than one formal parameter. + * Correspondingly we'll only support a single actual parameter (the count of + * formal and actual parameters has to match, naturally). + */ + +Parameter : ParamGovernor ':' DummyReference + { $$ = $1; }; + /* | DummyReference */ + ; + +DummyReference : TYPE_IDENTIFIER { $$ = idcounter++; }; + +ParamGovernor : DefinedObjectClass + { $$ = $1; } + /* | DummyGovernor */ + /* | Type */ + ; + +UnconstrainedType : BitStringType + | BooleanType + | CharacterStringType + | ChoiceType + | EnumeratedType + | IntegerType + | NullType + | ObjectIdentifierType + | OctetStringType + | SequenceType + | SetType + | ObjectClassFieldType; /* X.681 */ + +Type : BuiltinType | ReferencedType | ConstrainedType ; + +BuiltinType : BitStringType + | BooleanType + | CharacterStringType + | ChoiceType + | EnumeratedType + | IntegerType + | NullType + | ObjectIdentifierType + | OctetStringType + | SequenceType + | SequenceOfType + | SetType + | SetOfType + | TaggedType + | ObjectClassFieldType /* X.681 */ + /* | InstanceOfType // X.681 */ + ; + +ObjectClassFieldType + : DefinedObjectClass '.' '&' Identifier + { $$ = type_from_class_field($1, $4); }; + +BooleanType : kw_BOOLEAN + { + $$ = new_tag(ASN1_C_UNIV, UT_Boolean, + TE_EXPLICIT, new_type(TBoolean)); + } + ; + + /* + * The spec says the values in a ValueRange are Values, but a) all + * the various value ranges do not involve OBJECT IDENTIFIER, b) + * we only support integer value ranges at this time (as opposed + * to, e.g., time ranges, and we don't even support time values at + * this time), c) allowing OBJECT IDENTIFIER here causes a + * shift-reduce conflict, so we limit ourselves to integer values + * in ranges. We could always define IntegerValueRange, + * TimeValueRange, etc. when we add support for more value types. + */ +range : IntegerValue RANGE IntegerValue + { + if($1->type != integervalue) + lex_error_message("Non-integer used in first part of range"); + if($1->type != integervalue) + lex_error_message("Non-integer in second part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = $3->u.integervalue; + } + | IntegerValue RANGE kw_MAX + { + if($1->type != integervalue) + lex_error_message("Non-integer in first part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = INT_MAX; + } + | kw_MIN RANGE IntegerValue + { + if($3->type != integervalue) + lex_error_message("Non-integer in second part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = INT_MIN; + $$->max = $3->u.integervalue; + } + | IntegerValue + { + if($1->type != integervalue) + lex_error_message("Non-integer used in limit"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = $1->u.integervalue; + } + ; + + +IntegerType : kw_INTEGER + { + $$ = new_tag(ASN1_C_UNIV, UT_Integer, + TE_EXPLICIT, new_type(TInteger)); + } + | kw_INTEGER '{' NamedNumberList '}' + { + $$ = new_type(TInteger); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$); + } + ; + +NamedNumberList : NamedNumber + { + $$ = emalloc(sizeof(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | NamedNumberList ',' NamedNumber + { + HEIM_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; + } + | Identifier '(' DefinedValue ')' + { + if ($3->type != integervalue) + lex_error_message("Named number %s not a numeric value", + $3->s->name); + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->val = $3->u.integervalue; + $$->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)); + HEIM_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; + if (t->range) { + if (t->range->min < 0) + lex_error_message("can't use a negative SIZE range " + "length for OCTET STRING"); + } + $$ = 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 ')' + { $$ = $3; } + ; + + +SequenceType : kw_SEQUENCE '{' /* ComponentTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TSequence); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + | kw_SEQUENCE '{' '}' + { + $$ = new_type(TSequence); + $$->members = NULL; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + ; + +SequenceOfType : kw_SEQUENCE size kw_OF Type + { + $$ = new_type(TSequenceOf); + $$->range = $2; + if ($$->range) { + if ($$->range->min < 0) + lex_error_message("can't use a negative SIZE range " + "length for SEQUENCE OF"); + } + + $$->subtype = $4; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + ; + +SetType : kw_SET '{' /* ComponentTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TSet); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + | kw_SET '{' '}' + { + $$ = new_type(TSet); + $$->members = NULL; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + ; + +SetOfType : kw_SET kw_OF Type + { + $$ = new_type(TSetOf); + $$->subtype = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + ; + +ChoiceType : kw_CHOICE '{' /* AlternativeTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TChoice); + $$->members = $3; + } + ; + +ReferencedType : DefinedType + | UsefulType + /* | TypeFromObject // X.681 */ + /* | ValueSetFromObjects // X.681 */ + ; + +/* +TypeFromObject : VALUE_IDENTIFIER '.' '&' TYPE_IDENTIFIER + { $$ = type_from_object($1, $4); }; + */ + +DefinedType : TYPE_IDENTIFIER + { + Symbol *s = addsym($1); + $$ = new_type(TType); + if(s->stype != Stype && s->stype != SUndefined) + lex_error_message ("%s is not a type\n", $1); + else + $$->symbol = s; + } + | ParameterizedType + { $$ = $1; } + ; + + /* + * Should be ActualParameterList, but we'll do just one for now + * as that's enough for PKIX. + */ +ParameterizedType + : Identifier '{' ActualParameter '}' /* XXX ActualParameterList */ + { + Symbol *s, *ps; + char *pname = NULL; + + if ($3 == NULL) { + lex_error_message("Unknown ActualParameter object set parametrizing %s\n", $1); + exit(1); + } + + /* Lookup the type from a ParameterizedTypeAssignment */ + if (asprintf(&pname, "%s{%s:x}", $1, + $3->iosclass->symbol->name) == -1 || + pname == NULL) + err(1, "Out of memory"); + ps = addsym(pname); + if (ps->stype != Sparamtype) + lex_error_message ("%s is not a parameterized type\n", $1); + + s = addsym($1); + $$ = ps->type; /* XXX copy, probably */ + if (!ps->type) + errx(1, "Wrong class (%s) parameter for parameterized " + "type %s", $3->iosclass->symbol->name, $1); + s->stype = Stype; + if(s->stype != Stype && s->stype != SUndefined) + lex_error_message ("%s is not a type\n", $1); + else + $$->symbol = s; + $$->actual_parameter = $3; + if ($$->type == TTag) + $$->subtype->actual_parameter = $3; + } + +/* + * Per X.683 $1 for ActualParameter should be any of: a Type, a Value, a + * ValueSet, a DefinedObjectClass, an Object, or an ObjectSet. For PKIX we + * need nothing more than an ObjectSet here. + * + * Also, we can't lexically or syntactically tell the difference between all + * these things, though fortunately we can for ObjectSet. + */ +ActualParameter : DefinedObjectSet + { $$ = $1; }; + +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 : UnconstrainedType Constraint + { + $$ = $1; + if ($2->ctype == CT_RANGE) { + if ($1->type != TTag || $1->subtype->type != TInteger) + lex_error_message("RANGE constraints apply only to INTEGER types"); + $$->subtype->range = $2->u.range; + free($2); + } else { + $$->constraint = $2; + } + /* if (Constraint.type == contentConstraint) { + 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 : SubtypeConstraint | GeneralConstraint + ; + +SubtypeConstraint: range + { + $$ = new_constraint_spec(CT_RANGE); + $$->u.range = $1; + } + +GeneralConstraint: ContentsConstraint + | UserDefinedConstraint + | TableConstraint + ; + +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) + lex_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) + lex_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); + } + ; + +TableConstraint : SimpleTableConstraint + { $$ = $1; } + | ComponentRelationConstraint + { $$ = $1; }; + +SimpleTableConstraint + : '{' TYPE_IDENTIFIER '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->ctype = CT_TABLE_CONSTRAINT; + $$->u.content.crel.objectname = $2; + $$->u.content.crel.membername = 0; + }; + +/* + * In X.682, ComponentRelationConstraint is a fantastically more complicated + * production. The stuff in the second set of braces is a list of AtNotation, + * and AtNotation is '@' followed by some number of '.'s, followed by a + * ComponentIdList, which is a non-empty set of identifiers separated by '.'s. + * The number of '.'s is a "level" used to identify a SET, SEQUENCE, or CHOICE + * where the path of member identifiers is rooted that ultimately identifies + * the field providing the constraint. + * + * So in + * + * extnValue OCTET STRING + * (CONTAINING + * EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + * ^^^^^^^^^^^^^^^^^^^ + * ObjectClassFieldType + * meaning the open type field + * &ExtnType of EXTENSION + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * GeneralConstraint + * ^^^^^^^^^^^^^^^^^^^^^^^ + * ComponentRelationConstraint + * ^^^^^^^^^^^^^^ + * DefinedObjectSet + * ^^^^^^^^ + * '{' AtNotation ',' + '}' + * + * we have EXTENSION.&ExtnType is the ObjectClassFieldType, and + * ({ExtensionSet}{@extnID}) is the ComponentRelationConstraint on the + * extnValue member, where {ExtensionSet} is the DummyReference from the formal + * parameter of the enclosing parameterized type, and {@extnID} is the + * AtNotation list identifying the field of the class/objects-in-the-object-set + * that will be identifying the type of the extnValue field. + * + * We need just the one AtNotation component. + */ +ComponentRelationConstraint + : '{' TYPE_IDENTIFIER '}' '{' '@' Identifier '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->ctype = CT_TABLE_CONSTRAINT; + $$->u.content.crel.objectname = $2; + $$->u.content.crel.membername = $6; + }; + +TaggedType : Tag tagenv Type + { + $$ = new_type(TTag); + $$->tag = $1; + $$->tag.tagenv = $2; + if (template_flag) { + $$->subtype = $3; + } else if ($2 == TE_IMPLICIT) { + Type *t = $3; + + /* + * FIXME 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; + } + } + ; + +Tag : '[' Class NUMBER ']' + { + $$.tagclass = $2; + $$.tagvalue = $3; + $$.tagenv = default_tag_env; + } + ; + +Class : /* */ + { + $$ = ASN1_C_CONTEXT; + } + | kw_UNIVERSAL + { + $$ = ASN1_C_UNIV; + } + | kw_APPLICATION + { + $$ = ASN1_C_APPL; + } + | kw_PRIVATE + { + $$ = ASN1_C_PRIVATE; + } + ; + +tagenv : /* */ + { + $$ = default_tag_env; + } + | kw_EXPLICIT + { + $$ = default_tag_env; + } + | kw_IMPLICIT + { + $$ = TE_IMPLICIT; + } + ; + + +ValueAssignment : VALUE_IDENTIFIER Type EEQUAL Value + { + Symbol *s; + s = addsym ($1); + + s->stype = SValue; + s->value = $4; + generate_constant (s); + /* + * Save this value's name so we can know some name for + * this value wherever _a_ name may be needed for it. + * + * This is useful for OIDs used as type IDs in objects + * sets of classes with open types. We'll generate + * enum labels from those OIDs' names. + */ + s->value->s = s; + } + ; + +CharacterStringType: RestrictedCharactedStringType + ; + +RestrictedCharactedStringType: kw_GeneralString + { + $$ = new_tag(ASN1_C_UNIV, UT_GeneralString, + TE_EXPLICIT, new_type(TGeneralString)); + } + | kw_TeletexString + { + $$ = new_tag(ASN1_C_UNIV, UT_TeletexString, + TE_EXPLICIT, new_type(TTeletexString)); + } + | 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(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | ComponentTypeList ',' ComponentType + { + HEIM_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; + HEIM_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(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | NamedBitList ',' NamedBit + { + HEIM_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) { + lex_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 + ; + +ValueExNull : BuiltinValueExNull + | ReferencedValue + ; + +BuiltinValue : BooleanValue + | CharacterStringValue + | IntegerValue + | ObjectIdentifierValue + | NullValue + ; + +BuiltinValueExNull + : BooleanValue + | CharacterStringValue + | IntegerValue + | ObjectIdentifierValue + ; + +ReferencedValue : DefinedValue + ; + +DefinedValue : Valuereference + ; + +Valuereference : VALUE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != SValue) + lex_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 = 1; + } + | 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) +{ + lex_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; + t->id = idcounter++; + 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; + HEIM_TAILQ_FOREACH(m, members, members) { + if (asprintf(&m->label, "%s_%s", prefix, m->gen_name) < 0) + errx(1, "malloc"); + 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 = NULL; + if (asprintf(&p, "choice_%s", s->gen_name) < 0 || p == NULL) + errx(1, "malloc"); + if (s->type) + fix_labels2(s->type, p); + free(p); +} + +static struct objectshead * +add_object_set_spec(struct objectshead *lst, IOSObject *o) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, o, objects); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, o, objects); + } + return lst; +} + +static struct objfieldhead * +add_field_setting(struct objfieldhead *lst, ObjectField *f) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, f, objfields); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, f, objfields); + } + return lst; +} + +static struct fieldhead * +add_field_spec(struct fieldhead *lst, Field *f) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, f, fields); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, f, fields); + } + return lst; +} + +static ObjectField * +new_field_setting(char *n, Type *t, struct value *v) +{ + ObjectField *of; + + of = ecalloc(1, sizeof(*of)); + of->value = v; + of->type = t; + of->name = n; + return of; +} + +static Field * +new_type_field(char *n, int optional, Type *t) +{ + Field *f; + + f = ecalloc(1, sizeof(*f)); + f->optional = optional; + f->unique = 0; + f->defval = 0; + f->type = t; + f->name = n; + return f; +} + +static Field * +new_fixed_type_value_field(char *n, Type *t, int unique, int optional, struct value *defval) +{ + Field *f; + + f = ecalloc(1, sizeof(*f)); + f->optional = optional; + f->unique = unique; + f->defval = defval; + f->type = t; + f->name = n; + return f; +} + +static Type * +parametrize_type(Type *t, IOSClass *c) +{ + Type *type; + + type = new_type(TType); + *type = *t; /* XXX Copy, or use subtype; this only works as long as we don't cleanup! */ + type->formal_parameter = c; + return type; +} + +static Type * +type_from_class_field(IOSClass *c, const char *n) +{ + Field *f; + Type *t; + + HEIM_TAILQ_FOREACH(f, c->fields, fields) { + if (strcmp(f->name, n) == 0) { + t = new_type(TType); + if (f->type) { + *t = *f->type; + } else { + Symbol *s = addsym("HEIM_ANY"); + if(s->stype != Stype && s->stype != SUndefined) + errx(1, "Do not define HEIM_ANY, only import it\n"); + s->stype = Stype; + t->symbol = s; + } + t->typeref.iosclass = c; + t->typeref.field = f; + return t; + } + } + return NULL; +} + +static void +validate_object_set(IOSObjectSet *os) +{ + IOSObject **objects; + ObjectField *of; + IOSObject *o; + Field *cf; + size_t nobjs, i; + + /* Check unique fields */ + HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) { + if (!cf->unique) + continue; + if (!cf->type) + errx(1, "Type fields of classes can't be UNIQUE (%s)", + os->iosclass->symbol->name); + sort_object_set(os, cf, &objects, &nobjs); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + if (strcmp(cf->name, of->name) != 0) + continue; + if (!of->value) + errx(1, "Value not specified for required UNIQUE field %s of object %s", + cf->name, objects[i]->symbol->name); + break; + } + if (i == 0) + continue; + if (object_cmp(&objects[i - 1], &objects[i]) == 0) + errx(1, "Duplicate values of UNIQUE field %s of objects %s and %s", + cf->name, objects[i - 1]->symbol->name, + objects[i]->symbol->name); + } + free(objects); + } + + /* Check required fields */ + HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) { + if (cf->optional || cf->defval || !cf->type) + continue; + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + int specified = 0; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, cf->name) != 0) + continue; + if (of->value) + specified = 1; + break; + } + if (!specified) + errx(1, "Value not specified for required non-UNIQUE field %s of object %s", + cf->name, o->symbol->name); + } + } +} |