asn1: Update README-X681.md

This commit is contained in:
Nicolas Williams
2021-02-10 14:51:28 -06:00
parent 24d26a2ddc
commit 22b8c3d448

View File

@@ -7,6 +7,7 @@
3. [ASN.1 IOS, Constraint, and Parameterization](#asn1-ios-constraint-and-parameterization)
- [IOS Crash Course](#ios-crash-course)
4. [Implementation Thoughts](#implementation-thoughts)
5. [Moving From C](#moving-from-c)
## Introduction
@@ -19,23 +20,25 @@ Various extensions are specified in other X.680 series documents:
- X.683: Parameterization of ASN.1 specifications
While X.680 is essential for implementing many Internet (and other) protocols,
implementing a subset of X.681, X.682, and X.683, can enable some magical
features. These magical features are generally not the focus of those ITU-T
specifications nor of many RFCs that make use of them.
and sufficient for implementing all of those, implementing a subset of X.681,
X.682, and X.683, can enable some magical features. These magical features are
generally not the focus of those ITU-T specifications nor of many RFCs that
make use of them.
The intent of X.681, X.682, and X.683 is to add ways to formally express
constraints that would otherwise require natural language to express. But give
a compiler more formally-expressed constraints and it can do more labor-saving
constraints that would otherwise require natural language to express. Give a
compiler more formally-expressed constraints and it can do more labor-saving
than it could otherwise.
This README will cover some ideas for what this magic will be, and
implementation of it.
RFC 6025 does an excellent job of elucidating X.681, which otherwise most
readers unfamiliar with it will no doubt find inscrutable.
readers unfamiliar with it will no doubt find inscrutable. Hopefully this
README improces that further.
The magic that we're after is simply the *automatic and recursive handling of
open types by the Heimdal ASN.1 compiler*.
open types by an ASN.1 compiler*.
Combined with future support for the ASN.1 JSON Encoding Rules (JER) [X.697],
the automatic handling of open types should allow us to trivially implement a
@@ -46,9 +49,12 @@ encoding rules. I.e., dump DER to JSON, and parse JSON to output DER.
Combined with transcoders for JSON/CBOR and other binary-JSON formats, we could
support those encodings too.
We could really see how much space OER/JER/CBOR save over DER for Kerberos
tickets, PKIX certificates, and much else.
We especially want this for PKIX, and more than anything for certificates, as
the TBSCertificate type is full of open types: DN and subjectDirectory
attributes, otherName SAN types, and certificate extensions.
the TBSCertificate type is full of deeply nested open types: DN and
subjectDirectory attributes, otherName SAN types, and certificate extensions.
Besides a magical ASN.1 DER/JER dumper/transcoder utility, we want to replace
DN attribute and subject alternative name (SAN) `otherName` tables and much
@@ -406,21 +412,26 @@ zero, one, or more "objects". Each object has settings for all required fields
of a class, and possibly also for optional/defaulted fields as well.
IOS object sets really are akin to relational database tables, while objects
are akin to rows of the same. And classes? They're like a specification of
relational database tables that object sets derive.
are akin to rows of the same, with columns specified by classes. Or one can
think of classes as tables with one predefined column naming object sets, rows
being objects grouped into oject sets by that column. IOS supports complex
path expressions across these objects (but we won't need that yet).
So far, that is so useless to us: we have no need to specify constant (because
defined in compiled modules) relational data.
These relational entities are constant in that they are defined in ASN.1
modules that are compiled. There is no way to change them at run-time, only
query them. They also have no on-the-wire representation.
The magic for us lies in being able to document and constrain actual types
using IOS classes and object sets. We want to use classes and object sets to
constrain `SET` or `SEQUENCE` types (well, really, just `SEQUENCE`) in such a
way that the compiler can auto-generate decoding and encoding of values of open
types.
So far, the IOS seems just so useless to us: we have some, but non-urgent need
to specify constant relational data.
`SET` and `SEQUENCE` types have "members".
The magic for us lies in being able to document and constrain actual datatypes
using the IOS. We want to use classes and object sets to constrain `SET` or
`SEQUENCE` types (well, really, just `SEQUENCE`) so that our ASN.1 compiler can
have the metadata it needs in ordr to auto-generate decoding and encoding of
values of open types.
Classes and objects have "fields".
A termnology point: `SET` and `SEQUENCE` types have "members", but classes and
objects have "fields".
Objects of a class have all the required fields of a class and any of the
`OPTIONAL` or `DEFAULT` fields of the class. This is very similar to
@@ -432,9 +443,9 @@ struct or object types.
There are several kinds of fields of classes. These can be confusing, so it's
essential that we explain them by reference to how they relate to the members
of `SEQUENCE` types derived from a class:
of `SEQUENCE` types constrained by object sets:
- a `type field` of a class is one that specifies a SET or SEQUENCE member of
- A `type field` of a class is one that specifies a SET or SEQUENCE member of
unknown (open) type.
The type of that SET or SEQUENCE member will not be not truly unknown, but
@@ -442,22 +453,28 @@ of `SEQUENCE` types derived from a class:
specified in a "value field" (or "value set" field) an "object" in an
"object set" of that class.
- a `fixed type value field` of a class is one that specifies a SET or
SEQUENCE member of fixed type.
This is essentially a "type variable", as is seen in high-level languages
like Haskell.
- a `fixed type value set field` of a class is like a `fixed type value field`,
but where object sets should provide a set of values for the SET or SEQUENCE
member corresponding to the field.
- A `fixed type value field` of a class is one that specifies a SET or
SEQUENCE member of fixed type. Being of fixed-type, this is not a type
variable.
- a `variable type value [set] field` is one where the type of the SET or
SEQUENCE member corresponding to the field will vary according to some
- A `fixed type value set field` of a class is like a `fixed type value
field`, but where object sets should provide a set of values with which to
constrain `SET`/`SEQUENCE` members corresponding to the field.
- A `variable type value [set] field` is one where the type of the `SET` or
`SEQUENCE` member corresponding to the field will vary according to some
specified `type field` of the same class.
- an `object field` will be a field that names another class (possibly the
- An `object field` will be a field that names another class (possibly the
same class), which can be used to provide rich hierarchical type semantics
that... we don't need for PKIX.
- similarly for `object set field`s.
These define relations between classes, much like `FOREIGN KEY`s in SQL.
- Similarly for `object set field`s.
As usual for ASN.1, the case of the first letter of a field name is meaningful:
@@ -618,8 +635,9 @@ class and others are not, or where multiple classes are used.
In the case of `INSTANCE OF`, what shall the names of the members of the
derived type be? Well, such types can _only_ be instances of `TYPE-IDENTIFIER`
or classes isomorphic to it (as `OTHER-NAME` is in the above exammle), and so
the names of their two members are just baked in by X.681 annex C.1 as:
or classes copied from and isomorphic to it (as `OTHER-NAME` is in the above
exammle), and so the names of their two members are just baked in by X.681
annex C.1 as:
```ASN.1
SEQUENCE {
@@ -630,7 +648,8 @@ the names of their two members are just baked in by X.681 annex C.1 as:
-- `TYPE-IDENTIFIER` or exactly like it.
```
(This means we can't use `INSTANCE OF` with `EXTENSION`.)
(This means we can't use `INSTANCE OF` with `EXTENSION`, though we can for
`OTHER-NAME`.)
PKIX has much more complex classes for relating and constraining cryptographic
algorithms and their parameters:
@@ -653,7 +672,12 @@ only be used by the codecs at run-time to perform validation of, e.g.,
cryptographic algorithm parameters, but also to provide those rules to other
code in the application so that the programmer doesn't have to manually write
the same in C, C++, Java, etc, and can refer to them when applying those
cryptographic algorithms.
cryptographic algorithms. And, of course, the object sets for the above
classes can be and are specified in standards documents, making it very easy to
import them into projects that have an IOS-capable ASN.1 compiler.
Still, for Heimdal we won't bother with the full power of X.681/X.682/X.683 for
now.
## Implementation Thoughts
@@ -679,11 +703,11 @@ cryptographic algorithms.
qualifiers, the works.
- We'll really want to do this mainly for the template compiler and begin
abandoning the original compiler -- hacking on two compilers is difficult,
and the template compiler is superior just on account of emitted code size
scaling as `O(N)` instead of `O(M * N)` where `M` is the number of encoding
rules supported and `N` is the number of types in an ASN.1 module (or all
modules).
abandoning the original compiler -- maintaining and developing two compiler
backends is difficult enough, but the template compiler is superior just on
account of emitted code size scaling as `O(N)` instead of `O(M * N)` where
`M` is the number of encoding rules supported and `N` is the number of types
in an ASN.1 module (or all modules).
- Also, to make the transition to using IOS in-tree, we'll want to keep
existing fields of C structures as generated by the compiler today, only
@@ -691,7 +715,7 @@ cryptographic algorithms.
encoding/decoding can still work and we can then update Heimdal in-tree
slowly to take advantage of the new magic.
Thus `Extension` should compile to:
Thus `Extension` should compile to something like:
```C
typedef struct Extension {
@@ -722,14 +746,14 @@ cryptographic algorithms.
fields.
In both cases, the `critical` field should get used as-is. The rule should
be that we support *two* special fields: a hole type ID enum field, and a
decoded hole value union. All other fields will map to either normal
members of the SET/SEQUENCE, or to members that are derived from a CLASS but
which are neither hole type ID fields nor hole fields.
be that we support *two* special C struct fields for open types: a hole type
ID enum field, and a decoded hole value union. All other fields will map to
either normal (possibly constrained) members of the SET/SEQUENCE.
- Type ID values must get mapped to discrete enum values. We'll want type IDs
to be sorted, too, so that we can binary search the "object set" when
decoding. For encoding we'll want to "switch" on the mapped type ID enum.
to be sorted, too, so that we can binary search the object set's template
when decoding for extra speed. For encoding we'll want to "switch" on the
mapped type ID enum, directly indexing the template for the object set.
- The ASN.1 parser merely builds an AST. That will not change.
@@ -744,3 +768,11 @@ cryptographic algorithms.
Perhaps we'll inline the objects for locality of reference.
## Moving From C
- Generate a JSON representation of each ASN.1 module
- Code codegen/templategen backends in jq or Haskell or whatever
- Code template interpreters in <host> language