RFC 1076






Network Working Group                                         G. Trewitt
Request for Comments: 1076                           Stanford University
Obsoletes: RFC 1023                                         C. Partridge
                                                                BBN/NNSC
                                                           November 1988


                  HEMS Monitoring and Control Language

                           TABLE OF CONTENTS

1.   Status of This Memo                                               1
     Introduction                                                      2
2.   Overview and Scope                                                2
3.   Overview of Query Processor Operation                             4
4.   Encoding of Queries and Responses                                 5
4.1  Notation Used in This Proposal                                    5
5.   Data Organization                                                 6
5.1  Example Data Tree                                                 7
5.2  Arrays                                                            8
6.   Components of a Query                                             9
7.   Reply to a Query                                                 10
8.   Query Language                                                   12
8.1  Moving Around in the Data Tree                                   14
8.2  Retrieving Data                                                  15
8.3  Data Attributes                                                  16
8.4  Examining Memory                                                 18
8.5  Control Operations:  Modifying the Data Tree                     19
8.6  Associative Data Access:  Filters                                21
8.7  Terminating a Query                                              26
9.   Extending the Set of Values                                      27
10.  Authorization                                                    27
11.  Errors                                                           28
I.   ASN.1 Descriptions of Query Language Components                  29
I.1  Operation Codes                                                  30
I.2  Error Returns                                                    31
I.3  Filters                                                          33
I.4  Attributes                                                       34
I.5  VendorSpecific                                                   36
II.  Implementation Hints                                             36
III. Obtaining a Copy of the ASN.1 Specification                      42

1. STATUS OF THIS MEMO

   This RFC specifies a query language for monitoring and control of
   network entities.  This RFC supercedes RFC-1023, extending the query
   language and providing more discussion of the underlying issues.




Trewitt & Partridge                                             [Page 1]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   This language is a component of the High-Level Entity Monitoring
   System (HEMS) described in RFC-1021 and RFC-1022.  Readers may wish
   to consult these RFCs when reading this memo.  RFC-1024 contains
   detailed assignments of numbers and structures used in this system.
   Portions of RFC-1024 that define query language structures are
   superceded by definitions in this memo.  This memo assumes a
   knowledge of the ISO data encoding standard, ASN.1.

   Distribution of this memo is unlimited.

INTRODUCTION

   This RFC specifies the design of a general-purpose, yet efficient,
   monitoring and control language for managing network entities.  The
   data in the entity is modeled as a hierarchy and specific items are
   named by giving the path from the root of the tree.  Most items are
   read-only, but some can be "set" in order to perform control
   operations.  Both requests and responses are represented using the
   ISO ASN.1 data encoding rules.

2. OVERVIEW AND SCOPE

   The basic model of monitoring and control used in this memo is that a
   query is sent to a monitored entity and the entity sends back a
   response.  The term query is used in the database sense -- it may
   request information, modify data, or both.  We will use gateway-
   oriented examples, but it should be understood that this query-
   response mechanism is applicable to any IP entity.

   In particular, there is no notion of an interactive "conversation" as
   in SMTP [RFC-821] or FTP [RFC-959].  A query is a complete request
   that stands on its own and elicits a complete response.

   In order to design the query language, we had to define a model for
   the data to be retrieved by the queries, which required some
   understanding of and assumptions to be made about the data.  We ended
   up with a fairly flexible data model, which places few limits on the
   type or size of the data.

   Wherever possible, we give motivations for the design decisions or
   assumptions that led to particular features or definitions.  Some of
   the important global considerations and assumptions are:

         - The query processor should place as little computational
           burden on the monitored entity as possible.

         - It should not be necessary for a monitored entity to store
           the complete query.  Nothing in the query language should



Trewitt & Partridge                                             [Page 2]

