Commit Graph

27 Commits

Author SHA1 Message Date
Nicolas Williams
05a952dbb9 asn1: Fix IMPLICIT tagging (codegen) 2021-03-10 19:15:17 -06:00
Nicolas Williams
7f941b220b asn1: Basic validation of objects / object sets
- Validate that required value fields have values specified in objects

 - Validate that unique value fields have unique values within any
   object set
2021-02-28 18:15:57 -06:00
Nicolas Williams
db7763ca7b asn1: X.681/682/683 magic handling of open types
Status:

 - And it works!

 - We have an extensive test based on decoding a rich EK certficate.

   This test exercises all of:

    - decoding
    - encoding with and without decoded open types
    - copying of decoded values with decoded open types
    - freeing of decoded values with decoded open types

   Valgrind finds no memory errors.

 - Added a manual page for the compiler.

 - rfc2459.asn1 now has all three primary PKIX types that we care about
   defined as in RFC5912, with IOS constraints and parameterization:

    - `Extension`       (embeds open type in an `OCTET STRING`)
    - `OtherName`       (embeds open type in an        `ANY`-like type)
    - `SingleAttribute` (embeds open type in an        `ANY`-like type)
    - `AttributeSet`    (embeds open type in a  `SET OF ANY`-like type)

   All of these use OIDs as the open type type ID field, but integer
   open type type ID fields are also supported (and needed, for
   Kerberos).

   That will cover every typed hole pattern in all our ASN.1 modules.

   With this we'll be able to automatically and recursively decode
   through all subject DN attributes even when the subject DN is a
   directoryName SAN, and subjectDirectoryAttributes, and all
   extensions, and all SANs, and all authorization-data elements, and
   PA-data, and...

   We're not really using `SingleAttribute` and `AttributeSet` yet
   because various changes are needed in `lib/hx509` for that.

 - `asn1_compile` builds and recognizes the subset of X.681/682/683 that
   we need for, and now use in, rfc2459.asn1.  It builds the necessary
   AST, generates the correct C types, and generates templating for
   object sets and open types!

 - See READMEs for details.

 - Codegen backend not tested; I won't make it implement automatic open
   type handling, but it should at least not crash by substituting
   `heim_any` for open types not embedded in `OCTET STRING`.

 - We're _really_ starting to have problems with the ITU-T ASN.1
   grammar and our version of it...

   Type names have to start with upper-case, value names with
   lower-case, but it's not enough to disambiguate.

   The fact the we've allowed value and type names to violate their
   respective start-with case rules is causing us trouble now that we're
   adding grammar from X.681/682/683, and we're going to have to undo
   that.

   In preparation for that I'm capitalizing the `heim_any` and
   `heim_any_set` types, and doing some additional cleanup, which
   requires changes to other parts of Heimdal (all in this same commit
   for now).

   Problems we have because of this:

    - We cannot IMPORT values into modules because we have no idea if a
      symbol being imported refers to a value or a type because the only
      clue we would have is the symbol's name, so we assume IMPORTed
      symbols are for types.

      This means we can't import OIDs, for example, which is super
      annoying.

      One thing we might be able to do here is mark imported symbols as
      being of an undetermined-but-not-undefined type, then coerce the
      symbol's type the first time it's used in a context where its type
      is inferred as type, value, object, object set, or class.  (Though
      since we don't generate C symbols for objects or classes, we won't
      be able to import them, especially since we need to know them at
      compile time and cannot defer their handling to link- or
      run-time.)

    - The `NULL` type name, and the `NULL` value name now cause two
      reduce/reduce conflicts via the `FieldSetting` production.

    - Various shift/reduce conflicts involving `NULL` values in
      non-top-level contexts (in constraints, for example).

 - Currently I have a bug where to disambiguate the grammar I have a
   CLASS_IDENTIFIER token that is all caps, while TYPE_IDENTIFIER must
   start with a capital but not be all caps, but this breaks Kerberos
   since all its types are all capitalized -- oof!

   To fix this I made it so class names have to be all caps and
   start with an underscore (ick).

