asn1: Update README-X681.md

This commit is contained in:
Nicolas Williams
2021-02-05 16:49:24 -06:00
parent b0bf816ff8
commit 6cb0a2d667

View File

@@ -28,19 +28,29 @@ readers unfamiliar with it will no doubt find inscrutable.
The magic that we're after is simply the *automatic and recursive handling of 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 the Heimdal ASN.1 compiler*.
Combined with adding support for the ASN.1 JSON Encoding Rules (JER) [X.697], 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 the automatic handling of open types should allow us to trivially implement a
command-line tool that can parse any DER or JER (JSON) encoding of any value command-line tool that can parse any DER or JER (JSON) encoding of any value
whose type is known and compiled, and which could transcode to the other whose type is known and compiled, and which could transcode to the other
encoding rules. I.e., dump DER to JSON, and parse JSON to output DER. encoding rules. I.e., dump DER to JSON, and parse JSON to output DER.
We especially want this for PKIX, and more than anything for Certificates. Combined with transcoders for JSON/CBOR and other binary-JSON formats, we could
support those encodings too.
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.
Besides a magical ASN.1 DER/JER dumper/transcoder utility, we want to replace 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 DN attribute and subject alternative name (SAN) `otherName` tables and much
open-coded handling of certificate extensions in `lib/hx509/`. hand-coded handling of certificate extensions in `lib/hx509/`.
ITU-T references:
https://www.itu.int/rec/T-REC-X.680-201508-I/en
https://www.itu.int/rec/T-REC-X.681-201508-I/en https://www.itu.int/rec/T-REC-X.681-201508-I/en
https://www.itu.int/rec/T-REC-X.682-201508-I/en
https://www.itu.int/rec/T-REC-X.683-201508-I/en
Introduction Introduction
@@ -463,3 +473,261 @@ Implementation Thoughts
object will identify the type ID and the template for the associated type. object will identify the type ID and the template for the associated type.
Perhaps we'll inline the objects for locality of reference. Perhaps we'll inline the objects for locality of reference.
IOS Crash Course
================
The ASN.1 IOS is... a bit difficult to understand. X.681 has a lot of strange
terminology, like "variable type value set field". An IOS "class" has fields,
and those fields are of kind `[Fixed]Type[Value[Set]]` or `Object[Set]`.
Classes can have "object sets" associated with them, and each object set has
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.
So far, that is so useless to us: we have no need to specify constant (because
defined in compiled modules) relational data.
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.
`SET` and `SEQUENCE` types have "members".
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
`SET`/`SEQUENCE` members, which can be `OPTIONAL` or `DEFAULT`ed.
The "members" (we call them fields in C, instance variables in C++, Java, ...)
of a `SET` or `SEQUENCE` type are typed, just as in C, C++, Java, etc. for
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:
- 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
determined by some other member of the SET or SEQUENCE, and that will be
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.
- 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 `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
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.
As usual for ASN.1, the case of the first letter of a field name is meaningful:
- value and object field names start with a lower case letter;
- type, value set, and object set fields start with an upper-case letter;
- object and object set fields are also known as `link fields`.
The form of a `fixed type value` field and a `fixed type value set` field is
the same, differing only the case of the first letter of the field name.
Similarly for `variable type value` and `variable type value set` fields.
Similarly, again, for `object` and `object set` fields.
Here's a simple example from PKIX:
```ASN.1
-- An IOS class used to impose constraints on the PKIX Extension type:
EXTENSION ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&ExtnType,
&Critical BOOLEAN DEFAULT {TRUE | FALSE }
} WITH SYNTAX {
SYNTAX &ExtnType IDENTIFIED BY &id
[CRITICALITY &Critical]
}
```
- The `&id` field is a fixed-type value field. It's not a fixed-type value
_set_ field because its identifier (`id`) starts with a lower-case letter.
The `&id` field is intended to make the `extnId` member of the `Extension`
`SEQUENCE` type name identify the actual type of the `extnValue` member of
the same `SEQUENCE` type.
The `UNIQUE` keyword tells us there can be only one object with any given
value of this field in any object set of this class.
- The `&ExtnType` field is a type field. We can tell because no type is named
in its declaration.
- The `&Critical` field is a fixed-type value set field. We can tell because
it specifies a type (`BOOLEAN`) and starts with an upper-case letter.
- Ignore the `WITH SYNTAX` clause for now. All it does is specify a
user-friendly butimplementor-hostile syntax for specifying objects for this
class.
Note that none of the `Extension` extensions in PKIX actually specify
`CRITICALITY`/`&Critical`, so... we just don't need fixed-type value set
fields. We could elide the `&Critical` field of the `EXTENSION` class
altogether.
Here's another, much more complex example from PKIX:
```ASN.1
ATTRIBUTE ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&Type OPTIONAL,
&equality-match MATCHING-RULE OPTIONAL,
&minCount INTEGER DEFAULT 1,
&maxCount INTEGER OPTIONAL
}
MATCHING-RULE ::= CLASS {
&ParentMatchingRules MATCHING-RULE OPTIONAL,
&AssertionType OPTIONAL,
&uniqueMatchIndicator ATTRIBUTE OPTIONAL,
&id OBJECT IDENTIFIER UNIQUE
}
```
- For `ATTRIBUTE` the fields are:
- The `&id` field is a fixed-type value field (intended to name the type of
members linked to the `&Type` field).
- The `&Type` field is a type field (open type).
- The `&equality-match` is an object field linking to object sets of the
`MATCHING-RULE` class.
- The `minCount` and `maxCount` fields are fixed-type value fields.
- For `MATCHING-RULE` the fields are:
- The `&ParentMatchingRules` is an object set field linking to more
`MATCHING-RULE`s.
- The `&AssertionType` field is a type field (open type).
- The `&uniqueMatchIndicator` field is an object field linking back to some
object of the `ATTRIBUTE` class that indicates whether the match is
unique (presumably).
- The `&id` field is a fixed-type value field (intended to name the type of
members linked to the `&AssertionType` field).
No `Attribute`s in PKIX specify matching rules, so we really don't need support
for object nor object set fields.
Because
- no objects in object sets of `EXTENSION` in PKIX specify "criticality",
- and no objects in object sets of `ATTRIBUTE` in PKIX specify matching rules,
- and no matching rules are specified in PKIX.
we can drop `MATCHING-RULE` and simplify `ATTRIBUTE` and `EXTENSION` as:
```ASN.1
EXTENSION ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&ExtnType
}
ATTRIBUTE ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&Type OPTIONAL,
&minCount INTEGER DEFAULT 1,
&maxCount INTEGER OPTIONAL
}
```
X.681 has an example in appendix D.2 that has at least one field of every kind.
Again, the rubber that are IOS classes and object sets meet the road when
defining types:
```ASN.1
-- Define the Extension type but link it to the EXTENSION class so that
-- an object set for that class can constrain it:
Extension{EXTENSION:ExtensionSet} ::= SEQUENCE {
extnID EXTENSION.&id({ExtensionSet}),
critical BOOLEAN
(EXTENSION.&Critical({ExtensionSet}{@extnID}))
DEFAULT FALSE,
extnValue OCTET STRING (CONTAINING
EXTENSION.&ExtnType({ExtensionSet}{@extnID}))
}
-- Most members of TBSCertificate elided for brevity:
TBSCertificate ::= SEQUENCE {
...,
extensions [3] Extensions{{CertExtensions}} OPTIONAL
-- ^^^^^^^^^^^^^^^^
-- the rubber meets the road here!!
...
}
OTHER-NAME ::= TYPE-IDENTIFIER
-- Most members of GeneralName elided for brevity:
GeneralName ::= CHOICE {
otherName [0] INSTANCE OF OTHER-NAME({OtherNames}),
-- ^^^^^^^^^^^^
-- rubber & road meet!
...
}
```
(The `CertExtensions` and `OtherNames` object sets are not shown here for
brevity. PKIX doesn't even define an `OtherNames` object set, though it well
could.)
The above demonstrates two ways to create `SEQUENCE` types that are constrained
by IOS classes. One is by defining the types of the members of a `SEQUENCE`
type by reference to class fields. The other is by using `INSTANCE OF` to say
that the class defines the type directly. The first lets us do things like
have a mix members of a `SEQUENCE` type where some are defined by relation to a
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:
```ASN.1
SEQUENCE {
type-id <DefinedObjectClass>.&id,
value[0] <DefinedObjectClass>.&Type
}
-- where <DefinedObjectClass> is the name of the class, which has to be
-- `TYPE-IDENTIFIER` or exactly like it.
```
(This means we can't use `INSTANCE OF` with `EXTENSION`.)
PKIX has much more complex classes for relating and constraining cryptographic
algorithms and their parameters:
- `DIGEST-ALGORITHM`,
- `SIGNATURE-ALGORITHM`,
- `PUBLIC-KEY`,
- `KEY-TRANSPORT`,
- `KEY-AGREE`,
- `KEY-WRAP`,
- `KEY-DERIVATION`,
- `MAC-ALGORITHM`,
- `CONTENT-ENCRYPTION`,
- `ALGORITHM`,
- `SMIME-CAPS`,
- and `CURVE`.
These show the value of just the relational data aspect of IOS. They can not
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.