asn1: Add a GitHub Markdown manual (more)

This commit is contained in:
Nicolas Williams
2022-02-14 21:07:17 -06:00
parent dda9aa2535
commit 61607fa6ea

View File

@@ -577,17 +577,22 @@ values mean "absent", while non-`NULL` values mean "present").
Tags are of no consequence to the C types generated. Tags are of no consequence to the C types generated.
Types definitions to be topographically sorted because of the need to have
forward declarations.
Forward `typedef` declarations are emmitted.
Circular type dependencies are allowed provided that `OPTIONAL` members are
used for enough circular references so as to avoid creating types whose values
have infinite size! (Circular type dependencies can be used to build linked
lists, though that is a bit of a silly trick when one can use arrays instead,
though in principle this could be used to do on-line encoding and decoding of
arbitrarily large streams of objects. See the [commentary](#Commentary)
section.)
Thus `Certificate` becomes: Thus `Certificate` becomes:
```C ```C
typedef struct TBSCertificate TBSCertificate;
typedef struct Certificate {
TBSCertificate tbsCertificate;
AlgorithmIdentifier signatureAlgorithm;
heim_bit_string signatureValue;
} Certificate;
typedef struct TBSCertificate { typedef struct TBSCertificate {
heim_octet_string _save; /* see below! */ heim_octet_string _save; /* see below! */
Version *version; Version *version;
@@ -601,6 +606,12 @@ typedef struct TBSCertificate {
heim_bit_string *subjectUniqueID; heim_bit_string *subjectUniqueID;
Extensions *extensions; Extensions *extensions;
} TBSCertificate; } TBSCertificate;
typedef struct Certificate {
TBSCertificate tbsCertificate;
AlgorithmIdentifier signatureAlgorithm;
heim_bit_string signatureValue;
} Certificate;
``` ```
The `_save` field in `TBSCertificate` is generated when the compiler is invoked The `_save` field in `TBSCertificate` is generated when the compiler is invoked
@@ -644,6 +655,75 @@ code-generators do, of course, so it's not surprising. But you can see that
- in C we use `typedef`s to make the type names usable without having to add - in C we use `typedef`s to make the type names usable without having to add
`struct` `struct`
## Circular Type Dependencies
As noted above, circular type dependencies are supported.
Here's a toy example from [XDR](https://datatracker.ietf.org/doc/html/rfc4506)
-- a linked list:
```XDR
struct stringentry {
string item<>;
stringentry *next;
};
typedef stringentry *stringlist;
```
Here is the same example in ASN.1:
```ASN.1
Stringentry ::= SEQUENCE {
item UTF8String,
next Stringentry OPTIONAL
}
```
which compiles to:
```C
typedef struct Stringentry Stringentry;
struct Stringentry {
char *item;
Stringentry *next;
};
```
This illustrates that `OPTIONAL` members in ASN.1 are like pointers in XDR.
Making the `next` member not `OPTIONAL` would cause `Stringentry` to be
infinitely large, and there is no way to declare the equivalent in C anyways
(`struct foo { int a; struct foo b; };` will not compile in C).
Mutual circular references are allowed too. In the following example `A`
refers to `B` and `B` refers to `A`, but as long as one (or both) of those
references is `OPTIONAL`, then it will be allowed:
```ASN1
A ::= SEQUENCE { name UTF8String, b B }
B ::= SEQUENCE { name UTF8String, a A OPTIONAL }
```
```ASN1
A ::= SEQUENCE { name UTF8String, b B OPTIONAL }
B ::= SEQUENCE { name UTF8String, a A }
```
```ASN1
A ::= SEQUENCE { name UTF8String, b B OPTIONAL }
B ::= SEQUENCE { name UTF8String, a A OPTIONAL }
```
In the above example values of types `A` and `B` together form a linked list.
Whereas this is broken and will not compile:
```ASN1
A ::= SEQUENCE { name UTF8String, b B }
B ::= SEQUENCE { name UTF8String, a A } -- infinite size!
```
## Generated APIs For Any Given Type T ## Generated APIs For Any Given Type T
The C functions generated for ASN.1 types are all of the same form, for any The C functions generated for ASN.1 types are all of the same form, for any
@@ -674,16 +754,20 @@ written.
> last byte in the buffer into which the encoder will encode the value. This > last byte in the buffer into which the encoder will encode the value. This
> is because the encoder encodes from the end towards the beginning. > is because the encoder encodes from the end towards the beginning.
The `print_T()` functions encode the value of a C object of type `T` in JSON
(though not in JER-compliant JSON). A sample printing of a complex PKIX
`Certificate` can be seen in [README.md#features](README.md#features).
The `copy_T()` functions take a pointer to a source C object of type `T` whose The `copy_T()` functions take a pointer to a source C object of type `T` whose
value they then copy to the destination C object of the same type. value they then copy to the destination C object of the same type. The copy
constructor is equivalent to encoding the source value and decoding it onto the
destination.
The `free_T()` functions take a pointer to a C object of type `T` whose value's The `free_T()` functions take a pointer to a C object of type `T` whose value's
memory resources will be released. Note that the C object _itself_ is not memory resources will be released. Note that the C object _itself_ is not
freed, only its _content_. freed, only its _content_.
The `print_T()` functions encode the value of a C object of type `T` in JSON See [sample usage](#Using-the-Generated-APIs).
(though not in JER-compliant JSON). A sample printing of a complex PKIX
`Certificate` can be seen in [README.md#features](README.md#features).
These functions are all recursive. These functions are all recursive.
@@ -1179,18 +1263,18 @@ HEIMDAL February 22, 2021 HEIMDAL
The Heimdal ASN.1 compiler is focused on PKIX and Kerberos, and is almost The Heimdal ASN.1 compiler is focused on PKIX and Kerberos, and is almost
feature-complete for dealing with those. It could use additional support for feature-complete for dealing with those. It could use additional support for
X.681/X.682/X.683 elements that would allow the compiler to implement X.681/X.682/X.683 elements that would allow the compiler to understand
`Certificate ::= SIGNED{TBSCertificate}`, particularly the ability to `Certificate ::= SIGNED{TBSCertificate}`, particularly the ability to
automatically validate cryptographic algorithm parameters. However, this is automatically validate cryptographic algorithm parameters. However, this is
not that important. not that important.
Another feature that might be nice is the ability of callers to specify smaller Another feature that might be nice is the ability of callers to specify smaller
information object sets when decoding values of types like `Certificate`, information object sets when decoding values of types like `Certificate`,
mainly to avoid decoding types in typed holes that are not of interest to the mainly to avoid spending CPU cycles and memory allocations on decoding types in
application. typed holes that are not of interest to the application.
For testing, a JSON reader to go with the JSON printer might be nice, and For testing purposes, a JSON reader to go with the JSON printer might be nice,
anyways, would make for a generally useful tool. and anyways, would make for a generally useful tool.
Another feature that would be nice would to automatically generate SQL and LDAP Another feature that would be nice would to automatically generate SQL and LDAP
code for HDB based on `lib/hdb/hdb.asn1` (with certain usage conventions and/or code for HDB based on `lib/hdb/hdb.asn1` (with certain usage conventions and/or