TBD:

 - Check all the XXX comments and address them
 - Apply this treatment to Kerberos!  Automatic handling of authz-data
   sounds useful :)
 - Apply this treatment to PKCS#10 (CSRs) and other ASN.1 modules too.
 - Replace various bits of code in `lib/hx509/` with uses of this
   feature.
 - Add JER.
 - Enhance `hxtool` and `asn1_print`.

Getting there!
2021-02-28 18:13:08 -06:00
Nicolas Williams
89389bc7a0 asn1: Fix long-standing IMPLICIT tagging brokenness
This commit _mostly_ fixes the Heimdal ASN.1 compiler to properly
support IMPLICIT tagging in most if not all the many cases where it
didn't already, as you could see in lib/asn1/canthandle.asn1 prior to
this commit.

This fix is a bit of a hack in that a proper fix would change the
function prototypes of the encode/decode/length functions generated by
the compiler to take an optional IMPLICIT tag to tag with instead of the
type they code.  That fix would not be localized to lib/asn1/ however,
and would change the API and ABI of generated code (which is mostly not
an ABI for Heimdal, but still, some external projects would have to make
changes).

Instead, for IMPLICIT tags we currently depend on the IMPLICIT tag and
the sub-type's tag having the same size -- this can be fixed with extra
allocation on the encoder side as we do on the decoder side, but we
might leave it for later.

The issue we're fixing manifested as:

  -- The [CONTEXT 0] tag in Bar below was turned into an EXPLICIT tag
  -- instead of an IMPLICIT one, netting the DER encoding for the `foo`
  -- member as:
  --    [CONTEXT 0] [UNIVERSAL Seq] [UNIVERSAL Int] <encoding of i>
  -- instead of the correct:
  --    [CONTEXT 0] [UNIVERSAL Int] <encoding of i>
  Foo ::= SEQUENCE { i INTEGER }
  Bar ::= SEQUENCE { foo [0] IMPLICIT Foo }

or

  Foo ::= INTEGER
  Bar ::= SEQUENCE { foo [0] IMPLICIT Foo } -- tag context 0 marked
                                            -- constructed!

I've reviewed this in part by reviewing the output of the compiler
before and after this change using this procedure:

 - Run an earlier version of the ASN.1 compiler output for all
   modules in lib/asn1/.  Save these in a different location.

 - Run this (or later) version of the ASN.1 compiler output for
   the same modules, adding --original-order for modules that
   have been manually sorted already (e.g., rfc2459.asn1).

 - Run clang-format on the saved and newest generated C source
   and header files.

 - Diff the generated output.  Substantial differences will
   relate to handling of IMPLICIT tagging.  These are
   particularly evident in the tcg.asn1 module, which uses a lot
   of those.

Later commits add test data (certificates with extensions that use
IMPLICIT tagging) taken from external specifications as well, which
exercise this fix.

Non-urgent brokenness yet to be fixed:

 - When the IMPLICIT tag and the tag of the underlying type require
   differing numbers of bytes to encode, the encoding and decoding will
   fail.  The prototypes of generated length_*() functions make it
   impossible to do much better.

 - SET OF <primitive> still crashes the compiler (not a new bug).

Futures:

 - Unwind hackery in cms.asn1 that worked around our lack of proper
   IMPLICIT tagging support.

Here are some of the generated code deltas one expects to see around
this commit:

$ git checkout $earlier_version
$ ./autogen.sh
$ mkdir build
$ cd build
$ ../configure ...
$ make -j4
$ make check
$ cd lib/asn1
$ for i in *.c; do
      [[ $i = asn1parse.? || $i = lex.? || $i = *.h ]] && continue
      clang-format -i $i $i
      cmp /tmp/save/$i $i && echo NO DIFFS: $i && continue; echo DIFF: $i
  done