RFC 1076          HEMS Monitoring and Control Language     November 1988


           preclude an implementation from being able to process the
           query on the fly, producing portions of the response while
           the query is still being read and parsed.  There may be
           other constraints that require large amounts of data to be
           buffered, but the query language design must not be one.

         - It is assumed that there is some mechanism to transport a
           sequence of octets to a query processor within the
           monitored entity and that there is some mechanism to return
           a sequence of octets to the entity making the query.  In
           HEMS, this is provided by HEMP and its underlying transport
           layer.  The query language design is independent of these
           details, however, and could be grafted onto some other
           protocol.

         - The data model must provide organization for the data, so
           that it can be conveniently named.

         - Much of the data to be monitored will be contained in
           tables.  Some tables may contain other tables.  The query
           language should be able to deal with such tables.

         - We don't provide capabilities for data reduction in the
           query language.  We will provide for data selection, for
           example, only retrieving certain table entries, but we will
           not provide general facilities for processing data, such as
           computing averages.

         - Because one monitoring center may be querying many
           (possibly hetrogenous) hosts, it must be possible to write
           generic queries that can be sent to all hosts, and have the
           query elicit as much information as is available from each
           host.  i.e., queries must not be aborted just because they
           requested non-existent data.

   There were some assumptions that we specifically did not make:

         - It is up to the implementation to choose what degree of
           concurrency will be allowed when processing queries.  By
           locking only portions of the database, it should be
           possible to achieve good concurrency while still preventing
           deadlock.

         - This specification makes no statement about the use of the
           "definite" and "indefinite" length forms in ASN.1.  There
           is currently some debate about this usage in the ISO
           community; implementors should note the recommendations in
           the ASN.1 specification.



Trewitt & Partridge                                             [Page 3]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   Other RFCs associated with HEMS are:

      RFC-1021        Overview;
      RFC-1022        Transport protocol and message encapsulation;
      RFC-1024        Precise data definitions.

   The rest of this report is organized as follows:

      Section 3       Gives a brief overview of the data model and the
                      operation of the query processor.

      Section 4       Describes the encoding used for queries and
                      responses, and the notation used to represent them
                      in this report.

      Section 5       Describes how the data is organized in the
                      monitored entity, and the view provided of it by
                      the query processor.

      Section 6       Describes the basic data types that may be given
                      to the query processor as input.

      Section 7       Describes how a reply to a query is organized.

      Section 8       Describes the operations available in the query
                      language.

      Section 9       Describes how the set of data in the tree may be
                      extended.

      Section 10      Describes how authorization issues affect the
                      execution of a query.

      Section 11      Describes how errors are reported, and their
                      effect on the processing of the query.

      Appendix I      Gives precise ASN.1 definitions of the data types
                      used by the query processor.

      Appendix II     Gives extensive implementation hints for the core
                      of the query processor.

3. OVERVIEW OF QUERY PROCESSOR OPERATION

   In this section, we give an overview of the operation of the query
   processor, to provide a framework for the later sections.

   The query language models the manageable data as a tree, with each



Trewitt & Partridge                                             [Page 4]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   branch representing a different aspect of the entity, such as
   different layers of protocols.  Subtrees are further divided to
   provide additional structure to the data.  The leaves of the tree
   contain the actual data.

   Given this data representation, the task of the query processor is to
   traverse this tree and retrieve (or modify) data specified in a
   query.  A query consists of instructions to move around in the tree
   and to retrieve (or modify) named data.  The result of a query is an
   exact image of the parts of the tree that the query processor
   visited.

   The query processor is very simple -- it only understands eight
   commands, most of which share the same structure.  It is helpful to
   think of the query processor as an automaton that walks around in the
   tree, directed by commands in the query.  As it moves around, it
   copies the tree structure it traverses to the query result.  Data
   that is requested by the query is copied into the result as well.
   Data that is changed by a query is copied into the result after the
   modification is made.

4. ENCODING OF QUERIES AND RESPONSES

   Both queries and responses are encoded using the representation
   defined in ISO Standard ASN.1 (Abstract Syntax Notation 1).  ASN.1
   represents data as sequences of  triples that
   are encoded as a stream of octets.  The data tuples may be
   recursively nested to represent structured data such as arrays or
   records.  For a full description, see the ISO standards IS 8824 and
   IS 8825.  See appendix for information about obtaining these
   documents.

4.1 Notation Used in This Proposal

   The notation used in this memo is similar to that used in ASN.1, but
   less formal, smaller, and (hopefully) easier to read.  We will refer
   to a  tuple as a "data object".  In this RFC, we
   will not be concerned with the details of the object lengths.  They
   exist in the actual ASN.1 encoding, but will be omitted in the
   examples here.

   Data objects that have no internal ASN.1 structure such as integer or
   octet string are referred to as "simple types" or "simple objects".
   Objects which are constructed out of other ASN.1 data objects will be
   referred to as "composite types" or "composite objects".






