From 61607fa6ead78f7b64322d5211e31c532be9e6b4 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Mon, 14 Feb 2022 21:07:17 -0600 Subject: [PATCH] asn1: Add a GitHub Markdown manual (more) --- lib/asn1/MANUAL.md | 118 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 17 deletions(-) diff --git a/lib/asn1/MANUAL.md b/lib/asn1/MANUAL.md index 7e2849d96..89c452a03 100644 --- a/lib/asn1/MANUAL.md +++ b/lib/asn1/MANUAL.md @@ -577,17 +577,22 @@ values mean "absent", while non-`NULL` values mean "present"). 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: ```C -typedef struct TBSCertificate TBSCertificate; - -typedef struct Certificate { - TBSCertificate tbsCertificate; - AlgorithmIdentifier signatureAlgorithm; - heim_bit_string signatureValue; -} Certificate; - typedef struct TBSCertificate { heim_octet_string _save; /* see below! */ Version *version; @@ -601,6 +606,12 @@ typedef struct TBSCertificate { heim_bit_string *subjectUniqueID; Extensions *extensions; } 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 @@ -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 `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 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 > 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 -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 memory resources will be released. Note that the C object _itself_ is not freed, only its _content_. -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). +See [sample usage](#Using-the-Generated-APIs). 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 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 automatically validate cryptographic algorithm parameters. However, this is not that important. Another feature that might be nice is the ability of callers to specify smaller 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 -application. +mainly to avoid spending CPU cycles and memory allocations on decoding types in +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 -anyways, would make for a generally useful tool. +For testing purposes, a JSON reader to go with the JSON printer might be nice, +and anyways, would make for a generally useful tool. 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