NO DIFFS: asn1_cms_asn1.c
NO DIFFS: asn1_digest_asn1.c
NO DIFFS: asn1_err.c
NO DIFFS: asn1_krb5_asn1.c
/tmp/save/asn1_kx509_asn1.c asn1_kx509_asn1.c differ: byte 6433, line 264
DIFF: asn1_kx509_asn1.c
NO DIFFS: asn1_ocsp_asn1.c
NO DIFFS: asn1_pkcs10_asn1.c
/tmp/save/asn1_pkcs12_asn1.c asn1_pkcs12_asn1.c differ: byte 12934, line 455
DIFF: asn1_pkcs12_asn1.c
NO DIFFS: asn1_pkcs8_asn1.c
NO DIFFS: asn1_pkcs9_asn1.c
NO DIFFS: asn1_pkinit_asn1.c
/tmp/save/asn1_rfc2459_asn1.c asn1_rfc2459_asn1.c differ: byte 20193, line 532
DIFF: asn1_rfc2459_asn1.c
NO DIFFS: asn1_rfc4043_asn1.c
/tmp/save/asn1_rfc4108_asn1.c asn1_rfc4108_asn1.c differ: byte 595, line 26
DIFF: asn1_rfc4108_asn1.c
/tmp/save/asn1_tcg_asn1.c asn1_tcg_asn1.c differ: byte 31835, line 1229
DIFF: asn1_tcg_asn1.c
/tmp/save/asn1_test_asn1.c asn1_test_asn1.c differ: byte 384, line 21
DIFF: asn1_test_asn1.c
/tmp/save/test_template_asn1-template.c test_template_asn1-template.c differ: byte 650, line 20
DIFF: test_template_asn1-template.c
$
$ cd ../..
$ git checkout $newer_version
$ make -j4 && make check
$ cd lib/asn1
$ for i in *.[ch]; do
    [[ $i = asn1parse.? || $i = lex.? || $i = *.h ]] && continue
    clang-format -i $i $i
    cmp /tmp/save/$i $i && echo NO DIFFS: $i && continue
    diff -ubw /tmp/save/$i $i
  done | $PAGER

and one should see deltas such as the following:

 - a small enhancement to handling of OPTIONAL members:

     (data)->macData = calloc(1, sizeof(*(data)->macData));
     if ((data)->macData == NULL)
       goto fail;
     e = decode_PKCS12_MacData(p, len, (data)->macData, &l);