Trewitt & Partridge                                             [Page 5]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   The notation
       ID(value)
   represents a simple object whose tag is "ID" with the given value.  A
   composite object is represented as
       ID{ ... contents ... }
   where contents is a sequence of data objects.  The contents may
   include both simple and structured types, so the structure is fully
   recursive.

   The difference between simple and composite types is close to the
   meaning of the "constructor" bit in ASN.1.  For the uses here, the
   distinction is made based upon the semantics of the data, not the
   representation.  Therefore, even though an OctetString can be
   represented in ASN.1 using either constructed or non-constructed
   forms, it is conceptually a simple type, with no internal structure,
   and will always be written as
       ID("some arbitrary string")
   in this RFC.

   There are situations where it is necessary to specify a type but give
   no value, such as when referring to the name of the data.  In this
   situation, the same notation is used, but with the value omitted:
       ID   or  ID()   or   ID{}
   Such objects have zero length and no contents.  The latter two forms
   are used when a distinction is being made between simple and
   composite data, but the difference is just notation -- the
   representation is the same.

   ASN.1 distinguishes between four "classes" of tags: universal,
   application-specific, context-dependent, and reserved.  HEMS and this
   query language use the first three.  Universal tags are assigned in
   the ASN.1 standard and its addendums for common types, and are
   understood by any application using ASN.1.  Application-specific tags
   are limited in scope to a particular application.  These are used for
   "well-known" identifiers that must be recognizable in any context,
   such as derived data types.  Finally, context-dependent tags are used
   for objects whose meaning is dependent upon where they are
   encountered.  Most tags that identify data are context-dependent.

5. DATA ORGANIZATION

   Data in a monitored entity is modeled as a hierarchy.
   Implementations are not required to organize the data internally as a
   hierarchy, but they must provide this view of the data through the
   query language.  A hierarchy offers useful structure for the
   following operations:





Trewitt & Partridge                                             [Page 6]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   Organization    A hierarchy allows related data to be grouped
                   together in a natural way.

   Naming          The name of a piece of data is just the path from the
                   root to the data of interest.

   Mapping onto ASN.1
                   ASN.1 can easily represent a hierarchy by using a
                   "constructor" type as an envelope for an entire
                   subtree.

   Efficient Representation
                   Hierarchical structures are compact and can be
                   traversed quickly.

   Safe Locking    If it is necessary to lock part of the hierarchy (for
                   example, when doing an update), locking an entire
                   subtree can be done efficiently and safely, with no
                   danger of deadlock.

   We will use the term "data tree" to refer to this entire structure.
   Note that this internal model is completely independent of the
   external ASN.1 representation -- any other suitable representation
   would do.  For the sake of efficiency, we do make a one-to-one
   mapping between ASN.1 tags and the (internal) names of the nodes.
   The same could be done for any other external representation.

   Each node in the hierarchy must have names for its component parts.
   Although we would normally think of names as being ASCII strings such
   as "input errors", the actual name is just an ASN.1 tag.  Such names
   are small integers (typically, less than 30) and so can easily be
   mapped by the monitored entity onto its internal representation.

   We use the term "dictionary" to mean an internal node in the
   hierarchy.  Leaf nodes contain the actual data.  A dictionary may
   contain both leaf nodes and other dictionaries.

5.1 Example Data Tree

   Here is a possible organization of the hierarchy in an entity that
   has several network interfaces and does IP routing.  The exact
   organization of data in entities is specified in RFC-1024.  This
   skeletal data tree will be used throughout this RFC in query
   examples.

          System {
                  name                            -- host name
                  clock-msec                      -- msec since boot



Trewitt & Partridge                                             [Page 7]

RFC 1076          HEMS Monitoring and Control Language     November 1988


                  interfaces                      -- # of interfaces
                  memory
                  }
          Interfaces {                            -- one per interface
                  InterfaceData{ address, mtu, netMask, ARP{...}, ... }
                  InterfaceData{ address, mtu, netMask, ARP{...}, ... }
                                  :
                  }
          IPRouting {
                  Entry{ ip-addr, interface, cost, ... }
                  Entry{ ip-addr, interface, cost, ... }
                                  :
                  }

      There are three top-level dictionaries in this hierarchy (System,
      Interfaces, and IPRouting) and three other dictionary types
      (InterfaceData, Entry, and ARP), each with multiple instances.

      The "name" of the clock in this entity would be:
          system{ clock-msec }
      and the name of a routing table entry's IP address would be:
          IPRouting{ Entry{ ip-addr } }.

      More than one piece of data can be named by a single ASN.1 object.
      The entire collection of system information is named by:
          system
      and the name of a routing table's IP address and cost would be:
          IPRouting{ Entry{ ip-addr, cost } }.

5.2 Arrays

   There is one sub-type of a dictionary that is used as the basis for
   tables of objects with identical types.  We call these dictionaries
   arrays.  In the example above, the dictionaries for interfaces,
   routing tables, and ARP tables are all arrays.

   In the examples above, the "ip-addr" and "cost" fields are named.  In
   fact, these names refer to the field values for ALL of the routing
   table entries -- the name doesn't (and can't) specify which routing
   table entry is intended.  This ambiguity is a problem wherever data
   is organized in tables.  If there was a meaningful index for such
   tables (e.g., "routing table entry #1"), there would be no problem.
   Unfortunately, there usually isn't such an index.  The solution to
   this problem requires that the data be accessed on the basis of some
   of its content.  Filters, discussed in section 8.6, provide this
   mechanism.

   The primary difference between arrays and plain dictionaries is that



Trewitt & Partridge                                             [Page 8]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   arrays may contain only one type of item, while dictionaries, in
   general, will contain many different types of items.  For example,
   the dictionary IPRouting (which is an array) will contain only items
   of type Entry.

   The fact that these objects are viewed externally as arrays or tables
   does not mean that they are represented in an implementation as
   linear lists of objects.  Any collection of same-typed objects is
   viewed as an array, even though it might be stored internally in some
   other format, for example, as a hash table.

6. COMPONENTS OF A QUERY

   A HEMS query consists of a sequence of ASN.1 objects, interpreted by
   a simple stack-based interpreter.  [Although we define the query
   language in terms of the operations of a stack machine, the language
   does not require an implementation to use a stack machine.  This is a
   well-understood model, and is easy to implement.]  One ASN.1 tag is
   reserved for operation codes; all other tags indicate data that will
   eventually be used by an operation.  These objects are pushed onto
   the stack when received.  Opcodes are immediately executed and may
   remove or add items to the stack.  Because ASN.1 itself provides
   tags, very little needs to be done to the incoming ASN.1 objects to
   make them suitable for use by the query interpreter.

   Each ASN.1 object in a query will fit into one of the following
   categories:

   Opcode    An opcode tells the query interpreter to perform an action.
             They are described in detail in section 8.  Opcodes are
             represented by an application-specific type whose value
             determines the operation.

   Template  These are objects that name one or more items in the data
             tree.  Named items may be either simple items (leaf nodes)
             or entire dictionaries, in which case the entire subtree
             "underneath" the dictionary is understood.  Templates are
             used to select specific data to be retrieved from the data
             tree.  A template may be either simple or structured,
             depending upon what it is naming.  A template only names
             the data -- there are no values contained in it.  Therefore
             the leaf objects in a template will all have a length of
             zero.

             Examples of very simple templates are:
                 name()   or   System{}
             Each of these is just one ASN.1 data object, with zero
             length.  The first names a single data item in the "System"



Trewitt & Partridge                                             [Page 9]

RFC 1076          HEMS Monitoring and Control Language     November 1988


             dictionary (and must appear in that context), and the
             second names the entire "System" dictionary.  A more
             complex template such as:
                 Interfaces{ InterfaceData{ address, netMask, ARP } }
             names two simple data items and a dictionary, iterated over
             all occurrences of "InterfaceData" within the Interfaces
             array.

   Path      A path is a special case of a template that names only a
             single node in the tree.  It specifies a path down into the
             dictionary tree and names exactly one node in the
             dictionary tree.

   Value     These are used to give data values when needed in a query,
             for example, when changing a value in the data tree.  A
             value can be thought of as either a filled-in template or
             as the ASN.1 representation some part of the data tree.

   Filter    A boolean expression that can be executed in the context of
             a particular dictionary that is used to select or not
             select items in the dictionary.  The expressions consist of
             the primitives "equal", "greater-or-equal",
             "less-or-equal", and "present" possibly joined by "and",
             "or", and "not".  (See section 8.6.)

   Values, Paths, and Templates usually have names in the context-
   dependent class, except for a few special cases, which are in the
   application-specific class.