-    if (e) {
+    if (e == ASN1_MISSING_FIELD) {
       free((data)->macData);
       (data)->macData = NULL;
+    } else if (e) {
+      goto fail;
     } else {
       p += l;
       len -= l;
       ret += l;

 - more complete handling of DEFAULTed members:

     e = decode_FWReceiptVersion(p, len, &(data)->version, &l);
-    if (e)
+    if (e == ASN1_MISSING_FIELD) {
+      (data)->version = 1;
+    } else if (e) {
       goto fail;
-    p += l;
-    len -= l;
-    ret += l;
+    } else {
+      p += l;
+      len -= l;
+      ret += l;
+    }
     {

 - replacement of tags with implicit tags (encode side):

   /* targetUri */
   if ((data)->targetUri) {
     size_t Top_tag_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;
     ret = 0;
     e = encode_URIReference(p, len, (data)->targetUri, &l);
     if (e)
       return e;
     p -= l;
     len -= l;
     ret += l;

-    e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, PRIM, 4, &l);
+    e = der_replace_tag(p, len, ASN1_C_CONTEXT, CONS, 4);
     if (e)
       return e;
     p -= l;
     len -= l;
     ret += l;

     ret += Top_tag_oldret;
   }

 - replacement of tags with implicit tags (decode side):

         strengthOfFunction_oldlen = len;
         if (strengthOfFunction_datalen > len) {
           e = ASN1_OVERRUN;
           goto fail;
         }
         len = strengthOfFunction_datalen;
-        e = decode_StrengthOfFunction(p, len, (data)->strengthOfFunction, &l);
-        if (e)
-          goto fail;
-        p += l;
-        len -= l;
-        ret += l;
+        {
+          unsigned char *pcopy;
+          pcopy = calloc(1, len);
+          if (pcopy == 0) {
+            e = ENOMEM;
+            goto fail;
+          }
+          memcpy(pcopy, p, len);
+          e = der_replace_tag(pcopy, len, ASN1_C_UNIV, PRIM, 0);
+          if (e)
+            goto fail;
+          e = decode_StrengthOfFunction(p, len, (data)->strengthOfFunction, &l);
+          if (e)
+            goto fail;
+          p += l;
+          len -= l;
+          ret += l;
+          free(pcopy);
+        }
         len = strengthOfFunction_oldlen - strengthOfFunction_datalen;
       }
     }
     {
       size_t profileOid_datalen, profileOid_oldlen;

 - correct determination of implicit tag constructed vs no for IMPLICT-
   tagged named primitive types:

     {
       size_t profileUri_datalen, profileUri_oldlen;
       Der_type profileUri_type;
       e = der_match_tag_and_length(p, len, ASN1_C_CONTEXT, &profileUri_type, 2,
                                    &profileUri_datalen, &l);
-      if (e == 0 && profileUri_type != PRIM) {
+      if (e == 0 && profileUri_type != CONS) {
         e = ASN1_BAD_ID;
       }
       if (e) {
         (data)->profileUri = NULL;
       } else {
         (data)->profileUri = calloc(1, sizeof(*(data)->profileUri));
         if ((data)->profileUri == NULL) {
           e = ENOMEM;
           goto fail;
         }

 - correct determination of length of IMPLICT-tagged OIDs:

   if ((data)->profileOid) {
     size_t Top_tag_oldret = ret;
     ret = 0;
     ret += der_length_oid((data)->profileOid);
+    ret += 1 + der_length_len(ret);
     ret += Top_tag_oldret;
   }

These deltas should be examined with the corresponding ASN.1 module at
hand, cross-referencing the source code to the ASN.1 type definitions
and manually applying X.690 rules to double-check the choices of
primitive vs. constructed tag, and the choices of when to replace tags
and when not.
2021-01-13 20:17:58 -06:00
Nicolas Williams
83d4c6ddb5 asn1: Circular types and Topo. sort declarations
Many external ASN.1 modules that we have imported over time define types
like this:

  Foo ::= SEQUENCE { bar Bar }
  Bar ::= SEQUENCE { aMember INTEGER }

and before this change one had to re-order the definitions so that the
one for `Bar` came first.  No more.

We can now have out of order definitions in ASN.1 modules and the
compiler will topologically sort output C type declarations so that one
no longer has to manually sort types in ASN.1 modules when importing
them.

Besides that, it is now possible to create circular data types using
OPTIONAL since we generate such fields as pointers (which can then be
pointers to incomplete struct declarations):

  Circular ::= SEQUENCE {
          name UTF8String,
          next Circular OPTIONAL
  }

Circular types aren't necessarily useful, but they have been used in the
past.  E.g., the rpc.mountd protocol uses a circular type as a linked
list -- it should just have used an array, of course, as that's
semantically equivalent but more space efficient in its encoding, but
the point is that such types exist out there.
2021-01-13 20:17:58 -06:00
Nicolas Williams
45451814b3 asn1: Add breadcrumbs for future work 2020-12-16 15:12:00 -06:00
Andrew Bartlett
ccc4302a18 lib/asn1: Add extern to declaration of fuzzer string in gen_locl.h 2014-03-24 23:07:51 -05:00
Love Hornquist Astrand
060474df16 quel 64bit warnings, fixup implicit encoding for template, fix spelling 2013-06-03 21:46:20 -07:00
Love Hornquist Astrand
b939943b07 first stange of asn1 table driven compiler 2009-11-21 10:24:56 -08:00
Love Hörnquist Åstrand
b29554715f rename dce-stype to support_ber
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@24605 ec53bebd-3082-4978-b11e-865c3cabbd6b
2009-02-04 22:08:41 +00:00
Love Hörnquist Åstrand
0179e12d54 remove -DHAVE_CONFIG_H, add --one-source-file, rename krb5 and cms to "better" file names
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@24337 ec53bebd-3082-4978-b11e-865c3cabbd6b
2009-01-25 00:23:39 +00:00
Love Hörnquist Åstrand
6937d41a02 remove trailing whitespace
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@23815 ec53bebd-3082-4978-b11e-865c3cabbd6b
2008-09-13 09:21:03 +00:00
Love Hörnquist Åstrand
e172367898 switch to utf8 encoding of all files
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@23814 ec53bebd-3082-4978-b11e-865c3cabbd6b
2008-09-13 08:53:55 +00:00
Love Hörnquist Åstrand
3c380109e4 add new prototypes, remove unused ones.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@18008 ec53bebd-3082-4978-b11e-865c3cabbd6b
2006-09-05 12:29:18 +00:00
Love Hörnquist Åstrand
dd65561899 Remove argument names, no functional change.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@15958 ec53bebd-3082-4978-b11e-865c3cabbd6b
2005-08-23 10:48:15 +00:00
Love Hörnquist Åstrand
b838707d0e Commit much improved ASN.1 compiler from joda-choice-branch.
Highlighs for the compiler is support for CHOICE and in general better
support for tags. This compiler support most of what is needed for
PK-INIT, LDAP, X.509, PKCS-12 and many other protocols.


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@15617 ec53bebd-3082-4978-b11e-865c3cabbd6b
2005-07-12 06:27:42 +00:00
Love Hörnquist Åstrand
53ac3a20b2 make scope variables unique to avoid shadow warnings
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@15614 ec53bebd-3082-4978-b11e-865c3cabbd6b
2005-07-10 05:13:09 +00:00
Love Hörnquist Åstrand
491a812d67 rename function filename to get_filename
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@15439 ec53bebd-3082-4978-b11e-865c3cabbd6b
2005-06-16 19:58:58 +00:00
Assar Westerlund
cee81d995f remove libasn1.h
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@10750 ec53bebd-3082-4978-b11e-865c3cabbd6b
2001-09-27 16:23:15 +00:00
Assar Westerlund
2bcae56ac3 add ENUMERATED and OBJECT IDENTIFIER
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@10741 ec53bebd-3082-4978-b11e-865c3cabbd6b
2001-09-25 13:39:27 +00:00
Assar Westerlund
effdd6d882 (filename): add prototype
(init_generate): const-ize


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@8155 ec53bebd-3082-4978-b11e-865c3cabbd6b
2000-04-09 09:21:56 +00:00
Johan Danielsson
c5b916ca6f remove advertising clause
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@7464 ec53bebd-3082-4978-b11e-865c3cabbd6b
1999-12-02 17:05:13 +00:00
Assar Westerlund
a74d27d3d7 const-ize
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@7130 ec53bebd-3082-4978-b11e-865c3cabbd6b
1999-10-10 04:55:28 +00:00
Assar Westerlund
0ddcf2db1b generate_glue
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@3247 ec53bebd-3082-4978-b11e-865c3cabbd6b
1997-08-28 23:18:41 +00:00
Johan Danielsson
0ac49b3286 Update prototype for init_generate.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@2478 ec53bebd-3082-4978-b11e-865c3cabbd6b
1997-07-20 00:10:45 +00:00
Johan Danielsson
5a32a5c8e7 Add copyright notice.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@2389 ec53bebd-3082-4978-b11e-865c3cabbd6b
1997-07-16 21:40:05 +00:00
Assar Westerlund
c1439d2cd8 changed asn1_locl.h to gen_locl.h and der_locl.h
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@2328 ec53bebd-3082-4978-b11e-865c3cabbd6b
1997-07-15 20:02:05 +00:00