7. REPLY TO A QUERY

   The data returned to the monitoring entity is a sequence of ASN.1
   data items.  Conceptually, the reply is a subset of the data tree,
   where the query selects which portions are to be included.  This is
   exactly true for data retrieval requests, and essentially true for
   data modification requests -- the reply contains the data after it
   has been modified.  The key point is that the data in a reply
   represents the state of the data tree immediately after the query was
   executed.

   The sequence of the data is determined by the sequence of query
   language operations and the order of data items within Templates and
   Values given as input to these operations.  If a query requests data
   from two of the top-level dictionaries in the data tree, by giving
   two templates such as:

          System{ name, interfaces }
          Interfaces{



Trewitt & Partridge                                            [Page 10]

RFC 1076          HEMS Monitoring and Control Language     November 1988


                  InterfaceData { address, netMask, mtu }
                  }

   then the response will consist of two ASN.1 data objects, as follows:

          System {
                  name("system name"),
                  interfaces(2)
                  }
          Interfaces {
                  InterfaceData { address(36.8.0.1),
                                  netMask(FFFF0000),
                                  mtu(1500)
                                  }
                  InterfaceData { address(10.1.0.1),
                                  mtu(1008),
                                  netMask(FF000000)
                                  }
                  }

   With few exceptions, each of the data items in the hierarchy is named
   in the context-specific ASN.1 type space.  Because of this, the
   returned objects must be fully qualified.  For example, the name of
   the entity must always be returned encapsulated inside an ASN.1
   object for "System".  If it were not, there would be no way to tell
   if the object that was returned was "name" inside the "System"
   dictionary or "address" inside the "interfaces" dictionary (assuming
   in this case that "name" and "address" were assigned the same integer
   as their ASN.1 tags).

   Having fully-qualified data simplifies decoding of the data at the
   receiving end and allows the tags to be locally chosen.  Definitions
   for tags within routing tables won't conflict with definitions for
   tags within interfaces.  Therefore, the people doing the name
   assignments are less constrained.  In addition, most of the
   identifiers will be fairly small integers, which is an advantage
   because ASN.1 can fit tag numbers up to 30 in a one-octet tag field.
   Larger numbers require a second octet.

   If data is requested that doesn't exist, either because the tag is
   not defined, or because an implementation doesn't provide that data
   (such as when the data is optional), the response will contain an
   ASN.1 object that is empty.  The tag will be the same as in the
   query, and the object will have a length of zero.

   The same response is given if the requested data does exist, but the
   invoker of the query does not have authorization to access it.  See
   section 10 for more discussion of authorization mechanisms.



Trewitt & Partridge                                            [Page 11]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   This allows completely generic queries to be composed without regard
   to whether the data is defined or implemented at all of the entities
   that will receive the query.  All of the available data will be
   returned, without generating errors that might otherwise terminate
   the processing of the query.

8. QUERY LANGUAGE

   The query language is designed to be expressive enough to write
   useful queries with, yet simple enough to be easy to implement.  The
   query processor should be as simple and fast as possible, in order to
   avoid placing a burden on the monitored entity, which may be a
   critical node such as a gateway.

   Although queries are formed in a flexible way using what we term a
   "language", this is not a programming language.  There are operations
   that operate on data, but most other features of programming
   languages are not present.  In particular:

         - Programs are not stored in the query processor.

         - The only form of temporary storage is a stack, of limited
           depth.

         - There are no subroutines.

         - There are no explicit control structures defined in the
           language.

   The central element of the language is the stack.  It may contain
   templates, (and therefore paths), values, and filters taken from the
   query.  In addition, it can contain dictionaries (and therefore
   arrays) from the data tree.  At the beginning of a query, it contains
   one item, the root dictionary.

   The overall operation consists of reading ASN.1 objects from the
   input stream.  All objects that aren't opcodes are pushed onto the
   stack as soon as they are read.  Each opcode is executed immediately
   and may remove items from the stack, may generate ASN.1 objects and
   send them to the output stream, and may leave items on the stack.
   Because each input object is dealt with immediately, portions of the
   response may be generated while the query is still being received.

   In the descriptions below, operator names are in capital letters,
   preceded by the arguments used from the stack and followed by results
   left on the stack.  For example:





Trewitt & Partridge                                            [Page 12]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   OP                             a b   OP   a t
             means that the OP operator takes  and  off of the
             stack and leaves  on the stack.  Most of the operators
             in the query language leave the first operand ( in this
             example) on the stack for future use.

   If both  and  were received as part of the query (as opposed to
   being calculated by previous operations), then this part of the query
   would have consisted of the sequence:
       
       
       OP
   So, like other stack-based languages, the arguments and operators
   must be presented in postfix order, with an operator following its
   operands.

   Here is a summary of all of the operators defined in the query
   language.  Most of the operators can take several different sets of
   operands and behave differently based upon the operand types.
   Details and examples are given later.

   BEGIN                   dict1 path   BEGIN   dict1 dict
                    array path filter   BEGIN   array dict
             Move down in the data tree, establishing a context for
             future operations.

   END                           dict   END   --
             Undo the most recent BEGIN.

   GET                           dict   GET   dict
                        dict template   GET   dict
                array template filter   GET   array
             Retrieve data from the data tree.

   GET-ATTRIBUTES
                                 dict   GET-ATTRIBUTES   dict
                        dict template   GET-ATTRIBUTES   dict
                array template filter   GET-ATTRIBUTES   array
             Retrieve attribute information about data in the data tree.

   GET-RANGE   dict path start length   GET-RANGE   dict
             Retrieve a subrange of an OctetString.  Used for reading
             memory.

   SET                     dict value   SET   dict
                   array value filter   SET   array
             Change values in the data tree, possibly performing control
             functions.



Trewitt & Partridge                                            [Page 13]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   CREATE                 array value   CREATE   dict
             Create new table entries.

   DELETE                array filter   DELETE   array
             Delete table entries.

   These operators are defined so that it is impossible to generate an
   invalid query response.  Since a response is supposed to be a
   snapshot of a portion (or portions) of the data tree, it is important
   that only data that is actually in the tree be put in the response.
   Two features of the language help guarantee this:

      - Data is put in the response directly from the tree (by
        GET-*).  Data does not go from the tree to the stack and
        then into the response.

      - Dictionaries on the stack are all derived from the initial,
        root dictionary.  The operations that manipulate
        dictionaries (BEGIN and END) also update the response with
        the new location in the tree.

8.1 Moving Around in the Data Tree

   The initial point of reference in the data tree is the root.  That
   is, operators name data starting at the root of the tree.  It is
   useful to be able to move to some other dictionary in the tree and
   then name data from that point.  The BEGIN operator moves down in the
   tree and END undoes the last unmatched BEGIN.

   BEGIN is used for two purposes:

      - By moving to a dictionary closer to the data of interest,
        the name of the data can be shorter than if the full name
        (from the root) were given.

      - It is used to establish a context for filtered operations
        to operate in.  Filters are discussed in section 8.6.

   BEGIN                   dict1 path   BEGIN    dict1 dict
             Follow  down the dictionary starting from .
             Push the final dictionary named by  onto the stack.
              must name a dictionary (not a leaf node).  At the
             same time, produce the beginning octets of an ASN.1 object
             corresponding to the new dictionary.  It is up to the
             implementation to choose between using the "indefinite
             length" representation or the "definite length" form and
             going back and filling the length in later.




Trewitt & Partridge                                            [Page 14]

RFC 1076          HEMS Monitoring and Control Language     November 1988


   END                           dict   END   --
             Pop  off of the stack and terminate the open ASN.1
             object(s) started by the matching BEGIN.  Must be paired
             with a BEGIN.  If an END operation pops the root dictionary
             off of the stack, the query is terminated.

    must point to a regular dictionary.  If any part of it refers
   to a non-existent node, if it points to a leaf node, or if it refers
   to a node inside an array-type dictionary, then it is in error, and
   the query is terminated immediately.

   An additional form of BEGIN, which takes a filter argument, is
   described later.

8.2 Retrieving Data

   The basic model that all of the data retrieval operations follow is
   that they take a template and fill in the leaf nodes of the template
   with the appropriate data values.

   GET                  dict template   GET   dict
             Emit an ASN.1 object with the same "shape" as the given
             template, except with values filled in for each node.  The
             first ASN.1 tag of