diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /third_party/heimdal/lib/asn1 | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/heimdal/lib/asn1')
92 files changed, 39431 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/asn1/ChangeLog b/third_party/heimdal/lib/asn1/ChangeLog new file mode 100644 index 0000000..523e24b --- /dev/null +++ b/third_party/heimdal/lib/asn1/ChangeLog @@ -0,0 +1,1665 @@ +2008-04-09 Love Hörnquist Åstrand <lha@it.su.se> + + * pkinit.asn1: add id-pkinit-kdf + + * pkinit.asn1: add PkinitSP80056AOtherInfo + +2008-04-07 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c: Use unsigned where appropriate. + +2008-03-22 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: Match name in ClientCanonicalizedNames with -10 + + * k5.asn1: add referral-valid-until + +2008-01-13 Love Hörnquist Åstrand <lha@it.su.se> + + * asn1-common.h gen.c der.c gen_encode.c: add and use der_{malloc,free} + +2007-12-13 Love Hörnquist Åstrand <lha@it.su.se> + + * libasn1.h: remove, not used. + +2007-12-04 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add DigestTypes, add --seq to antoher type. + + * digest.asn1: Add supportedMechs request. + +2007-10-18 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: Some "old" windows enctypes. From Andy Polyakov. + +2007-07-23 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Fold in pk-init-alg-agilty. + + * pkinit.asn1: Fold in pk-init-alg-agilty. + +2007-07-16 Love Hörnquist Åstrand <lha@it.su.se> + + * parse.y: Passe object id is its part of the module defintion + statement. + +2007-07-14 Love Hörnquist Åstrand <lha@it.su.se> + + * check-gen.c: test SEQ OF SIZE (...) + + * Makefile.am: Include more sizeof tests. + +2007-07-12 Love Hörnquist Åstrand <lha@it.su.se> + + * try to avoid aliasing of pointers enum {} vs int + +2007-07-10 Love Hörnquist Åstrand <lha@it.su.se> + + * test.asn1: Test SIZE attribute for SEQ and OCTET STRING + + * parse.y (OctetStringType): add SIZE to OCTET STRING. + + * Makefile.am: New library version. + +2007-07-02 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: Re-add size limits. + + * k5.asn1: Add size limits from RFC 4120. + + * gen_decode.c: Check range on SEQ OF and OCTET STRING. + + * asn1_err.et (min|max|exact) constraints. + + * parse.y: Parse size limitations to SEQ OF. + +2007-06-28 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add AuthorityInfoAccessSyntax. + + * rfc2459.asn1: Add AuthorityInfoAccessSyntax. + + * rfc2459.asn1: Add authorityInfoAccess, rename proxyCertInfo. + + * Makefile.am: Add authorityInfoAccess, rename proxyCertInfo. + +2007-06-27 Love Hörnquist Åstrand <lha@it.su.se> + + * der_get.c (der_get_time): avoid using wrapping of octet_string + and realloc. + + * der_get.c: No need to undef timetm, we don't use it any more. + + * timegm.c: Fix spelling caused by too much query-replace. + + * gen.c: Include <limits.h> for UINT_MAX. + + * gen_decode.c: Check for multipication overrun. + + * gen_encode.c: Paranoia check in buffer overun in output + function. + + * check-der.c: Test boolean. + + * check-der.c: test universal strings. + + * check-der.c: Test failure cases for der_get_tag. + + * check-der.c: test dates from last century. + + * check-der.c: Move zero length integercheck to a better place. + + * check-der.c: Test zero length integer. + +2007-06-18 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: Init data to something. + +2007-06-15 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: Add KRB5-AUTHDATA-INITIAL-VERIFIED-CAS. + +2007-06-13 Love Hörnquist Åstrand <lha@it.su.se> + + * pkinit.asn1: Make the pkinit nonce signed (like the kerberos + nonce). + +2007-06-03 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: Free more memory. + + * der_format.c: Don't accect zero length hex numbers. + + * check-der.c: Also free right memory. + + * main.c: Close asn1 file when done. + + * check-der.c: more check for der_parse_hex_heim_integer + + * der_format.c (der_parse_hex_heim_integer): check length before + reading data. + + * check-gen.c (test_authenticator): free memory + +2007-05-31 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add MS-UPN-SAN + + * pkinit.asn1: add MS-UPN-SAN + + * rfc2459.asn1: Do evil things to handle IMPLICIT encoded + structures. Add id-ms-client-authentication. + +2007-05-30 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add asn1_id_ms_cert_enroll_domaincontroller.x + +2007-05-10 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c: Add struct units; as a forward declaration. Pointed out + by Marcus Watts. + + * rfc2459.asn1: Netscape extentions + + * Makefile.am: add U.S. Federal PKI Common Policy Framework + + * rfc2459.asn1: add U.S. Federal PKI Common Policy Framework + +2007-04-24 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_seq.c: Handle the case of resize to 0 and realloc that + returns NULL. + + * check-gen.c (check_seq): free seq. + +2007-04-19 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c (test_heim_oid_format_same): avoid leaking memory in + the non failure case too + +2007-04-16 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: remove extra ^Q + +2007-04-11 Love Hörnquist Åstrand <lha@it.su.se> + + * der_get.c: Allow trailing NULs. We allow this since MIT Kerberos + sends an strings in the NEED_PREAUTH case that includes a trailing + NUL. + +2007-02-17 Love Hörnquist Åstrand <lha@it.su.se> + + + * Makefile.am: Add PA-ClientCanonicalized and friends. + + * k5.asn1: Add PA-ClientCanonicalized and friends. + +2007-02-08 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: Drop one over INT_MAX test-case. + +2007-02-05 Love Hörnquist Åstrand <lha@it.su.se> + + * pkinit.asn1: add id-pkinit-ms-eku + + * pkinit.asn1: fill in more bits of id-pkinit-ms-san + +2007-02-02 Love Hörnquist Åstrand <lha@it.su.se> + + * digest.asn1: rename hash-a1 to session key + +2007-02-01 Love Hörnquist Åstrand <lha@it.su.se> + + * digest.asn1: Add elements to send in requestResponse to KDC and + get status of the request. + +2007-01-31 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: seq rules for CRLDistributionPoints + +2007-01-30 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add CRLDistributionPoints and friends + +2007-01-20 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: check BMPstring oddlength more + + * check-der.c: Test for NUL char in string in GENERAL STRING. + + * der_get.c: Check for NUL characters in string and return + ASN1_BAD_CHARACTER error-code if we find them. + + * asn1_err.et: Add BAD_CHARACTER error. + +2007-01-16 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add id-at-streetAddress. + + * rfc2459.asn1: Add id-at-streetAddress. + +2007-01-12 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: Add PKIXXmppAddr and id-pkix-on-xmppAddr. + +2006-12-30 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add id-pkix-kp oids. + + * rfc2459.asn1: Add id-pkix-kp oids. + +2006-12-29 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_encode.c: Named bit strings have this horrible, disgusting, + compress bits until they are no longer really there but stuff in + an initial octet anyway encoding scheme. Try to get it right and + calculate the initial octet runtime instead of compiletime. + + * check-gen.c: Check all other silly bitstring combinations. + + * Makefile.am: Add --sequence=Extensions to rfc2459. + +2006-12-28 Love Hörnquist Åstrand <lha@it.su.se> + + * kx509.asn1: Add kx509. + + * Makefile.am: Add kx509. + + * Add VisibleString parsing + +2006-12-15 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add ntlm files. + + * digest.asn1: Add bits for handling NTLM. + +2006-12-08 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add pkix proxy cert policy lang oids + + * rfc2459.asn1: add pkix proxy cert policy lang oids + +2006-12-07 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: unbreak id-pe-proxyCertInfo + + * rfc2459.asn1: Add id-pkix-on-dnsSRV and related oids + +2006-11-28 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add explicit depenency to LIB_roken for libasn1.la, + make AIX happy. + +2006-11-27 Love Hörnquist Åstrand <lha@it.su.se> + + * der_format.c (der_print_heim_oid): oid with zero length is + invalid, fail to print. + +2006-11-24 Love Hörnquist Åstrand <lha@it.su.se> + + * der_format.c (der_print_heim_oid): use delim when printing. + +2006-11-21 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: Make KRB5-PADATA-S4U2SELF pa type 129. + +2006-10-24 Love Hörnquist Åstrand <lha@it.su.se> + + * asn1_err.et: add EXTRA_DATA + +2006-10-21 Love Hörnquist Åstrand <lha@it.su.se> + + * check-gen.c: avoid leaking memory + + * check-der.c: avoid leaking memory + + * der_format.c (der_parse_heim_oid): avoid leaking memory + + * check-common.c: Print size_t as (unsigned long) and cast. + + * check-common.c: Try to align data, IA64's gets upset if its + unaligned. + + * lex.l: add missing */ + + * lex.c: need %e for hpux lex + +2006-10-20 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: remove dups from gen_files_test, add check-timegm. + + * Makefile.am: include more test.asn1 built files + + * Makefile.am: More files, now for make check. + +2006-10-19 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add missing files + + * Makefile.am (asn1_compile_SOURCES): add gen_locl.h + + * check-timegm.c: Add check for _der_timegm. + + * der_get.c (generalizedtime2time): always use _der_timegm. + + * timegm.c: make more strict + + * der_locl.h: Rename timegm to _der_timegm. + +2006-10-17 Love Hörnquist Åstrand <lha@it.su.se> + + * timegm.c: vJust fail if tm_mon is out of range for now XXXX this + is wrong. + +2006-10-16 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: extra depencies on der-protos.h + +2006-10-14 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: Prefix primitive types with der_. + + * timegm.c: rename the buildin timegm to _der_timegm + + * heim_asn1.h: move prototype away from here. + + * der_format.c: Add der_parse_heim_oid + + * gen_free.c: prefix primitive types with der_ + + * der_copy.c: prefix primitive types with der_ + + * gen_length.c: prefix primitive types with der_ + + * der_length.c: prefix primitive types with der_ + + * der_cmp.c: prefix primitive types with der_ + + * gen_free.c: prefix primitive types with der_ + + * der_free.c: prefix primitive types with der_ + + * gen_copy.c: prefix primitive types with der_ + + * der_copy.c: rename copy_ to der_copy_ + + * Makefile.am: Add der-protos.h to nodist_include_HEADERS. + + * der.h: use newly built <der-protos.h> + + * Makefile.am: Generate der prototypes. + + * gen.c: move any definitions here. + + * asn1-common.h: move any definitions here. + + * der.h: remove der_parse_oid prototype, it was never implemented. + + * der.h: New der_print_heim_oid signature. Test + der_parse_heim_oid + + * check-der.c: New der_print_heim_oid signature. Test + der_parse_heim_oid + +2006-10-07 Love Hörnquist Åstrand <lha@it.su.se> + + * lex.l: Grow an even larger output table size. + + * Makefile.am: split build files into dist_ and noinst_ SOURCES + +2006-10-04 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_seq.c: In generation of remove_TYPE: if you just removed the + last element, you must not memmove memory beyond the array. From + Andrew Bartlett + +2006-10-01 Love Hörnquist Åstrand <lha@it.su.se> + + * lex.l: Grow (%p, %a, %n) tables for Solaris 10 lex. From Harald + Barth. + +2006-09-24 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c (decode_type): drop unused variable realtype. + +2006-09-11 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add KRB5SignedPath and friends. + + * k5.asn1: Add KRB5SignedPath and friends. + + * Makefile.am: Add new sequence generation for GeneralNames. + +2006-09-07 Love Hörnquist Åstrand <lha@it.su.se> + + * CMS.asn1 (CMSVersion): rename versions from v0 to CMSVersion_v0, + ... + +2006-09-05 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add TESTSeqOf for testing sequence generation code. + + * check-gen.c: Add sequence tests. + + * test.asn1: Add TESTSeqOf for testing sequence generation code. + + * gen_seq.c: fix warning. + + * gen_seq.c: make generated data work + + * setchgpw2.asn1: enctype is part of the krb5 module now, use that + instead of locally defining it. + + * Makefile.am: asn1_compile += gen_seq.c + + * gen_locl.h: add new prototypes, remove unused ones. + + * gen.c: Generate sequence function. + + * main.c: add --sequence + + * gen_seq.c: Add generated add_ and remove_ for "SEQUENCE OF + TType". I'm tried of writing realloc(foo->data, + sizeof(foo->data[0]) + (foo->len + 1)); Only generated for those + type that is enabled by the command flag --sequence. + +2006-08-25 Love Hörnquist Åstrand <lha@it.su.se> + + * digest.asn1 (DigestRequest): add authid + + * digest.asn1: Comment describing on how to communicate the sasl + int/conf mode. + +2006-08-23 Love Hörnquist Åstrand <lha@it.su.se> + + * digest.asn1: Add some missing fields needed for digest. + +2006-08-21 Love Hörnquist Åstrand <lha@it.su.se> + + * digest.asn1: Tweak to make consisten and more easier to use. + +2006-07-20 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Remove CMS symmetric encryption support. Add + DigestProtocol. + + * digest.asn1: DigestProtocol + + * k5.asn1: Remove CMS symmetric encryption support. + +2006-06-22 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c (check_fail_heim_integer): disable test + + * der_get.c (der_get_heim_integer): revert part of previous + + * der_get.c (der_get_heim_integer): Add more checks + + * asn1_print.c: Add printing of bignums and use der_print_heim_oid + + * check-der.c (test_heim_oid_format_same): add printing on failure + + * check-der.c: Add one check for heim_int, add checking for oid + printing + +2006-06-06 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Impersonation support bits (and sort) + + * k5.asn1: Impersonation support bits. + +2006-05-13 Love Hörnquist Åstrand <lha@it.su.se> + + * der_format.c (der_parse_hex_heim_integer): avoid shadowing. + +2006-04-29 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add ExternalPrincipalIdentifiers, shared between + several elements. + + * pkinit.asn1: Add ExternalPrincipalIdentifiers, shared between + several elements. + +2006-04-28 Love Hörnquist Åstrand <lha@it.su.se> + + * parse.y: Add missing ;'s, found by bison on a SuSE 8.2 machine. + +2006-04-26 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add definitions from RFC 3820, Proxy Certificate + Profile. + + * rfc2459.asn1: Add definitions from RFC 3820, Proxy Certificate + Profile. + +2006-04-24 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: Add id-Userid + + * Makefile.am: Add UID and email + + * pkcs9.asn1: Add id-pkcs9-emailAddress + + * Makefile.am: Add attribute type oids from X520 and RFC 2247 DC + oid + + * rfc2459.asn1: Add attribute type oids from X520 and RFC 2247 DC + oid + +2006-04-21 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add sha-1 and sha-2 + + * rfc2459.asn1: add sha-1 and sha-2 + +2006-04-15 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add id-pkcs1-sha256WithRSAEncryption and friends + + * rfc2459.asn1: Add id-pkcs1-sha256WithRSAEncryption and friends + + * CMS.asn1: Turn CMSRC2CBCParameter.rc2ParameterVersion into a + constrained integer + +2006-04-08 Love Hörnquist Åstrand <lha@it.su.se> + + * hash.c (hashtabnew): check for NULL before setting structure. + Coverity, NetBSD CID#4 + +2006-03-31 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: gen_files_rfc2459 += asn1_ExtKeyUsage.x + + * rfc2459.asn1: Add ExtKeyUsage. + + * gen.c (generate_header_of_codefile): remove unused variable. + +2006-03-30 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c: Put all the IMPORTed headers into the headerfile to avoid + hidden depencies. + +2006-03-27 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add id-pkinit-ms-san. + + * pkinit.asn1: Add id-pkinit-ms-san. + + * k5.asn1 (PADATA-TYPE): Add KRB5-PADATA-PA-PK-OCSP-RESPONSE + +2006-03-26 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add pkinit-san. + + * pkinit.asn1: Rename id-pksan to id-pkinit-san + +2006-03-08 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c (init_generate): Nothing in the generated files needs + timegm(), so no need to provide a prototype for it. + +2006-02-13 Love Hörnquist Åstrand <lha@it.su.se> + + * pkinit.asn1: paChecksum is now OPTIONAL so it can be upgraded to + something better then SHA1 + +2006-01-31 Love Hörnquist Åstrand <lha@it.su.se> + + * extra.c: Stub-generator now generates alloc statements for + tagless ANY OPTIONAL, remove workaround. + + * check-gen.c: check for "tagless ANY OPTIONAL" + + * test.asn1: check for "tagless ANY OPTIONAL" + +2006-01-30 Love Hörnquist Åstrand <lha@it.su.se> + + * der.h: UniversalString and BMPString are both implemented. + + * der.h: Remove , after the last element of enum. + + * asn1_gen.c: Spelling. + +2006-01-20 Love Hörnquist Åstrand <lha@it.su.se> + + * der_length.c (length_heim_integer): Try handle negative length + of integers better. + + * der_get.c (der_get_heim_integer): handle negative integers. + + * check-der.c: check heim_integer. + +2006-01-18 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Its cRLReason, not cRLReasons + + * canthandle.asn1: "Allocation is done on CONTEXT tags" works just + fine. + + * rfc2459.asn1: Add CRL structures and OIDs. + + * Makefile.am: Add CRL and TESTAlloc structures and OIDs. + + * check-gen.c: Check OPTIONAL context-tagless elements. + + * test.asn1: Check OPTIONAL context-tagless elements. + + * der_cmp.c (heim_integer_cmp): make it work with negative + numbers. + +2006-01-17 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: check that der_parse_hex_heim_integer() handles odd + length numbers. + + * der_format.c (der_parse_hex_heim_integer): make more resiliant + to errors, handle odd length numbers. + +2006-01-13 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add RSAPrivateKey + + * rfc2459.asn1: Add RSAPrivateKey. + +2006-01-05 Love Hörnquist Åstrand <lha@it.su.se> + + * der_copy.c (copy_heim_integer): copy the negative flag + +2005-12-14 Love Hörnquist Åstrand <lha@it.su.se> + + * parse.y: Drop ExceptionSpec for now, its not used. + +2005-12-06 Love Hörnquist Åstrand <lha@it.su.se> + + * test.asn1: Add test string for constraints. + + * symbol.h: Add support for part of the Constraint-s + + * gen.c: Set new constraints pointer in Type to NULL for inline + constructed types. + + * parse.y: Add support for parsing part of the Constraint-s + +2005-10-29 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Add some X9.57 (DSA) oids, sort lines + + * rfc2459.asn1: Add some X9.57 (DSA) oids. + +2005-10-07 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: Remove pk-init-19 support. + + * pkinit.asn1: Fix comment + + * check-der.c: Add tests for parse and print functions for + heim_integer. + + * Makefile.am: Add parse and print functions for heim_integer. + + * der_format.c: Add parse and print functions for heim_integer. + + * der.h: Add parse and print functions for heim_integer. + +2005-09-22 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am (gen_files_rfc2459) += asn1_DHPublicKey.x + + * rfc2459.asn1: Add DHPublicKey, and INTEGER to for storing the DH + public key in the SubjectPublicKeyInfo.subjectPublicKey BIT + STRING. + +2005-09-20 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c: TSequenceOf/TSetOf: Increase the length of the + array after successful decoding the next element, so that the + array don't contain heap-data. + +2005-09-13 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: Avoid empty array initiators. + + * pkcs8.asn1 (PKCS8PrivateKeyInfo): Inline SET OF to avoid + compiler "feature" + + * check-common.c: Avoid signedness warnings. + + * check-common.h: Makes bytes native platform signed to avoid + casting everywhere + + * check-der.c: Don't depend on malloc(very-very-larger-value) will + fail. Cast to unsigned long before printing size_t. + + * check-gen.c: Don't depend on malloc(very-very-larger-value) will + fail. + + * check-gen.c: Fix signedness warnings. + + * lex.l: unput() have to hanppen in actions for flex 2.5.31, can + do them in user code sesction, so move up handle_comment and + handle_string into action, not much sharing was done anyway. + +2005-09-09 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c (test_one_int): len and len_len is size_t + +2005-08-23 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_encode.c: Change name of oldret for each instance its used + to avoid shadow warning. From: Stefan Metzmacher + <metze@samba.org>. + + * gen_length.c: Change name of oldret for each instance its used + to avoid shadow warning. From: Stefan Metzmacher + <metze@samba.org>. + + * gen_decode.c: Change name of oldret for each instance its used + to avoid shadow warning. From: Stefan Metzmacher + <metze@samba.org>. + + * parse.y: Const poision yyerror. + + * gen.c: Const poision. + +2005-08-22 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: Add KRB5-PADATA-PK-AS-09-BINDING, client send + this (with an empty pa-data.padata-value) to tell the KDC that the + client support the binding the PA-REP to the AS-REQ packet. This + is to fix the problem lack of binding the AS-REQ to the PK-AS-REP + in pre PK-INIT-27. The nonce is replaced with a asCheckSum. + +2005-08-11 Love Hörnquist Åstrand <lha@it.su.se> + + * canthandle.asn1: Allocation is done on CONTEXT tags. + + * asn1_gen.c: rename optind to optidx to avoid shadow warnings + +2005-07-28 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: add id-rsadsi-rc2-cbc + + * Makefile.am: add another oid for rc2 + +2005-07-27 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: Make variable initiation constant by moving them to + global context + + * check-gen.c: change to c89 comment + +2005-07-27 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: remove duplicate asn1_CMSAttributes.x + +2005-07-26 Love Hörnquist Åstrand <lha@it.su.se> + + * asn1_print.c: rename optind to optidx + + * Makefile.am: Update to pkinit-27 + + * pkinit.asn1: Update to pkinit-27 + +2005-07-25 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: make it work for non c99 compilers too + + * check-der.c: start testing BIT STRING + + * der_cmp.c (heim_bit_string_cmp): try handle corner cases better + + * gen_free.c (free_type): free bignum integers + +2005-07-23 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add PKCS12-OctetString + + * pkcs12.asn1: add PKCS12-OctetString + + * Makefile.am: add new files + + * rfc2459.asn1: include SET OF in Attribute to make the type more + useful + + * CMS.asn1: handle IMPLICIT and share some common structures + +2005-07-21 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: Include enough workarounds that this even might + work. + + * check-gen.c: Two implicit tests, one with all structures inlined + + * test.asn1: fix workaround for IMPLICIT CONS case + + * canthandle.asn1: fix workaround for IMPLICIT CONS case + + * asn1_print.c: hint that there are IMPLICIT content when we find + it + + * check-gen.c: Added #ifdef out test for IMPLICIT tagging. + + * Makefile.am: test several IMPLICIT tag level deep + + * test.asn1: test several IMPLICIT tag level deep + + * test.asn1: tests for IMPLICIT + + * Makefile.am: tests for IMPLICIT + + * canthandle.asn1: Expand on what is wrong with the IMPLICIT + tagging + + * rfc2459.asn1: some of the structure are in the IMPLICIT TAGS + module + +2005-07-19 Love Hörnquist Åstrand <lha@it.su.se> + + * asn1_print.c: print size_t by casting to unsigned long and use + right printf format tags are unsigned integers + + * gen.c (generate_constant): oid elements are unsigned + + * gen_decode.c (decode_type): tagdatalen should be an size_t. + + * extra.c (decode_heim_any): tag is unsigned int. + + * der_get.c (der_match_tag): tag is unsigned int. + + * gen_length.c (length_type): cast size_t argument to unsigned + long and use appropriate printf format + + * check-der.c (check_fail_bitstring): check for length overflow + + * der_get.c: rewrite integer overflow tests w/o SIZE_T_MAX + + * check-common.c (generic_decode_fail): only copy in if checklen + its less then 0xffffff and larger than 0. + + * gen_decode.c (find_tag): find external references, we can't + handle those, so tell user that instead of crashing + +2005-07-18 Dave Love <fx@gnu.org> + + * extra.c (free_heim_any_set): Fix return. + + * gen_decode.c (find_tag): Fix return in TType case. + +2005-07-13 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_encode.c (TChoice): add () to make sure variable expression + is evaluated correctly + + * gen_length.c (TChoice): add () to make sure variable expression + is evaluated correctly + + * k5.asn1: reapply 1.43 that got lost in the merge: rename pvno to + krb5-pvno + +2005-07-12 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c (decode_type): TChoice: set the label + + * check-gen.c (cmp_Name): do at least some checking + + * gen_locl.h: rename function filename() to get_filename() to + avoid shadowing + + * lex.l: rename function filename() to get_filename() to avoid + shadowing + + * gen.c: rename function filename() to get_filename() to avoid + shadowing + + * check-der.c: add failure checks for large oid elements + + * check-gen.c: add failure checks for tag (and large tags) + + * der_get.c: Check for integer overflows in tags and oid elements. + +2005-07-10 Assar Westerlund <assar@kth.se> + + * gen_decode.c: Fix decoding of choices to select which branch to + try based on the tag and return an error if that branch fails. + + * check-gen.c: Fix short choice test cases. + +2005-07-09 Assar Westerlund <assar@kth.se> + + * symbol.c: + * parse.y: + * main.c: + * lex.l: + * gen_length.c: + * gen_free.c: + * gen_encode.c: + * gen_decode.c: + * gen_copy.c: + * gen.c: + * extra.c: + * check-gen.c: + * check-der.c: + * check-common.c: + * asn1_print.c: + * asn1_gen.c: + Use emalloc, ecalloc, and estrdup. + Check return value from asprintf. + Make sure that malloc(0) returning NULL is not treated as an + error. + +2005-07-10 Love Hörnquist Åstrand <lha@it.su.se> + + * check-gen.c: test cases for CHOICE, its too liberal right now, + it don't fail hard on failure on after it successfully decoded the + first tag in a choice branch + + * asn1_gen.c: calculate the basename for the output file, + pretty-print tag number + + * test.gen: sample for asn1_gen + + * check-gen.c: check errors in SEQUENCE + + * Makefile.am: build asn1_gen, TESTSeq and new, and class/type/tag + string<->num converter. + + * test.asn1: TESTSeq, for testing SEQUENCE + + * asn1_gen.c: generator for asn1 data + + * asn1_print.c: use class/type/tag string<->num converter. + + * der.c: Add class/type/tag string<->num converter. + + * der.h: Add class/type/tag string<->num converter. + Prototypes/structures for new time bits. + +2005-07-09 Love Hörnquist Åstrand <lha@it.su.se> + + * der_get.c (der_get_unsigned) check for length overflow + (der_get_integer) ditto + (der_get_general_string) ditto + + * der_get.c: check for overruns using SIZE_T_MAX + + * check-der.c: check BIT STRING and OBJECT IDENTIFIER error cases + + * check-common.c (generic_decode_fail): allocate 4K for the over + sized memory test + + * der_get.c (der_get_oid): check for integer overruns and + unterminated oid correctly + + * check-common.h (map_alloc, generic_decode_fail): prototypes + + * check-common.c (map_alloc): make input buffer const + (generic_decode_fail): verify decoding failures + +2005-07-05 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_encode.c: split up the printf for SET OF, also use the + generate name for the symbol in the SET OF, if not, the name might + contain non valid variable name characters (like -) + +2005-07-04 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: move pkcs12 defines into their own namespace + + * pkcs12.asn1: move pkcs12 defines into their own namespace + + * pkcs9.asn1: add PKCS9-friendlyName with workaround for SET OF + bug + + * heim_asn1.h: reuse heim_octet_string for heim_any types + + * main.c: use optidx, handle the case where name is missing and + use base of filename then + + * asn1-common.h: include ASN1_MALLOC_ENCODE + + * gen_decode.c: use less context so lower indentention level, add + missing {} where needed + +2005-07-02 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_copy.c: Use a global variable to keep track of if the 'goto + fail' was used, and use that to only generate the label if needed. + + * asn1_print.c: do indefinite form loop detection and stop after + 10000 recursive indefinite forms, stops crashing due to running + out of stack + + * asn1_print.c: catch badly formated indefinite length data + (missing EndOfContent tag) add (negative) indent flag to speed up + testing + +2005-07-01 Love Hörnquist Åstrand <lha@it.su.se> + + * canthandle.asn1: Can't handle primitives in CHOICE + + * gen_decode.c: Check if malloc failes + + * gen_copy.c: Make sure to free memory on failure + + * gen_decode.c: Check if malloc failes, rename "reallen" to + tagdatalen since that is what it is. + +2005-05-29 Love Hörnquist Åstrand <lha@it.su.se> + + * prefix Der_class with ASN1_C_ to avoid problems with system + headerfiles that pollute the name space + +2005-05-20 Love Hörnquist Åstrand <lha@it.su.se> + + * pkcs12.asn1: add PKCS12CertBag + + * pkcs9.asn1: add pkcs9 certtype x509 certificate + + * Makefile.am: add pkcs12 certbag and pkcs9 certtype x509 + certificate + + * pkcs12.asn1: split off PKCS12Attributes from SafeBag so it can + be reused + + * Makefile.am: add PKCS12Attributes + +2005-05-10 Love Hörnquist Åstrand <lha@it.su.se> + + * canthandle.asn1: fix tags in example + +2005-05-02 Love Hörnquist Åstrand <lha@it.su.se> + + * pkinit.asn1: Let the Windows nonce be an int32 (signed), if not + it will fail when using Windows PK-INIT. + +2005-05-01 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add pkcs12-PBEParams + + * pkcs12.asn1: add pkcs12-PBEParams + + * parse.y: objid_element: exit when the condition fails + +2005-04-26 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_glue.c: 1.8: switch the units variable to a + function. gcc-4.1 needs the size of the structure if its defined + as extern struct units foo_units[] an we don't want to include + <parse_units.h> in the generate headerfile + +2005-03-20 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add the des-ede3-cbc oid that ansi x9.52 uses + + * rfc2459.asn1: add the des-ede3-cbc oid that ansi x9.52 uses + + * Makefile.am: add oids for x509 + + * rfc2459.asn1: add oids now when the compiler can handle them + +2005-03-19 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add pkcs9 files + + * pkcs9.asn1: add small number of oids from pkcs9 + +2005-03-14 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add a bunch of pkcs1/pkcs2/pkcs3/aes oids + + * rfc2459.asn1: add a bunch of pkcs1/pkcs2/pkcs3/aes oids + +2005-03-10 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: merge pa-numbers + +2005-03-09 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add oid's + + * rfc2459.asn1: add encryption oids + + * CMS.asn1: add signedAndEnvelopedData oid + + * pkcs12.asn1: add pkcs12 oids + + * CMS.asn1: add pkcs7 oids + +2005-03-08 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c (generate_header_of_codefile): break out the header + section generation + (generate_constant): generate a function that return the oid + inside a heim_oid + + * parse.y: fix the ordering of the oid's + + * parse.y: handle OBJECT IDENTIFIER as value construct + +2005-02-24 Love Hörnquist Åstrand <lha@it.su.se> + + * Preserve content of CHOICE element that is unknown if ellipsis + was used when defining the structure + +2005-02-13 Love Hörnquist Åstrand <lha@it.su.se> + + * parse.y: use ANS1_TAILQ macros + + * *.[ch]: use ASN1_TAILQ macros + + * asn1_queue.h: inline bsd sys/queue.h and rename TAILQ to + ASN1_TAILQ to avoid problems with name polluting headerfiles + +2005-01-19 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c: pull in <krb5-types.h> + +2005-01-10 Love Hörnquist Åstrand <lha@it.su.se> + + * Add BMPString and UniversalString + + * k5.asn1 (EtypeList): make INTEGER constrained (use krb5int32) + +2005-01-07 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: add GeneralNames + +2004-11-21 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c: use unsigned integer for len of SequenceOf/SetOf and + bitstring names + +2004-11-10 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: switch to krb5int32 and krb5uint32 + + * Unify that three integer types TInteger TUInteger and TBigInteger. + Start to use constrained integers where appropriate. + +2004-10-13 Love Hörnquist Åstrand <lha@it.su.se> + + * CMS.asn1: remove no longer used commented out elements + + * gen_glue.c: make units structures const + +2004-10-12 Love Hörnquist Åstrand <lha@it.su.se> + + * lex.l: handle hex number with [a-fA-F] in them + +2004-10-07 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_free.c: free _save for CHOICE too + + * rfc2459.asn1: use Name and not heim_any + + * gen_decode.c: if malloc for _save failes, goto fail so we free + the structure + + * gen_copy.c: copy _save for CHOICE too + + * gen.c: add _save for CHOICE too + + * CMS.asn1: RecipientIdentifier and SignerIdentifier is the same + name is CMSIdentifier and add glue for that so we can share code + use Name and not heim_any + +2004-10-03 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: drop AlgorithmIdentifierNonOpt add + {RC2CBC,}CBCParameter here where they belong + + * CMS.asn1: add {RC2CBC,}CBCParameter here where they belong + + * rfc2459.asn1: drop AlgorithmIdentifierNonOpt + + * rfc2459.asn1: stop using AlgorithmIdentifierNonOpt hint that we + really want to use Name and some MS stuff + +2004-09-05 Love Hörnquist Åstrand <lha@it.su.se> + + * asn1_print.c: handle end of content, this is part BER support, + however, OCTET STRING need some tweeking too. + + * der.h: add UT_EndOfContent + + * test.asn1: test asn1 spec file + + * check-gen.c: check larget tags + + * Makefile.am: add test asn1 spec file that we can use for testing + constructs that doesn't exists in already existing spec (like + large tags) + + * der_put.c (der_put_tag): make sure there are space for the head + tag when we are dealing with large tags (>30) + + * check-gen.c: add test for tag length + + * check-common.c: export the map_ functions for OVERRUN/UNDERRUN + detection restore the SIGSEGV handler when test is done + + * check-common.h: export the map_ functions for OVERRUN/UNDERRUN + detection + + * gen_decode.c: check that the tag-length is not longer the length + use forwstr on some more places + + * parse.y: revert part of 1.14.2.21, multiple IMPORT isn't allowed + + * pkinit.asn1: correct usage of IMPORT + + * CMS.asn1: correct usage of IMPORT + + * pkcs8.asn1: pkcs8, encrypting private key + + * pkcs12.asn1: pkcs12, key/crl/certificate file transport PDU + + * Makefile.am: add pkcs8 and pkcs12 + + * der_free.c: reset length when freing primitives + + * CMS.asn1: add EncryptedData + +2004-08-26 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c (decode_type): if the entry is already optional + when parsing a tag and we allocate the structure, not pass down + optional since that will case the subtype's decode_type also to + allocate an entry. and we'll leak an entry. Bug from Luke Howard + <lukeh@padl.com>. While here, use calloc. + +2004-04-29 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: shift the last added etypes one step so rc2 doesn't + stomp on cram-md5 + +2004-04-26 Love Hörnquist Åstrand <lha@it.su.se> + + * k5.asn1: add ETYPE_AESNNN_CBC_NONE + + * CMS.asn1: add CMS symmetrical parameters moved to k5.asn1 + + * k5.asn1: add CMS symmetrical parameters here, more nametypes + enctype rc2-cbc + +2004-04-25 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c: free data on decode failure + +2004-04-24 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add CBCParameter and RC2CBCParameter + + * CMS.asn1: add CBCParameter and RC2CBCParameter + +2004-04-20 Love Hörnquist Åstrand <lha@it.su.se> + + * check-der.c: add simple test for oid's, used to trigger malloc + bugs in you have picky malloc (like valgrind/purify/third) + + * der_get.c (der_get_oid): handle all oid components being smaller + then 127 and allocate one extra element since first byte is split + to to elements. + +2004-04-16 Love Hörnquist Åstrand <lha@it.su.se> + + * canthandle.asn1: one thing handled + + * gen_decode.c: handle OPTIONAL CONS-tag-less elements + + * der_length.c (length_len): since length is no longer the same as + an unsigned, do the length counting here. ("unsigned" is zero + padded when most significate bit is set, length is not) + +2004-04-12 Love Hörnquist Åstrand <lha@it.su.se> + + * canthandle.asn1: document by example what the encoder can't + handle right now + + * Makefile.am: add more stuff needed whem implementing x509 + preserve TBSCertificate + + * rfc2459.asn1: add more stuff needed whem implementing x509 + + * CMS.asn1: move some type to rfc2459.asn1 where they belong (and + import them) + + * gen.c: preserve the raw data when asked too + + * gen_decode.c: preserve the raw data when asked too + + * gen_copy.c: preserve the raw data when asked too + + * gen_free.c: preserve the raw data when asked too + + * gen_locl.h: add preserve_type + + * heim_asn1.h: add heim_any_cmp + + * main.c: add flag --preserve-binary=Symbol1,Symbol2,... that make + the compiler generate stubs to save the raw data, its not used + right now when generating the stat + + * k5.asn1: Windows uses PADATA 15 for the request too + + * extra.c: add heim_any_cmp + + * der_put.c: implement UTCtime correctly + + * der_locl.h: remove #ifdef HAVE_TIMEGM\ntimegm\n#endif here from + der.h so one day der.h can get installed + + * der_length.c: implement UTCtime correctly + + * der_get.c: implement UTCtime correctly, prefix dce_fix with + _heim_fix + + * der_copy.c: make copy_bit_string work again + + * der_cmp.c: add octet_string, integer, bit_string cmp functions + + * der.h: hide away more symbols, add more _cmp functions + +2004-03-06 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: add more pkix types make k5 use rfc150 bitstrings, + everything else use der bitstrings + + * main.c: as a compile time option, handle no rfc1510 bitstrings + + * gen_locl.h: rfc1510 bitstrings flag + + * gen_length.c: as a compile time option, handle no rfc1510 + bitstrings + + * gen_encode.c: as a compile time option, handle no rfc1510 + bitstrings + + * gen_decode.c: handle no rfc1510 bitstrings + + * check-gen.c: test for bitstrings + + * rfc2459.asn1: add Certificates and KeyUsage + +2004-02-22 Love Hörnquist Åstrand <lha@it.su.se> + + * pkinit.asn1: use Name from PKIX + + * rfc2459.asn1: add more silly string types to DirectoryString + + * gen_encode.c: add checks for data overflow when encoding + TBitString with members encode SET OF correctly by bytewise + sorting the members + + * gen_decode.c: add checks for data overrun when encoding + TBitString with members + + * der_put.c: add _heim_der_set_sort + + * der_cmp.c: rename oid_cmp to heim_oid_cmp + + * der.h: rename oid_cmp to heim_oid_cmp, add _heim_der_set_sort + + * check-gen.c: add check for Name and (commented out) heim_integer + + * check-der.c: test for "der_length.c: Fix len_unsigned for + certain negative integers, it got the length wrong" , from + Panasas, Inc. + + * der_length.c: Fix len_unsigned for certain negative integers, it + got the length wrong, fix from Panasas, Inc. + + rename len_int and len_unsigned to _heim_\& + + * gen_length.c: 1.14: (length_type): TSequenceOf: add up the size + of all the elements, don't use just the size of the last element. + +2004-02-20 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: include defintion of Name + + * pkinit.asn1: no need for ContentType, its cms internal + + * CMS.asn1: move ContentInfo to CMS + + * pkinit.asn1: update to pk-init-18, move ContentInfo to CMS + + * Makefile.am: align with pk-init-18, move contentinfo to cms + +2004-02-17 Love Hörnquist Åstrand <lha@it.su.se> + + * der_get.c: rewrite previous commit + + * der_get.c (der_get_heim_integer): handle positive integer + starting with 0 + + * der_length.c (der_put_heim_integer): try handle negative + integers better (?) + + * der_put.c (der_put_heim_integer): try handle negative integers + better + + * der_get.c (der_get_heim_integer): dont abort on negative integer just + return ASN1_OVERRUN for now + + * parse.y: add ia5string, and printablestring + + * gen_length.c: add ia5string, and printablestring + + * gen_free.c: add ia5string, and printablestring + + * gen_decode.c: add ia5string, and printablestring + + * gen_copy.c: add ia5string, and printablestring + + * gen.c: add ia5string, printablestring, and utf8string change + implemetation of heim_integer and store the data as bigendian byte + array with a external flag for signedness + + * der_put.c: add ia5string, printablestring, and utf8string change + implemetation of heim_integer and store the data as bigendian byte + array with a external flag for signedness + + * der_length.c: add ia5string, printablestring, and utf8string + change implemetation of heim_integer and store the data as + bigendian byte array with a external flag for signedness + + * der_get.c: add ia5string, printablestring, and utf8string change + implemetation of heim_integer and store the data as bigendian byte + array with a external flag for signedness + + * der_free.c: add ia5string, printablestring, and utf8string + + * der_copy.c: add ia5string, printablestring, and utf8string + + * der.h: add ia5string, printablestring, and utf8string + + * asn1-common.h: add signedness flag to heim_integer, add + ia5string and printablestring + +2004-02-13 Love Hörnquist Åstrand <lha@it.su.se> + + * rfc2459.asn1: use BIGINTEGER where appropriate + + * setchgpw2.asn1: spelling and add op-req again + +2004-02-12 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: clean up better + +2004-02-11 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c (decode_type): TTag, don't overshare the reallen + variable + + * Makefile.am: adapt to log file name change + + * gen.c: genereate log file name based on base name + +2003-11-26 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: += asn1_AlgorithmIdentifierNonOpt.x + + * rfc2459.asn1: add AlgorithmIdentifierNonOpt and use it where + it's needed, make DomainParameters.validationParms heim_any as a + hack. Both are workarounds for the problem with heimdal's asn1 + compiler have with decoing context tagless OPTIONALs. + + * pkinit.asn1: don't import AlgorithmIdentifier + +2003-11-25 Love Hörnquist Åstrand <lha@it.su.se> + + * der_put.c (der_put_bit_string): make it work somewhat better + (should really prune off all trailing zeros) + + * gen_encode.c (encode_type): bit string is not a constructed type + + * der_length.c (length_bit_string): calculate right length for + bitstrings + +2003-11-24 Love Hörnquist Åstrand <lha@it.su.se> + + * der_cmp.c (oid_cmp): compare the whole array, not just + length/sizeof(component) + + * check-common.c: mmap the scratch areas, mprotect before and + after, align data to the edge of the mprotect()ed area to provoke + bugs + + * Makefile.am: add DomainParameters, ValidationParms + + * rfc2459.asn1: add DomainParameters, ValidationParms + + * check-der.c: add free function + + * check-common.h: add free function + + * check-common.c: add free function + + * check-gen.c: check KRB-ERROR + + * asn1_print.c: check end of tag_names loop into APPL class tags + +2003-11-23 Love Hörnquist Åstrand <lha@it.su.se> + + * der_put.c (der_put_generalized_time): check size, not *size + +2003-11-11 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c (decode_type/TBitString): skip over + skipped-bits-in-last-octet octet + + * gen_glue.c (generate_units): generate units in reverse order to + keep unparse_units happy + +2003-11-08 Love Hörnquist Åstrand <lha@it.su.se> + + * Makefile.am: generate all silly pkinit files + + * pkinit.asn1: make it work again, add strange ms structures + + * k5.asn1: PROV-SRV-LOCATION, PacketCable provisioning server + location, PKT-SP-SEC-I09-030728 + + * asn1-common.h: add bit string + + * der_put.c: add bit string and utctime + + * gen.c: add bit string and utctime + + * gen_copy.c: add bit string and utctime + + * der_copy.c: add bit string + + * gen_decode.c: add utctime and bitstring + + * gen_encode.c: add utctime and bitstring + + * gen_free.c: add utctime and bitstring + + * gen_glue.c: don't generate glue for member-less bit strings + + * der_cmp.c: compare function for oids + + * gen_length.c: add utc time, make bit string work for bits + strings w/o any members + + * der_cmp.c: compare function for oids + + * der.h: update boolean prototypes add utctime and bit_string + + * der_free.c: add free_bit_string + + * der_get.c: add bit string and utctime + + * der_length.c: add bit string and utctime, fix memory leak in + length_generalized_time + + * CMS.asn1: make EncryptedContentInfo.encryptedContent a OCTET + STRING to make the generator do the right thing with IMPLICIT + mumble OPTIONAL, make CertificateSet a heim_any_set + + * extra.c, heim_asn1.h: add any_set, instead of just consuming one + der object, its consumes the rest of the data avaible + + * extra.c, heim_asn1.h: extern implementation of ANY, decoder + needs to have hack removed when generator handles tagless optional + data + + * pkinit.asn1: add KdcDHKeyInfo-Win2k + +2003-11-07 Love Hörnquist Åstrand <lha@it.su.se> + + * der_copy.c (copy_oid): copy all components + + * parse.y: parse UTCTime, allow multiple IMPORT + + * symbol.h: add TUTCTime + + * rfc2459.asn1: update + + * x509.asn1: update + + * pkinit.asn1: update + + * CMS.asn1: new file + + * asn1_print.c: print some more lengths, check length before + steping out in the void, parse SET, only go down CONTEXT of type + CONS (not PRIM) + +2003-09-17 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_encode.c (TChoice, TSequence): code element in reverse + order... + +2003-09-16 Love Hörnquist Åstrand <lha@it.su.se> + + * gen.c: store NULL's as int's for now + + * parse.y: remove dup of type def of UsefulType + +2003-09-11 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c (decode_type): if malloc failes, return ENOMEM + +2003-09-10 Love Hörnquist Åstrand <lha@it.su.se> + + * parse.y: kw_UTF8String is a token put tag around the OID + + * asn1_print.c (UT_Integer): when the integer is larger then int + can handle, just print BIG INT and its size + +2003-09-10 Love Hörnquist Åstrand <lha@it.su.se> + + * gen_decode.c (decode_type): TTag, try to generate prettier code + in the non optional case, also remember to update length + +2003-01-22 Johan Danielsson <joda@pdc.kth.se> + + * gen_decode.c: add flag to decode broken DCE BER encoding + + * gen_locl.h: add flag to decode broken DCE BER encoding + + * main.c: add flag to decode broken DCE BER encoding + diff --git a/third_party/heimdal/lib/asn1/MANUAL.md b/third_party/heimdal/lib/asn1/MANUAL.md new file mode 100644 index 0000000..89c452a --- /dev/null +++ b/third_party/heimdal/lib/asn1/MANUAL.md @@ -0,0 +1,1287 @@ +# Introduction + +Heimdal is an implementation of PKIX and Kerberos. As such it must handle the +use of [Abstract Syntax Notation One (ASN.1)](https://www.itu.int/rec/T-REC-X.680-X.693-202102-I/en) +by those protocols. ASN.1 is a language for describing the schemata of network +protocol messages. Associated with ASN.1 are the ASN.1 Encoding Rules (ERs) +that specify how to encode such messages. + +In short: + + - ASN.1 is just a _schema description language_ + + - ASN.1 Encoding Rules are specifications for encoding formats for values of + types described by ASN.1 schemas ("modules") + +Similar languages include: + + - [DCE RPC's Interface Description Language (IDL)](https://pubs.opengroup.org/onlinepubs/9629399/chap4.htm#tagcjh_08) + - [Microsoft Interface Description Language (IDL)](https://docs.microsoft.com/en-us/windows/win32/midl/midl-start-page) + (MIDL is derived from the DCE RPC IDL) + - ONC RPC's eXternal Data Representation (XDR) [RFC4506](https://datatracker.ietf.org/doc/html/rfc4506) + - [XML Schema](https://en.wikipedia.org/wiki/XML_schema) + - Various JSON schema languages + - [Protocol Buffers](https://developers.google.com/protocol-buffers) + - and [many, many others](https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats)! + Many are not even listed there. + +Similar encoding rules include: + + - DCE RPC's [NDR](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm) + - ONC RPC's [XDR](https://datatracker.ietf.org/doc/html/rfc4506) + - XML + - FastInfoSet + - JSON + - CBOR + - [Protocol Buffers](https://developers.google.com/protocol-buffers) + - [Flat Buffers](https://google.github.io/flatbuffers/) + - and [many, many others](https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats)! + Many are not even listed there. + +Many such languages are quite old. ASN.1 itself dates to the early 1980s, with +the first specification published in 1984. XDR was first published in 1987. +IDL's lineage dates back to sometime during the 1980s, via the Apollo Domain +operating system. + +ASN.1 is standardized by the International Telecommunications Union (ITU-T), +and has continued evolving over the years, with frequent updates. + +The two most useful and transcending features of ASN.1 are: + + - the ability to formally express what some know as "open types", "typed + holes", or "references"; + + - the ability to add encoding rules over type, which for ASN.1 includes: + + - binary, tag-length-value (TLV) encoding rules + - binary, non-TLV encoding rules + - textual encoding rules using XML and JSON + - an ad-hoc generic text-based ER called GSER + + In principle ASN.1 can add encoding rules that would allow it to + interoperate with many others, such as: CBOR, protocol buffers, flat + buffers, NDR, and others. + + Readers may recognize that some alternatives to ASN.1 have followed a + similar arc. For example, Protocol Buffers was originally a syntax and + encoding, and has become a syntax and set of various encodings (e.g., Flat + Buffers was added later). And XML has FastInfoSet as a binary encoding + alternative to XML's textual encoding. + +As well, ASN.1 has [high-quality, freely-available specifications](https://www.itu.int/rec/T-REC-X.680-X.693-202102-I/en). + +## ASN.1 Example + +For example, this is a `Certificate` as used in TLS and other protocols, taken +from [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280): + + ```ASN.1 + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING + } + + TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL + } + ``` + +and the same `Certificate` taken from a more modern version -from +[RFC5912](https://datatracker.ietf.org/doc/html/rfc5912)- using newer features +of ASN.1: + + ```ASN.1 + Certificate ::= SIGNED{TBSCertificate} + + TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier{SIGNATURE-ALGORITHM, + {SignatureAlgorithms}}, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + ... , + [[2: + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL + ]], + [[3: + extensions [3] Extensions{{CertExtensions}} OPTIONAL + ]], ... + } + ``` + +As you can see, a `Certificate` is a structure containing a to-be-signed +sub-structure, and a signature of that sub-structure, and the sub-structure +has: a version number, a serial number, a signature algorithm, an issuer name, +a validity period, a subject name, a public key for the subject name, "unique +identifiers" for the issuer and subject entities, and "extensions". + +To understand more we'd have to look at the types of those fields of +`TBSCertificate`, but for now we won't do that. The point here is to show that +ASN.1 allows us to describe "types" of data in a way that resembles +"structures", "records", or "classes" in various programming languages. + +To be sure, there are some "noisy" artifacts in the definition of +`TBSCertificate` which mostly have to do with the original encoding rules for +ASN.1. The original encoding rules for ASN.1 were tag-length-value (TLV) +binary encodings, meaning that for every type, the encoding of a value of that +type consisted of a _tag_, a _length_ of the value's encoding, and the _actual +value's encoding_. Over time other encoding rules were added that do not +require tags, such as the octet encoding rules (OER), but also JSON encoding +rules (JER), XML encoding rules (XER), and others. There is almost no need for +tagging directives like `[1] IMPLICIT` when using OER. But in existing +protocols like PKIX and Kerberos that date back to the days when DER was king, +tagging directives are unfortunately commonplace. + +## ASN.1 Crash Course + +This is not a specification. Readers should refer to the ITU-T's X.680 base +specification for ASN.1's syntax. + +A schema is called a "module". + +A module looks like: + +```ASN.1 +-- This is a comment + +-- Here's the name of the module, here given as an "object identifier" or +-- OID: +PKIXAlgs-2009 { iso(1) identified-organization(3) dod(6) + internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) + id-mod-pkix1-algorithms2008-02(56) } + + +-- `DEFINITIONS` is a required keyword +-- `EXPLICIT TAGS` will be explained later +DEFINITIONS EXPLICIT TAGS ::= +BEGIN +-- list exported types, or `ALL`: +EXPORTS ALL; +-- import some types: +IMPORTS PUBLIC-KEY, SIGNATURE-ALGORITHM, ... FROM AlgorithmInformation-2009 + mda-sha224, mda-sha256, ... FROM PKIX1-PSS-OAEP-Algorithms-2009; + +-- type definitions follow: +... + +END +``` + +Type names start with capital upper-case letters. Value names start with +lower-case letters. + +Type definitions are of the form `TypeName ::= TypeDefinition`. + +Value (constant) definitions are of the form `valueName ::= TypeName <literal>`. + +There are some "universal" primitive types (e.g., string types, numeric types), +and several "constructed" types (arrays, structures. + +Some useful primitive types include `BOOLEAN`, `INTEGER` and `UTF8String`. + +Structures are either `SEQUENCE { ... }` or `SET { ... }`. The "fields" of +these are known as "members". + +Arrays are either `SEQUENCE OF SomeType` or `SET OF SomeType`. + +A `SEQUENCE`'s elements or members are ordered, while a `SET`'s are not. In +practice this means that for _canonical_ encoding rules a `SET OF` type's +values must be sorted, while a `SET { ... }` type's members need not be sorted +at run-time, but are sorted by _tag_ at compile-time. + +Anonymous types are supported, such as `SET OF SET { a A, b B }` (which is a +set of structures with an `a` field (member) of type `A` and a `b` member of +type `B`). + +The members of structures can be `OPTIONAL` or have a `DEFAULT` value. + +There are also discriminated union types known as `CHOICE`s: `U ::= CHOICE { a +A, b B, c C }` (in this case `U` is either an `A`, a `B`, or a `C`. + +Extensibility is supported. "Extensibility" means: the ability to add new +members to structures, new alternatives to discriminated unions, etc. For +example, `A ::= SEQUENCE { a0 A0, a1 A1, ... }` means that type `A` is a +structure that has two fields and which may have more fields added in future +revisions, therefore decoders _must_ be able to receive and decode encodings of +extended versions of `A`, even encoders produced prior to the extensions being +specified! (Normally a decoder "skips" extensions it doesn't know about, and +the encoding rules need only make it possible to do so.) + +## TLV Encoding Rules + +The TLV encoding rules for ASN.1 are: + + - Basic Encoding Rules (BER) + - Distinguished Encoding Rules (DER), a canonical subset of BER + - Canonical Encoding Rules (CER), another canonical subset of BER + +"Canonical" encoding rules yield just one way to encode any value of any type, +while non-canonical rules possibly yield many ways to encode values of certain +types. For example, JSON is not a canonical data encoding. A canonical form +of JSON would have to specify what interstitial whitespace is allowed, a +canonical representation of strings (which Unicode codepoints must be escaped +and in what way, and which must not), and a canonical representation of decimal +numbers. + +It is important to understand that originally ASN.1 came with TLV encoding +rules, and some considerations around TLV encoding rules leaked into the +language. For example, `A ::= SET { a0 [0] A0, a1 [1] A1 }` is a structure +that has two members `a0` and `a1`, and when encoded those members will be +tagged with a "context-specific" tags `0` and `1`, respectively. + +Tags only have to be specified when needed to disambiguate encodings. +Ambiguities arise only in `CHOICE` types and sometimes in `SEQUENCE`/`SET` +types that have `OPTIONAL`/`DEFAULT`ed members. + +In modern ASN.1 it is possible to specify that a module uses `AUTOMATIC` +tagging so that one need never specify tags explicitly in order to fix +ambiguities. + +Also, there are two types of tags: `IMPLICIT` and `EXPLICIT`. Implicit tags +replace the tags that the tagged type would have otherwise. Explicit tags +treat the encoding of a type's value (including its tag and length) as the +value of the tagged type, thus yielding a tag-length-tag-length-value encoding +-- a TLTLV encoding! + +Thus explicit tagging is more redundant and wasteful than implicit tagging. +But implicit tagging loses metadata that is useful for tools that can decode +TLV encodings without reference to the schema (module) corresponding to the +types of values encoded. + +TLV encodings were probably never justified except by lack of tooling and +belief that codecs for TLV ERs can be hand-coded. But TLV RTs exist, and +because they are widely used, cannot be removed. + +## Other Encoding Rules + +The Packed Encoding Rules (PER) and Octet Encoding Rules (OER) are rules that +resemble XDR, but with a 1-byte word size instead of 4-byte word size, and also +with a 1-byte alignment instead of 4-byte alignment, yielding space-efficient +encodings. + +Hand-coding XDR codecs is quite common and fairly easy. Hand-coding PER and +OER is widely considered difficult because PER and OER try to be quite +space-efficient. + +Hand-coding TLV codecs used to be considered easy, but really, never was. + +But no one should hand-code codecs for any encoding rules. + +Instead, one should use a compiler. This is true for ASN.1, and for all schema +languages. + +## Encoding Rule Specific Syntactic Forms + +Some encoding rules require specific syntactic forms for some aspects of them. + +For example, the JER (JSON Encoding Rules) provide for syntax to select the use +of JSON arrays vs. JSON objects for encoding structure types. + +For example, the TLV encoding rules provide for syntax for specifying +alternative tags for disambiguation. + +## ASN.1 Syntax Specifications + + - The base specification is ITU-T + [X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en). + + - Additional syntax extensions include: + + - [X.681 ASN.1 Information object specification](https://www.itu.int/rec/T-REC-X.681/en) + - [X.682 ASN.1 Constraint specification](https://www.itu.int/rec/T-REC-X.682/en) + - [X.682 ASN.1 Parameterization of ASN.1 specifications](https://www.itu.int/rec/T-REC-X.683/en) + + Together these three specifications make the formal specification of open + types possible. + +## ASN.1 Encoding Rules Specifications + + - The TLV Basic, Distinguished, and Canonical Encoding Rules (BER, DER, CER) + are described in ITU-T [X.690](https://www.itu.int/rec/T-REC-X.690/en). + + - The more flat-buffers/XDR-like Packed Encoding Rules (PER) are described in + ITU-T [X.691](https://www.itu.int/rec/T-REC-X.691/en), and its successor, + the Octet Encoding Rules (OER) are described in + [X.696](https://www.itu.int/rec/T-REC-X.692/en). + + - The XML Encoding Rules (XER) are described in ITU-T + [X.693](https://www.itu.int/rec/T-REC-X.693/en). + + Related is the [X.694 Mapping W3C XML schema definitions into ASN.1](https://www.itu.int/rec/T-REC-X.694/en) + + - The JSON Encoding Rules (JER) are described in ITU-T + [X.697](https://www.itu.int/rec/T-REC-X.697/en). + + - The Generic String Encoding Rules are specified by IETF RFCs + [RFC3641](https://datatracker.ietf.org/doc/html/rfc3641), + [RFC3642](https://datatracker.ietf.org/doc/html/rfc3642), + [RFC4792](https://datatracker.ietf.org/doc/html/rfc4792). + +Additional ERs can be added. + +For example, XDR can clearly encode a very large subset of ASN.1, and with a +few additional conventions, all of ASN.1. + +NDR too can clearly encode a very large subset of ASN.1, and with a few +additional conventions, all of ASN. However, ASN.1 is not sufficiently rich a +_syntax_ to express all of what NDR can express (think of NDR conformant and/or +varying arrays), though with some extensions it could. + +## Commentary + +The text in this section is the personal opinion of the author(s). + + - ASN.1 gets a bad rap because BER/DER/CER are terrible encoding rules, as are + all TLV encoding rules. + + The BER family of encoding rules is a disaster, yes, but ASN.1 itself is + not. On the contrary, ASN.1 is quite rich in features and semantics -as + rich as any competitor- while also being very easy to write and understand + _as a syntax_. + + - ASN.1 also gets a bad rap because its full syntax is not context-free, and + so parsing it can be tricky. + + And yet the Heimdal ASN.1 compiler manages, using LALR(1) `yacc`/`bison`/`byacc` + parser-generators. For the subset of ASN.1 that this compiler handles, + there are no ambiguities. However, we understand that eventually we will + need run into ambiguities. + + For example, `ValueSet` and `ObjectSet` are ambiguous. X.680 says: + + ``` + ValueSet ::= "{" ElementSetSpecs "}" + ``` + + while X.681 says: + + ``` + ObjectSet ::= "{" ObjectSetSpec "}" + ``` + + and the set members can be just the symbolic names of members, in which case + there's no grammatical difference between those two productions. These then + cause a conflict in the `FieldSetting` production, which is used in the + `ObjectDefn` production, which is used in defining an object (which is to be + referenced from some `ObjectSet` or `FieldSetting`). + + This particular conflict can be resolved by one of: + + - limiting the power of object sets by disallowing recursion (object sets + containing objects that have field settings that are object sets ...), + + - or by introducing additional required and disambiguating syntactic + elements that preclude full compliance with ASN.1, + + - or by simply using the same production and type internally to handle + both, the `ValueSet` and `ObjectSet` productions and then internally + resolving the actual type as late as possible by either inspecting the + types of the set members or by inspecting the expected kind of field that + the `ValueSet`-or-`ObjectSet` is setting. + + Clearly, only the last of these is satisfying, but it is more work for the + compiler developer. + + - TLV encodings are bad because they yield unnecessary redundance in + encodings. This is space-inefficient, but also a source of bugs in + hand-coded codecs for TLV encodings. + + EXPLICIT tagging makes this worse by making the encoding a TLTLV encoding + (tag length tag length value). (The inner TLV is the V for the outer TL.) + + - TLV encodings are often described as "self-describing" because one can + usually write a `dumpasn1` style of tool that attempts to decode a TLV + encoding of a value without reference to the value's type definition. + + The use of `IMPLICIT` tagging with BER/DER/CER makes schema-less `dumpasn1` + style tools harder to use, as some type information is lost. E.g., a + primitive type implicitly tagged with a context tag results in a TLV + encoding where -without reference to the schema- the tag denotes no + information about the type of the value encoded. The user is left to figure + out what kind of data that is and to then decode it by hand. For + constructed types (arrays and structures), implicit tagging does not really + lose any metadata about the type that wasn't already lost by BER/DER/CER, so + there is no great loss there. + + However, Heimdal's ASN.1 compiler includes an `asn1_print(1)` utility that + can print DER-encoded values in much more detail than a schema-less + `dumpasn1` style of tool can. This is because `asn1_print(1)` includes + a number of compiled ASN.1 modules, and it can be extended to include more. + + - There is some merit to BER, however. Specifically, an appropriate use of + indeterminate length encoding with BER can yield on-line encoding. Think of + encoding streams of indeterminate size -- this cannot be done with DER or + Flat Buffers, or most encodings, though it can be done with some encodings, + such as BER and NDR (NDR has "pipes" for this). + + Some clues are needed in order to produce an codec that can handle such + on-line behavior. In IDL/NDR that clue comes from the "pipe" type. In + ASN.1 there is no such clue and it would have to be provided separately to + the ASN.1 compiler (e.g., as a command-line option). + + - Protocol Buffers is a TLV encoding. There was no need to make it a TLV + encoding. + + Public opinion seems to prefer Flat Buffers now, which is not a TLV encoding + and which is more comparable to XDR/NDR/PER/OER. + +# Heimdal ASN.1 Compiler + +The Heimdal ASN.1 compiler and library implement a very large subset of the +ASN.1 syntax, meanign large parts of X.680, X.681, X.682, and X.683. + +The compiler currently emits: + + - a JSON representation of ASN.1 modules + - C types corresponding to ASN.1 modules' types + - C functions for DER (and some BER) codecs for ASN.1 modules' types + +We vaguely hope to eventually move to using the JSON representation of ASN.1 +modules to do code generation in a programming language like `jq` rather than +in C. The idea there is to make it much easier to target other programming +languages than C, especially Rust, so that we can start moving Heimdal to Rust +(first after this would be `lib/hx509`, then `lib/krb5`, then `lib/hdb`, then +`lib/gssapi`, then `kdc/`). + +The compiler has two "backends": + + - C code generation + - "template" (byte-code) generation and interpretation + +## Features and Limitations + +Supported encoding rules: + + - DER + - BER decoding (but not encoding) + +As well, the Heimdal ASN.1 compiler can render values as JSON using an ad-hoc +metaschema that is not quite JER-compliant. A sample rendering of a complex +PKIX `Certificate` with all typed holes automatically decoded is shown in +[README.md#features](README.md#features). + +The Heimdal ASN.1 compiler supports open types via X.681/X.682/X.683 syntax. +Specifically: (when using the template backend) the generated codecs can +automatically and recursively decode and encode through "typed holes". + +An "open type", also known as "typed holes" or "references", is a part of a +structure that can contain the encoding of a value of some arbitrary data type, +with a hint of that value's type expressed in some way such as: via an "object +identifier", or an integer, or even a string (e.g., like a URN). + +Open types are widely used as a form of extensibility. + +Historically, open types were never documented formally, but with natural +language (e.g., English) meant only for humans to understand. Documenting open +types with formal syntax allows compilers to support them specially. + +See the the [`asn1_compile(1)` manual page](#Manual-Page-for-asn1_compile) +below and [README.md#features](README.md#features), for more details on +limitations. Excerpt from the manual page: + +``` +The Information Object System support includes automatic codec support +for encoding and decoding through “open types” which are also known as +“typed holes”. See RFC5912 for examples of how to use the ASN.1 Infor- +mation Object System via X.681/X.682/X.683 annotations. See the com- +piler's README files for more information on ASN.1 Information Object +System support. + +Extensions specific to Heimdal are generally not syntactic in nature but +rather command-line options to this program. For example, one can use +command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei- + ther encoded nor decoded; +etc. + +ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + +Size and range constraints on the ‘INTEGER’ type cause the compiler to +generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, +‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which +represents an integer of arbitrary size. + +Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. +``` + +## Easy-to-Use C Types + +The Heimdal ASN.1 compiler generates easy-to-use C types for ASN.1 types. + +Unconstrained `INTEGER` becomes `heim_integer` -- a large integer type. + +Constrained `INTEGER` types become `int`, `unsigned int`, `int64_t`, or +`uint64_t`. + +String types generally become `char *` (C strings, i.e., NUL-terminated) or +`heim_octet_string` (a counted byte string type). + +`SET` and `SEQUENCE` types become `struct` types. + +`SET OF SomeType` and `SEQUENCE OF SomeType` types become `struct` types with a +`size_t len` field counting the number of elements of the array, and a pointer +to `len` consecutive elements of the `SomeType` type. + +`CHOICE` types become a `struct` type with an `enum` discriminant and a +`union`. + +Type names have hyphens turned to underscores. + +Every ASN.1 gets a `typedef`. + +`OPTIONAL` members of `SET`s and `SEQUENCE`s become pointer types (`NULL` +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 { + heim_octet_string _save; /* see below! */ + Version *version; + CertificateSerialNumber serialNumber; + AlgorithmIdentifier signature; + Name issuer; + Validity validity; + Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + heim_bit_string *issuerUniqueID; + 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 +with `--preserve-binary=TBSCertificate`, and the decoder will place the +original encoding of the value of a `TBSCertificate` in the decoded +`TBSCertificate`'s `_save` field. This is very useful for signature +validation: the application need not attempt to re-encode a `TBSCertificate` in +order to validate its signature from the containing `Certificate`! + +Let's compare to the `Certificate` as defined in ASN.1: + +```ASN.1 + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING + } + + TBSCertificate ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL + } +``` + +The conversion from ASN.1 to C is quite mechanical and natural. That's what +code-generators do, of course, so it's not surprising. But you can see that +`Certificate` in ASN.1 and C differs only in: + + - in C `SEQUENCE { }` becomes `struct { }` + - in C the type name comes first + - in C we drop the tagging directives (e.g., `[0] EXPLICIT`) + - `DEFAULT` and `OPTIONAL` become pointers + - 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 +type `T`: + +```C +int decode_T(const unsigned char *, size_t, TBSCertificate *, size_t *); +int encode_T(unsigned char *, size_t, const TBSCertificate *, size_t *); +size_t length_T(const TBSCertificate *); +int copy_T(const TBSCertificate *, TBSCertificate *); +void free_T(TBSCertificate *); +char * print_T(const TBSCertificate *, int); +``` + +The `decode_T()` functions take a pointer to the encoded data, its length in +bytes, a pointer to a C object of type `T` to decode into, and a pointer into +which the number of bytes consumed will be written. + +The `length_T()` functions take a pointer to a C object of type `T` and return +the number of bytes its encoding would need. + +The `encode_T()` functions take a pointer to enough bytes to encode the value, +the number of bytes found there, a pointer to a C object of type `T` whose +value to encode, and a pointer into which the number of bytes output will be +written. + +> NOTE WELL: The first argument to `encode_T()` functions must point to the +> 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. 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_. + +See [sample usage](#Using-the-Generated-APIs). + +These functions are all recursive. + +> NOTE WELL: These functions use the standard C memory allocator. +> When using the Windows statically-linked C run-time, you must link with +> `LIBASN1.LIB` to avoid possibly freeing memory allocated by a different +> allocator. + +## Error Handling + +All codec functions that return errors return them as `int`. + +Error values are: + + - system error codes (use `strerror()` to display them) + +or + + - `ASN1_BAD_TIMEFORMAT` + - `ASN1_MISSING_FIELD` + - `ASN1_MISPLACED_FIELD` + - `ASN1_TYPE_MISMATCH` + - `ASN1_OVERFLOW` + - `ASN1_OVERRUN` + - `ASN1_BAD_ID` + - `ASN1_BAD_LENGTH` + - `ASN1_BAD_FORMAT` + - `ASN1_PARSE_ERROR` + - `ASN1_EXTRA_DATA` + - `ASN1_BAD_CHARACTER` + - `ASN1_MIN_CONSTRAINT` + - `ASN1_MAX_CONSTRAINT` + - `ASN1_EXACT_CONSTRAINT` + - `ASN1_INDEF_OVERRUN` + - `ASN1_INDEF_UNDERRUN` + - `ASN1_GOT_BER` + - `ASN1_INDEF_EXTRA_DATA` + +You can use the `com_err` library to display these errors as strings: + +```C + struct et_list *etl = NULL; + initialize_asn1_error_table_r(&etl); + int ret; + + ... + + ret = decode_T(...); + if (ret) { + const char *error_message; + + if ((error_message = com_right(etl, ret)) == NULL) + error_message = strerror(ret); + + fprintf(stderr, "Failed to decode T: %s\n", + error_message ? error_message : "<unknown error>"); + } +``` + +## Using the Generated APIs + +Value construction is as usual in C. Use the standard C allocator for +allocating values of `OPTIONAL` fields. + +Value destruction is done with the `free_T()` destructors. + +Decoding is just: + +```C + Certificate c; + size_t sz; + int ret; + + ret = decode_Certificate(pointer_to_encoded_bytes, + number_of_encoded_bytes, + &c, &sz); + if (ret == 0) { + if (sz != number_of_encoded_bytes) + warnx("Extra bytes after Certificate!"); + } else { + warnx("Failed to decode certificate!"); + return ret; + } + + /* Now do stuff with the Certificate */ + ... + + /* Now release the memory */ + free_Certificate(&c); +``` + +Encoding involves calling the `length_T()` function to compute the number of +bytes needed for the encoding, then allocating that many bytes, then calling +`encode_T()` to encode into that memory. A convenience macro, +`ASN1_MALLOC_ENCODE()`, does all three operations: + +```C + Certificate c; + size_t num_bytes, sz; + char *bytes = NULL; + int ret; + + /* Build a `Certificate` in `c` */ + ... + + /* Encode `c` */ + ASN1_MALLOC_ENCODE(Certificate, bytes, num_bytes, &c, sz, ret); + if (ret) + errx(1, "Out of memory encoding a Certificate"); + + /* This check isn't really needed -- it never fails */ + if (num_bytes != sz) + errx(1, "ASN.1 encoder internal error"); + + /* Send the `num_bytes` in `bytes` */ + ... + + /* Free the memory allocated by `ASN1_MALLOC_ENCODE()` */ + free(bytes); +``` + +or, the same code w/o the `ASN1_MALLOC_ENCODE()` macro: + +```C + Certificate c; + size_t num_bytes, sz; + char *bytes = NULL; + int ret; + + /* Build a `Certificate` in `c` */ + ... + + /* Encode `c` */ + num_bytes = length_Certificate(&c); + bytes = malloc(num_bytes); + if (bytes == NULL) + errx(1, "Out of memory"); + + /* + * Note that the memory to encode into, passed to encode_Certificate() + * must be a pointer to the _last_ byte of that memory, not the first! + */ + ret = encode_Certificate(bytes + num_bytes - 1, num_bytes, + &c, &sz); + if (ret) + errx(1, "Out of memory encoding a Certificate"); + + /* This check isn't really needed -- it never fails */ + if (num_bytes != sz) + errx(1, "ASN.1 encoder internal error"); + + /* Send the `num_bytes` in `bytes` */ + ... + + /* Free the memory allocated by `ASN1_MALLOC_ENCODE()` */ + free(bytes); +``` + +## Open Types + +The handling of X.681/X.682/X.683 syntax for open types is described at length +in [README-X681.md](README-X681.md). + +## Command-line Usage + +The compiler takes an ASN.1 module file name and outputs a C header and C +source files, as well as various other metadata files: + + - `<module>_asn1.h` + + This file defines all the exported types from the given ASN.1 module as C + types. + + - `<module>_asn1-priv.h` + + This file defines all the non-exported types from the given ASN.1 module as + C types. + + - `<module>_asn1_files` + + This file is needed because the default is to place the code for each type + in a separate C source file, which can help improve the performance of + builds by making it easier to parallelize the building of the ASN.1 module. + + - `asn1_<Type>.c` or `asn1_<module>_asn1.c` + + If `--one-code-file` is used, then the implementation of the module will be + in a file named `asn1_<module>_asn1.c`, otherwise the implementation of each + type in the module will be in `asn1_<Type>.c`. + + - `<module>_asn1.json` + + This file contains a JSON description of the module (the schema for this + file is ad-hoc and subject to change w/o notice). + + - `<module>_asn1_oids.c` + + This file is meant to be `#include`d, and contains just calls to a + `DEFINE_OID_WITH_NAME(sym)` macro that the user must define, where `sym` is + the suffix of the name of a variable of type `heim_oid`. The full name of + the variable is `asn1_oid_ ## sym`. + + - `<module>_asn1_syms.c` + + This file is meant to be `#include`d, and contains just calls to these + macros that the user must define: + + - `ASN1_SYM_INTVAL(name, genname, sym, num)` + - `ASN1_SYM_OID(name, genname, sym)` + - `ASN1_SYM_TYPE(name, genname, sym)` + + where `name` is the C string literal name of the value or type as it appears + in the ASN.1 module, `genname` is the C string literal name of the value or + type as generated (e.g., with hyphens replaced by underscores), `sym` is the + symbol or symbol suffix (see above0, and `num` is the numeric value of the + integer value. + +Control over the C types used for ASN.1 `INTEGER` types is done by ASN.1 usage +convention: + + - unconstrained `INTEGER` types, or `INTEGER` types where only the minimum, or + only the maximum value is specified generate `heim_integer` + + - constrained `INTEGER` types whose minimum and maximum fit in `unsigned`'s + range generate `unsigned` + + - constrained `INTEGER` types whose minimum and maximum fit in `int`'s + range generate `int` + + - constrained `INTEGER` types whose minimum and maximum fit in `uin64_t`'s + range generate `uin64_t` + + - constrained `INTEGER` types whose minimum and maximum fit in `in64_t`'s + range generate `in64_t` + + - `INTEGER` types with named members generate a C `struct` with `unsigned int` + bit-field members + + - all other `INTEGER` types generate `heim_integer` + +Various code generation options are provided as command-line options or as +ASN.1 usage conventions: + + - `--type-file=C-HEADER-FILE` -- generate an `#include` directive to include + that header for some useful base types (within Heimdal we use `krb5-types.h` + as that header) + + - `--template` -- use the "template" (byte-coded) backend + + - `--one-code-file` -- causes all the code generated to be placed in one C + source file (mutually exclusive with `--template`) + + - `--support-ber` -- accept non-DER BER when decoding + + - `--preserve-binary=TYPE` -- add a `_save` field to the C struct type for the + ASN.1 `TYPE` where the decoder will save the original encoding of the value + of `TYPE` it decodes (useful for cryptographic signature verification!) + + - `--sequence=TYPE` -- generate `add_TYPE()` and `remove_TYPE()` utility + functions (`TYPE` must be a `SET OF` or `SEQUENCE OF` type) + + - `--decorate=DECORATION` -- add fields to generated C struct types as + described in the `DECORATION` (see the + [manual page](#Manual-Page-for-asn1_compile) below) + + Decoration fields are never encoded or decoded. They are meant to be used + for, e.g., application state keeping. + + - `--no-parse-units` -- normally the compiler generates code to use the + Heimdal `libroken` "units" utility for displaying bit fields; this option + disables this + +See the [manual page for `asn1_compile(1)`](#Manual-Page-for-asn1_compile) for +a full listing of command-line options. + +### Manual Page for `asn1_compile(1)` + +``` +ASN1_COMPILE(1) BSD General Commands Manual ASN1_COMPILE(1) + +NAME + asn1_compile — compile ASN.1 modules + +SYNOPSIS + asn1_compile [--template] [--prefix-enum] [--enum-prefix=PREFIX] + [--encode-rfc1510-bit-string] [--decode-dce-ber] + [--support-ber] [--preserve-binary=TYPE] [--sequence=TYPE] + [--decorate=DECORATION] [--one-code-file] [--gen-name=NAME] + [--option-file=FILE] [--original-order] [--no-parse-units] + [--type-file=C-HEADER-FILE] [--version] [--help] + [FILE.asn1 [NAME]] + +DESCRIPTION + asn1_compile compiles an ASN.1 module into C source code and header + files. + + A fairly large subset of ASN.1 as specified in X.680, and the ASN.1 In‐ + formation Object System as specified in X.681, X.682, and X.683 is sup‐ + ported, with support for the Distinguished Encoding Rules (DER), partial + Basic Encoding Rules (BER) support, and experimental JSON support (encod‐ + ing only at this time). + + See the compiler's README files for details about the C code and inter‐ + faces it generates. + + The Information Object System support includes automatic codec support + for encoding and decoding through “open types” which are also known as + “typed holes”. See RFC 5912 for examples of how to use the ASN.1 Infor‐ + mation Object System via X.681/X.682/X.683 annotations. See the com‐ + piler's README files for more information on ASN.1 Information Object + System support. + + Extensions specific to Heimdal are generally not syntactic in nature but + rather command-line options to this program. For example, one can use + command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei‐ + ther encoded nor decoded; + etc. + + ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + + Size and range constraints on the ‘INTEGER’ type cause the compiler to + generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, + ‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which + represents an integer of arbitrary size. + + Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. + + Options supported: + + --template + Use the “template” backend instead of the “codegen” backend + (which is the default backend). + + The template backend generates “templates” which are akin to + bytecode, and which are interpreted at run-time. + + The codegen backend generates C code for all functions directly, + with no template interpretation. + + The template backend scales better than the codegen backend be‐ + cause as we add support for more encoding rules and more opera‐ + tions (we may add value comparators) the templates stay mostly + the same, thus scaling linearly with size of module. Whereas the + codegen backend scales linear with the product of module size and + number of encoding rules supported. + + --prefix-enum + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --enum-prefix=PREFIX + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --encode-rfc1510-bit-string + Use RFC1510, non-standard handling of “BIT STRING” types. + + --decode-dce-ber + + --support-ber + + --preserve-binary=TYPE + Generate a field named ‘_save’ in the C struct generated for the + named TYPE. This field is used to preserve the original encoding + of the value of the TYPE. + + This is useful for cryptographic applications so that they can + check signatures of encoded values as-received without having to + re-encode those values. + + For example, the TBSCertificate type should have values preserved + so that Certificate validation can check the signatureValue over + the tbsCertificate's value as-received. + + The alternative of encoding a value to check a signature of it is + brittle. For types where non-canonical encodings (such as BER) + are allowed, this alternative is bound to fail. Thus the point + of this option. + + --sequence=TYPE + Generate add/remove functions for the named ASN.1 TYPE which must + be a ‘SET OF’ or ‘SEQUENCE OF’ type. + + --decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given ASN.1 type FIELD-ASN1-TYPE, but do not encode or decode + it. If the fname ends in a question mark, then treat the field + as OPTIONAL. + + This is useful for adding fields to existing types that can be + used for internal bookkeeping but which do not affect interoper‐ + ability because they are neither encoded nor decoded. For exam‐ + ple, one might decorate a request type with state needed during + processing of the request. + + --decorate=ASN1-TYPE:void*:fname + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + type ‘void *’ (but do not encode or decode it. + + The destructor and copy constructor functions generated by this + compiler for ASN1-TYPE will set this field to the ‘NULL’ pointer. + + --decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given external C type FIELD-C-TYPE, declared in the given + header but do not encode or decode this field. If the fname ends + in a question mark, then treat the field as OPTIONAL. + + The header must include double quotes or angle brackets. The + copyfn must be the name of a copy constructor function that takes + a pointer to a source value of the type, and a pointer to a des‐ + tination value of the type, in that order, and which returns zero + on success or else a system error code on failure. The freefn + must be the name of a destructor function that takes a pointer to + a value of the type and which releases resources referenced by + that value, but does not free the value itself (the run-time al‐ + locates this value as needed from the C heap). The freefn should + also reset the value to a pristine state (such as all zeros). + + If the copyfn and freefn are empty strings, then the decoration + field will neither be copied nor freed by the functions generated + for the TYPE. + + --one-code-file + Generate a single source code file. Otherwise a separate code + file will be generated for every type. + + --gen-name=NAME + Use NAME to form the names of the files generated. + + --option-file=FILE + Take additional command-line options from FILE. + + --original-order + Attempt to preserve the original order of type definition in the + ASN.1 module. By default the compiler generates types in a topo‐ + logical sort order. + + --no-parse-units + Do not generate to-int / from-int functions for enumeration + types. + + --type-file=C-HEADER-FILE + Generate an include of the named header file that might be needed + for common type defintions. + + --version + + --help + +NOTES + Currently only the template backend supports automatic encoding and de‐ + coding of open types via the ASN.1 Information Object System and + X.681/X.682/X.683 annotations. + +HEIMDAL February 22, 2021 HEIMDAL +``` + +# Future Directions + +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 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 spending CPU cycles and memory allocations on decoding types in +typed holes that are not of interest to the application. + +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 +compiler command-line options to make it possible to map schemas usefully). + +For the `hxtool` command, it would be nice if the user could input arbitrary +certificate extensions and `subjectAlternativeName` (SAN) values in JSON + an +ASN.1 module and type reference that `hxtool` could then parse and encode using +the ASN.1 compiler and library. Currently the `hx509` library and its `hxtool` +command must be taught about every SAN type. diff --git a/third_party/heimdal/lib/asn1/Makefile.am b/third_party/heimdal/lib/asn1/Makefile.am new file mode 100644 index 0000000..e5af4ba --- /dev/null +++ b/third_party/heimdal/lib/asn1/Makefile.am @@ -0,0 +1,567 @@ +# $Id$ + +include $(top_srcdir)/Makefile.am.common + +WFLAGS += $(WFLAGS_ENUM_CONV) + +AM_YFLAGS = -d -o asn1parse.c -t + +AM_CPPFLAGS += $(ROKEN_RENAME) -I$(top_builddir)/include -I$(top_srcdir)/lib/base + +man_MANS = asn1_print.1 asn1_compile.1 + +lib_LTLIBRARIES = libasn1.la libasn1template.la +libasn1_la_LDFLAGS = -version-info 8:0:0 +libasn1template_la_LDFLAGS = -version-info 8:0:0 + +noinst_LTLIBRARIES = libasn1base.la + +if versionscript +libasn1_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +libasn1template_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map +endif + + +libasn1_la_LIBADD = \ + libasn1base.la \ + @LIB_com_err@ \ + $(LIBADD_roken) + +libasn1template_la_LIBADD = \ + libasn1base.la \ + @LIB_com_err@ \ + $(LIBADD_roken) + +BUILT_SOURCES = \ + $(gen_files_rfc2459) \ + $(gen_files_rfc4108) \ + $(gen_files_cms) \ + $(gen_files_krb5) \ + $(gen_files_ocsp) \ + $(gen_files_pkinit) \ + $(gen_files_pkcs8) \ + $(gen_files_pkcs9) \ + $(gen_files_pkcs10) \ + $(gen_files_pkcs12) \ + $(gen_files_digest) \ + $(gen_files_kx509) + +BUILT_TEMPLATE_SOURCES = \ + $(gen_files_rfc2459_template) \ + $(gen_files_rfc4108_template) \ + $(gen_files_cms_template) \ + $(gen_files_krb5_template) \ + $(gen_files_ocsp_template) \ + $(gen_files_pkinit_template) \ + $(gen_files_pkcs8_template) \ + $(gen_files_pkcs9_template) \ + $(gen_files_pkcs10_template) \ + $(gen_files_pkcs12_template) \ + $(gen_files_digest_template) \ + $(gen_files_kx509_template) + +gen_files_krb5 = asn1_krb5_asn1.c +gen_files_krb5_template = asn1_krb5_template_asn1.c +gen_files_cms = asn1_cms_asn1.c +gen_files_cms_template = asn1_cms_template_asn1.c +gen_files_crmf = asn1_crmf_asn1.c +gen_files_crmf_template = asn1_crmf_template_asn1.c +gen_files_rfc2459 = asn1_rfc2459_asn1.c +gen_files_rfc2459_template = asn1_rfc2459_template_asn1.c +gen_files_rfc4108 = asn1_rfc4108_asn1.c +gen_files_rfc4108_template = asn1_rfc4108_template_asn1.c +gen_files_ocsp = asn1_ocsp_asn1.c +gen_files_ocsp_template = asn1_ocsp_template_asn1.c +gen_files_pkinit = asn1_pkinit_asn1.c +gen_files_pkinit_template = asn1_pkinit_template_asn1.c +gen_files_pkcs10 = asn1_pkcs10_asn1.c +gen_files_pkcs10_template = asn1_pkcs10_template_asn1.c +gen_files_pkcs12 = asn1_pkcs12_asn1.c +gen_files_pkcs12_template = asn1_pkcs12_template_asn1.c +gen_files_pkcs8 = asn1_pkcs8_asn1.c +gen_files_pkcs8_template = asn1_pkcs8_template_asn1.c +gen_files_pkcs9 = asn1_pkcs9_asn1.c +gen_files_pkcs9_template = asn1_pkcs9_template_asn1.c +gen_files_test = asn1_test_asn1.c +gen_files_test_template = asn1_test_template_asn1.c +gen_files_digest = asn1_digest_asn1.c +gen_files_digest_template = asn1_digest_template_asn1.c +gen_files_kx509 = asn1_kx509_asn1.c +gen_files_kx509_template = asn1_kx509_template_asn1.c +gen_files_x690sample = asn1_x690sample_asn1.c +gen_files_x690sample_template = asn1_x690sample_template_asn1.c + +oid_resolution.lo: $(BUILT_SOURCES) + +noinst_PROGRAMS = asn1_gen + +bin_PROGRAMS = asn1_compile asn1_print + +TESTS = check-der check-gen check-gen-template check-timegm check-ber check-template +check_PROGRAMS = $(TESTS) + +asn1_gen_SOURCES = asn1_gen.c +asn1_print_SOURCES = asn1_print.c +asn1_print_SOURCES += $(gen_files_x690sample_template) +asn1_print_CPPFLAGS = -DASN1_PRINT_SUPPORTED +check_der_SOURCES = check-der.c check-common.c check-common.h + +check_template_SOURCES = check-template.c check-common.c check-common.h +nodist_check_template_SOURCES = $(gen_files_test_template) + +check_gen_template_CPPFLAGS = -DASN1_IOS_SUPPORTED +dist_check_gen_template_SOURCES = check-gen.c check-common.c check-common.h +nodist_check_gen_template_SOURCES = $(gen_files_test_template) \ + $(gen_files_x690sample_template) + +dist_check_gen_SOURCES = check-gen.c check-common.c check-common.h +nodist_check_gen_SOURCES = $(gen_files_test) $(gen_files_x690sample) + +build_HEADERZ = asn1-template.h + +asn1_compile_SOURCES = \ + asn1parse.y \ + der.h \ + gen.c \ + gen_copy.c \ + gen_decode.c \ + gen_encode.c \ + gen_print.c \ + gen_free.c \ + gen_glue.c \ + gen_length.c \ + gen_locl.h \ + gen_seq.c \ + gen_template.c \ + hash.c \ + hash.h \ + lex.l \ + lex.h \ + main.c \ + asn1-template.h \ + symbol.c \ + symbol.h + +dist_libasn1base_la_SOURCES = \ + der_locl.h \ + der.c \ + der.h \ + der_get.c \ + der_put.c \ + der_free.c \ + der_print.c \ + der_length.c \ + der_copy.c \ + der_cmp.c \ + der_format.c \ + fuzzer.c \ + heim_asn1.h \ + extra.c \ + roken_rename.h \ + template.c \ + timegm.c + +dist_libasn1_la_SOURCES = oid_resolution.c +dist_libasn1template_la_SOURCES = oid_resolution.c + +nodist_libasn1base_la_SOURCES = \ + asn1_err.h \ + asn1_err.c + +nodist_libasn1_la_SOURCES = $(BUILT_SOURCES) + +if !ASN1_TEMPLATING +nodist_libasn1template_la_SOURCES = $(BUILT_TEMPLATE_SOURCES) +else +nodist_libasn1template_la_SOURCES = $(BUILT_SOURCES) +endif + +asn1_compile_LDADD = \ + $(LIB_roken) $(LEXLIB) + +check_der_LDADD = \ + libasn1.la \ + $(LIB_roken) + +check_template_LDADD = $(check_der_LDADD) +asn1_print_LDADD = libasn1template.la $(LIB_roken) $(LIB_com_err) +asn1_gen_LDADD = $(check_der_LDADD) +check_timegm_LDADD = $(check_der_LDADD) + +check_gen_template_LDADD = \ + libasn1template.la \ + $(LIB_roken) + +check_gen_LDADD = \ + libasn1template.la \ + $(LIB_roken) + +check_ber_LDADD = $(check_gen_LDADD) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(gen_files_rfc2459) \ + $(gen_files_rfc2459_template) \ + $(gen_files_rfc4108) \ + $(gen_files_rfc4108_template) \ + $(gen_files_cms) \ + $(gen_files_cms_template) \ + $(gen_files_krb5) \ + $(gen_files_krb5_template) \ + $(gen_files_ocsp) \ + $(gen_files_ocsp_template) \ + $(gen_files_pkinit) \ + $(gen_files_pkinit_template) \ + $(gen_files_pkcs8) \ + $(gen_files_pkcs8_template) \ + $(gen_files_pkcs9) \ + $(gen_files_pkcs9_template) \ + $(gen_files_pkcs10) \ + $(gen_files_pkcs10_template) \ + $(gen_files_pkcs12) \ + $(gen_files_pkcs12_template) \ + $(gen_files_digest) \ + $(gen_files_digest_template) \ + $(gen_files_kx509) \ + $(gen_files_kx509_template) \ + $(gen_files_x690sample) \ + $(gen_files_x690sample_template) \ + $(gen_files_test) \ + $(gen_files_test_template) \ + $(nodist_check_gen_SOURCES) \ + asn1parse.c asn1parse.h lex.c \ + asn1_err.c asn1_err.h \ + rfc2459_asn1_files rfc2459_asn1*.h \ + rfc2459_template_asn1_files rfc2459_template_asn1*.h \ + rfc4108_asn1_files rfc4108_asn1*.h \ + rfc4108_template_asn1_files rfc4108_template_asn1*.h \ + cms_asn1_files cms_asn1*.h \ + cms_template_asn1_files cms_template_asn1* \ + crmf_asn1_files crmf_asn1* \ + crmf_template_asn1_files crmf_template_asn1* \ + krb5_asn1_files krb5_asn1* \ + krb5_template_asn1_files krb5_template_asn1* \ + ocsp_asn1_files ocsp_asn1* \ + ocsp_template_asn1_files ocsp_template_asn1* \ + pkinit_asn1_files pkinit_asn1* \ + pkinit_template_asn1_files pkinit_template_asn1* \ + pkcs8_asn1_files pkcs8_asn1* \ + pkcs8_template_asn1_files pkcs8_template_asn1* \ + pkcs9_asn1_files pkcs9_asn1* \ + pkcs9_template_asn1_files pkcs9_template_asn1* \ + pkcs10_asn1_files pkcs10_asn1* \ + pkcs10_template_asn1_files pkcs10_template_asn1* \ + pkcs12_asn1_files pkcs12_asn1* \ + pkcs12_template_asn1_files pkcs12_template_asn1* \ + digest_asn1_files digest_asn1* \ + digest_template_asn1_files digest_template_asn1* \ + kx509_asn1_files kx509_asn1* \ + kx509_template_asn1_files kx509_template_asn1* \ + x690sample_asn1_files x690sample_asn1* \ + x690sample_template_asn1_files x690sample_template_asn1* \ + test_asn1_files test_asn1* \ + test_template_asn1_files test_template_asn1* \ + asn1_*_asn1.c *_asn1.json *_asn1_syms.c *_asn1_oids.c + +dist_include_HEADERS = der.h heim_asn1.h +dist_include_HEADERS += $(srcdir)/der-protos.h $(srcdir)/der-private.h +dist_include_HEADERS += asn1-common.h + +nodist_include_HEADERS = asn1_err.h +nodist_include_HEADERS += krb5_asn1.h +nodist_include_HEADERS += krb5_template_asn1.h +nodist_include_HEADERS += pkinit_asn1.h +nodist_include_HEADERS += pkinit_template_asn1.h +nodist_include_HEADERS += cms_asn1.h +nodist_include_HEADERS += cms_template_asn1.h +nodist_include_HEADERS += crmf_asn1.h +nodist_include_HEADERS += crmf_template_asn1.h +nodist_include_HEADERS += rfc2459_asn1.h +nodist_include_HEADERS += rfc2459_template_asn1.h +nodist_include_HEADERS += rfc4108_asn1.h +nodist_include_HEADERS += rfc4108_template_asn1.h +nodist_include_HEADERS += ocsp_asn1.h +nodist_include_HEADERS += ocsp_template_asn1.h +nodist_include_HEADERS += pkcs8_asn1.h +nodist_include_HEADERS += pkcs8_template_asn1.h +nodist_include_HEADERS += pkcs9_asn1.h +nodist_include_HEADERS += pkcs9_template_asn1.h +nodist_include_HEADERS += pkcs10_asn1.h +nodist_include_HEADERS += pkcs10_template_asn1.h +nodist_include_HEADERS += pkcs12_asn1.h +nodist_include_HEADERS += pkcs12_template_asn1.h +nodist_include_HEADERS += digest_asn1.h +nodist_include_HEADERS += digest_template_asn1.h +nodist_include_HEADERS += kx509_asn1.h +nodist_include_HEADERS += kx509_template_asn1.h +nodist_include_HEADERS += x690sample_asn1.h +nodist_include_HEADERS += x690sample_template_asn1.h + +priv_headers = krb5_asn1-priv.h +priv_headers += krb5_template_asn1-priv.h +priv_headers += pkinit_asn1-priv.h +priv_headers += pkinit_template_asn1-priv.h +priv_headers += cms_asn1-priv.h +priv_headers += cms_template_asn1-priv.h +priv_headers += crmf_asn1-priv.h +priv_headers += crmf_template_asn1-priv.h +priv_headers += rfc2459_asn1-priv.h +priv_headers += rfc2459_template_asn1-priv.h +priv_headers += rfc4108_asn1-priv.h +priv_headers += rfc4108_template_asn1-priv.h +priv_headers += ocsp_asn1-priv.h +priv_headers += ocsp_template_asn1-priv.h +priv_headers += pkcs8_asn1-priv.h +priv_headers += pkcs8_template_asn1-priv.h +priv_headers += pkcs9_asn1-priv.h +priv_headers += pkcs9_template_asn1-priv.h +priv_headers += pkcs10_asn1-priv.h +priv_headers += pkcs10_template_asn1-priv.h +priv_headers += pkcs12_asn1-priv.h +priv_headers += pkcs12_template_asn1-priv.h +priv_headers += digest_asn1-priv.h +priv_headers += digest_template_asn1-priv.h +priv_headers += kx509_asn1-priv.h +priv_headers += kx509_template_asn1-priv.h +priv_headers += x690sample_asn1-priv.h +priv_headers += x690sample_template_asn1-priv.h +priv_headers += test_asn1.h test_asn1-priv.h +priv_headers += test_template_asn1.h test_template_asn1-priv.h + + + +$(asn1_compile_OBJECTS): asn1parse.h asn1parse.c $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1_la_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1template_la_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(libasn1base_la_OBJECTS): asn1_err.h $(srcdir)/der-protos.h $(srcdir)/der-private.h +$(check_gen_OBJECTS): test_asn1.h +$(check_template_OBJECTS): test_asn1_files +$(asn1_print_OBJECTS): $(nodist_include_HEADERS) $(priv_headers) + +asn1parse.h: asn1parse.c + +$(gen_files_krb5) krb5_asn1.h krb5_asn1-priv.h: krb5_asn1_files +$(gen_files_krb5_template) krb5_template_asn1.h krb5_template_asn1-priv.h: krb5_template_asn1_files +$(gen_files_ocsp) ocsp_asn1.h ocsp_asn1-priv.h: ocsp_asn1_files +$(gen_files_ocsp_template) ocsp_template_asn1.h ocsp_template_asn1-priv.h: ocsp_template_asn1_files +$(gen_files_pkinit) pkinit_asn1.h pkinit_asn1-priv.h: pkinit_asn1_files +$(gen_files_pkinit_template) pkinit_template_asn1.h pkinit_template_asn1-priv.h: pkinit_template_asn1_files +$(gen_files_pkcs8) pkcs8_asn1.h pkcs8_asn1-priv.h: pkcs8_asn1_files +$(gen_files_pkcs8_template) pkcs8_template_asn1.h pkcs8_template_asn1-priv.h: pkcs8_template_asn1_files +$(gen_files_pkcs9) pkcs9_asn1.h pkcs9_asn1-priv.h: pkcs9_asn1_files +$(gen_files_pkcs9_template) pkcs9_template_asn1.h pkcs9_template_asn1-priv.h: pkcs9_template_asn1_files +$(gen_files_pkcs10) pkcs10_asn1.h pkcs10_asn1-priv.h: pkcs10_asn1_files +$(gen_files_pkcs10_template) pkcs10_template_asn1.h pkcs10_template_asn1-priv.h: pkcs10_template_asn1_files +$(gen_files_pkcs12) pkcs12_asn1.h pkcs12_asn1-priv.h: pkcs12_asn1_files +$(gen_files_pkcs12_template) pkcs12_template_asn1.h pkcs12_template_asn1-priv.h: pkcs12_template_asn1_files +$(gen_files_digest) digest_asn1.h digest_asn1-priv.h: digest_asn1_files +$(gen_files_digest_template) digest_template_asn1.h digest_template_asn1-priv.h: digest_template_asn1_files +$(gen_files_kx509) kx509_asn1.h kx509_asn1-priv.h: kx509_asn1_files +$(gen_files_kx509_template) kx509_template_asn1.h kx509_template_asn1-priv.h: kx509_template_asn1_files +$(gen_files_rfc2459) rfc2459_asn1.h rfc2459_asn1-priv.h: rfc2459_asn1_files +$(gen_files_rfc2459_template) rfc2459_template_asn1.h rfc2459_template_asn1-priv.h: rfc2459_template_asn1_files +$(gen_files_rfc4108) rfc4108_asn1.h rfc4108_asn1-priv.h: rfc4108_asn1_files +$(gen_files_rfc4108_template) rfc4108_template_asn1.h rfc4108_template_asn1-priv.h: rfc4108_template_asn1_files +$(gen_files_cms) cms_asn1.h cms_asn1-priv.h: cms_asn1_files +$(gen_files_cms_template) cms_template_asn1.h cms_template_asn1-priv.h: cms_template_asn1_files +$(gen_files_crmf) crmf_asn1.h crmf_asn1-priv.h: crmf_asn1_files +$(gen_files_crmf_template) crmf_template_asn1.h crmf_template_asn1-priv.h: crmf_template_asn1_files +$(gen_files_x690sample) x690sample_asn1.h x690sample_asn1-priv.h: x690sample_asn1_files +$(gen_files_x690sample_template) x690sample_template_asn1.h x690sample_template_asn1-priv.h: x690sample_template_asn1_files +$(gen_files_test) test_asn1.h test_asn1-priv.h: test_asn1_files +$(gen_files_test_template) test_template_asn1.h test_template_asn1-priv.h: test_template_asn1_files + +if ASN1_TEMPLATING +TEMPLATE_OPTION=--template +else +TEMPLATE_OPTION= +endif + +# If the default is not templating, then we build a variant of libasn1 that is +# templated anyways. +rfc2459_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc2459.asn1 + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_template_asn1 || (rm -f rfc2459_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc2459_template_asn1.c + +rfc4108_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4108.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/rfc4108.asn1 rfc4108_template_asn1 || (rm -f rfc4108_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc4108_template_asn1.c + +cms_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/cms.asn1 $(srcdir)/cms.opt + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/cms.opt $(srcdir)/cms.asn1 cms_template_asn1 || (rm -f cms_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_cms_template_asn1.c + +crmf_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_template_asn1 || (rm -f crmf_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_crmf_template_asn1.c + +krb5_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt + $(ASN1_COMPILE) --one-code-file --template \ + --option-file=$(srcdir)/krb5.opt \ + $(srcdir)/krb5.asn1 krb5_template_asn1 || (rm -f krb5_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_krb5_template_asn1.c + +ocsp_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_template_asn1 || (rm -f ocsp_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_ocsp_template_asn1.c + +pkinit_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkinit.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkinit.asn1 pkinit_template_asn1 || (rm -f pkinit_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkinit_template_asn1.c + +pkcs8_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs8.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs8.asn1 pkcs8_template_asn1 || (rm -f pkcs8_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs8_template_asn1.c + +pkcs9_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs9.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs9.asn1 pkcs9_template_asn1 || (rm -f pkcs9_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs9_template_asn1.c + +pkcs10_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs10.asn1 + $(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/pkcs10.opt $(srcdir)/pkcs10.asn1 pkcs10_template_asn1 || (rm -f pkcs10_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs10_template_asn1.c + +pkcs12_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs12.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/pkcs12.asn1 pkcs12_template_asn1 || (rm -f pkcs12_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs12_template_asn1.c + +digest_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/digest.asn1 digest_template_asn1 || (rm -f digest_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_digest_template_asn1.c + +kx509_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/kx509.asn1 kx509_template_asn1 || (rm -f kx509_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_kx509_template_asn1.c + +rfc2459_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc2459.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/rfc2459.opt $(srcdir)/rfc2459.asn1 rfc2459_asn1 || (rm -f rfc2459_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc2459_asn1.c + +rfc4108_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4108.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/rfc4108.asn1 rfc4108_asn1 || (rm -f rfc4108_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_rfc4108_asn1.c + +cms_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/cms.asn1 $(srcdir)/cms.opt + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/cms.opt $(srcdir)/cms.asn1 cms_asn1 || (rm -f cms_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_cms_asn1.c + +crmf_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_asn1 || (rm -f crmf_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_crmf_asn1.c + +krb5_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) \ + --option-file=$(srcdir)/krb5.opt \ + $(srcdir)/krb5.asn1 krb5_asn1 || (rm -f krb5_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_krb5_asn1.c + +ocsp_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_asn1 || (rm -f ocsp_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_ocsp_asn1.c + +pkinit_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkinit.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkinit.asn1 pkinit_asn1 || (rm -f pkinit_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkinit_asn1.c + +pkcs8_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs8.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs8.asn1 pkcs8_asn1 || (rm -f pkcs8_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs8_asn1.c + +pkcs9_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs9.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs9.asn1 pkcs9_asn1 || (rm -f pkcs9_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs9_asn1.c + +pkcs10_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs10.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/pkcs10.opt $(srcdir)/pkcs10.asn1 pkcs10_asn1 || (rm -f pkcs10_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs10_asn1.c + +pkcs12_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/pkcs12.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/pkcs12.asn1 pkcs12_asn1 || (rm -f pkcs12_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_pkcs12_asn1.c + +digest_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/digest.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/digest.asn1 digest_asn1 || (rm -f digest_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_digest_asn1.c + +kx509_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/kx509.asn1 + $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/kx509.asn1 kx509_asn1 || (rm -f kx509_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_kx509_asn1.c + +x690sample_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 + $(ASN1_COMPILE) --one-code-file --template $(srcdir)/x690sample.asn1 x690sample_template_asn1 || (rm -f x690sample_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_x690sample_template_asn1.c + +x690sample_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1 + $(ASN1_COMPILE) --one-code-file $(srcdir)/x690sample.asn1 x690sample_asn1 || (rm -f x690sample_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_x690sample_asn1.c + +test_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 + $(ASN1_COMPILE) --one-code-file \ + --template \ + --option-file=$(srcdir)/test.opt \ + $(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_test_template_asn1.c + +test_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1 + $(ASN1_COMPILE) --one-code-file \ + --option-file=$(srcdir)/test.opt \ + $(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1) + @$(CLANG_FORMAT) -style=$(CLANG_FORMAT_STYLE) -i asn1_test_asn1.c + + +EXTRA_DIST = \ + NTMakefile \ + README-template.md \ + asn1_compile-version.rc \ + libasn1-exports.def \ + canthandle.asn1 \ + cms.asn1 \ + cms.opt \ + crmf.asn1 \ + crmf.opt \ + digest.asn1 \ + krb5.asn1 \ + krb5.opt \ + kx509.asn1 \ + ocsp.asn1 \ + ocsp.opt \ + pkcs10.asn1 \ + pkcs10.opt \ + pkcs12.asn1 \ + pkcs8.asn1 \ + pkcs9.asn1 \ + pkinit.asn1 \ + pku2u.asn1 \ + rfc2459.asn1 \ + rfc2459.opt \ + rfc4108.asn1 \ + setchgpw2.asn1 \ + tcg.asn1 \ + test.asn1 \ + test.opt \ + x690sample.asn1 \ + test.gen \ + asn1_err.et \ + asn1_err.c \ + asn1_err.h \ + asn1_print.1 \ + asn1_compile.1 \ + version-script.map + +DER_PROTOS = $(srcdir)/der-protos.h $(srcdir)/der-private.h + +ALL_OBJECTS = $(libasn1_la_OBJECTS) +ALL_OBJECTS += $(libasn1template_la_OBJECTS) +ALL_OBJECTS += $(libasn1base_la_OBJECTS) +ALL_OBJECTS += $(asn1_print_OBJECTS) +ALL_OBJECTS += $(asn1_compile_OBJECTS) +ALL_OBJECTS += $(asn1_gen_OBJECTS) +ALL_OBJECTS += $(check_template_OBJECTS) + +$(ALL_OBJECTS): $(DER_PROTOS) asn1_err.h + +$(srcdir)/der-protos.h: $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -o der-protos.h $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) || rm -f der-protos.h + +$(srcdir)/der-private.h: $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) + cd $(srcdir) && perl ../../cf/make-proto.pl -q -P comment -p der-private.h $(dist_libasn1base_la_SOURCES) $(dist_libasn1_la_SOURCES) || rm -f der-private.h diff --git a/third_party/heimdal/lib/asn1/NTMakefile b/third_party/heimdal/lib/asn1/NTMakefile new file mode 100644 index 0000000..19255c6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/NTMakefile @@ -0,0 +1,548 @@ +######################################################################## +# +# Copyright (c) 2009-2022, Secure Endpoints Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RELDIR=lib\asn1 + +intcflags=-I$(SRCDIR) -I$(OBJ) -DROKEN_RENAME -DASN1_IOS_SUPPORTED -DASN1_LIB + +!include ../../windows/NTMakefile.w32 + +ASN1_BINARIES = \ + $(LIBEXECDIR)\asn1_compile.exe + +$(BINDIR)\asn1_compile.exe: \ + $(OBJ)\asn1parse.obj \ + $(OBJ)\gen.obj \ + $(OBJ)\gen_copy.obj \ + $(OBJ)\gen_decode.obj \ + $(OBJ)\gen_encode.obj \ + $(OBJ)\gen_print.obj \ + $(OBJ)\gen_free.obj \ + $(OBJ)\gen_glue.obj \ + $(OBJ)\gen_length.obj \ + $(OBJ)\gen_seq.obj \ + $(OBJ)\gen_template.obj \ + $(OBJ)\hash.obj \ + $(OBJ)\lex.obj \ + $(OBJ)\main.obj \ + $(OBJ)\symbol.obj \ + $(OBJ)\asn1_compile-version.res + $(EXECONLINK) $(LIBROKEN) $(LIBVERS) + $(EXEPREP_NOHEIM) + +$(OBJ)\lex.c: lex.l $(OBJ)\asn1parse.h + $(LEX) -o$@ lex.l + +$(OBJ)\lex.obj: $(OBJ)\lex.c + $(C2OBJ) -DYY_NO_UNISTD_H + +$(OBJ)\asn1parse.c $(OBJ)\asn1parse.h: asn1parse.y + $(YACC) -o $(OBJ)\asn1parse.c --defines=$(OBJ)\asn1parse.h $** + +$(OBJ)\asn1_err.c $(OBJ)\asn1_err.h: asn1_err.et + cd $(OBJ) + $(BINDIR)\compile_et.exe $(SRCDIR)\asn1_err.et + cd $(SRCDIR) + +$(BINDIR)\asn1_print.exe: $(OBJ)\asn1_print.obj $(LIBHEIMDAL) + $(EXECONLINK) $(LIBVERS) $(LIBROKEN) $(LIBCOMERR) + $(EXEPREP) + +$(BINDIR)\asn1_gen.exe: $(OBJ)\asn1_gen.obj $(LIBHEIMDAL) + $(EXECONLINK) $(LIBVERS) $(LIBROKEN) + $(EXEPREP) + +LIBASN1_X= \ + $(OBJ)\asn1_rfc2459_asn1.c \ + $(OBJ)\asn1_rfc4108_asn1.c \ + $(OBJ)\asn1_cms_asn1.c \ + $(OBJ)\asn1_krb5_asn1.c \ + $(OBJ)\asn1_ocsp_asn1.c \ + $(OBJ)\asn1_pkinit_asn1.c \ + $(OBJ)\asn1_pkcs8_asn1.c \ + $(OBJ)\asn1_pkcs9_asn1.c \ + $(OBJ)\asn1_pkcs10_asn1.c \ + $(OBJ)\asn1_pkcs12_asn1.c \ + $(OBJ)\asn1_digest_asn1.c \ + $(OBJ)\asn1_kx509_asn1.c \ + $(OBJ)\asn1_x690sample_asn1.c + +LIBASN1_OBJS= \ + $(OBJ)\der.obj \ + $(OBJ)\der_get.obj \ + $(OBJ)\der_put.obj \ + $(OBJ)\der_free.obj \ + $(OBJ)\der_print.obj \ + $(OBJ)\der_length.obj \ + $(OBJ)\der_copy.obj \ + $(OBJ)\der_cmp.obj \ + $(OBJ)\der_format.obj \ + $(OBJ)\template.obj \ + $(OBJ)\extra.obj \ + $(OBJ)\oid_resolution.obj \ + $(OBJ)\timegm.obj \ + $(OBJ)\asn1_rfc2459_asn1.obj \ + $(OBJ)\asn1_rfc4108_asn1.obj \ + $(OBJ)\asn1_cms_asn1.obj \ + $(OBJ)\asn1_krb5_asn1.obj \ + $(OBJ)\asn1_ocsp_asn1.obj \ + $(OBJ)\asn1_pkinit_asn1.obj \ + $(OBJ)\asn1_pkcs8_asn1.obj \ + $(OBJ)\asn1_pkcs9_asn1.obj \ + $(OBJ)\asn1_pkcs10_asn1.obj \ + $(OBJ)\asn1_pkcs12_asn1.obj \ + $(OBJ)\asn1_digest_asn1.obj \ + $(OBJ)\asn1_kx509_asn1.obj \ + $(OBJ)\asn1_x690sample_asn1.obj \ + $(OBJ)\asn1_err.obj + +$(OBJ)\oid_resolution.obj: $(LIBASN1_X) + +$(LIBASN1): $(LIBASN1_OBJS) + $(LIBCON_C) -out:$@ @<< +$(**: = +) +<< + +clean:: + -$(RM) $(LIBASN1) + +# +# The static runtime version LIBASN1_S is for use by thirdparty +# components. It is not used in the construction of the Heimdal +# DLLs. + +LIBASN1_S_OBJS= \ + $(OBJ)\der.s.obj \ + $(OBJ)\der_get.s.obj \ + $(OBJ)\der_put.s.obj \ + $(OBJ)\der_free.s.obj \ + $(OBJ)\der_print.s.obj \ + $(OBJ)\der_length.s.obj \ + $(OBJ)\der_copy.s.obj \ + $(OBJ)\der_cmp.s.obj \ + $(OBJ)\der_format.s.obj \ + $(OBJ)\template.s.obj \ + $(OBJ)\extra.s.obj \ + $(OBJ)\oid_resolution.s.obj \ + $(OBJ)\timegm.s.obj \ + $(OBJ)\asn1_rfc2459_asn1.s.obj \ + $(OBJ)\asn1_rfc4108_asn1.s.obj \ + $(OBJ)\asn1_cms_asn1.s.obj \ + $(OBJ)\asn1_krb5_asn1.s.obj \ + $(OBJ)\asn1_ocsp_asn1.s.obj \ + $(OBJ)\asn1_pkinit_asn1.s.obj \ + $(OBJ)\asn1_pkcs8_asn1.s.obj \ + $(OBJ)\asn1_pkcs9_asn1.s.obj \ + $(OBJ)\asn1_pkcs10_asn1.s.obj \ + $(OBJ)\asn1_pkcs12_asn1.s.obj \ + $(OBJ)\asn1_digest_asn1.s.obj \ + $(OBJ)\asn1_kx509_asn1.s.obj \ + $(OBJ)\asn1_x690sample_asn1.s.obj \ + $(OBJ)\asn1_err.s.obj + +$(OBJ)\oid_resolution.s.obj: oid_resolution.c $(LIBASN1_X) + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ oid_resolution.c + +$(OBJ)\der.s.obj: der.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_get.s.obj: der_get.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_put.s.obj: der_put.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_free.s.obj: der_free.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_print.s.obj: der_print.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_length.s.obj: der_length.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_copy.s.obj: der_copy.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_cmp.s.obj: der_cmp.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\der_format.s.obj: der_format.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\template.s.obj: template.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\extra.s.obj: extra.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\timegm.s.obj: timegm.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_rfc2459_asn1.s.obj: $(OBJ)\asn1_rfc2459_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_rfc4108_asn1.s.obj: $(OBJ)\asn1_rfc4108_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_cms_asn1.s.obj: $(OBJ)\asn1_cms_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_krb5_asn1.s.obj: $(OBJ)\asn1_krb5_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_ocsp_asn1.s.obj: $(OBJ)\asn1_ocsp_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkinit_asn1.s.obj: $(OBJ)\asn1_pkinit_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs8_asn1.s.obj: $(OBJ)\asn1_pkcs8_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs9_asn1.s.obj: $(OBJ)\asn1_pkcs9_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs10_asn1.s.obj: $(OBJ)\asn1_pkcs10_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_pkcs12_asn1.s.obj: $(OBJ)\asn1_pkcs12_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_digest_asn1.s.obj: $(OBJ)\asn1_digest_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_kx509_asn1.s.obj: $(OBJ)\asn1_kx509_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_x690sample_asn1.s.obj: $(OBJ)\asn1_x690sample_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_test_asn1.s.obj: $(OBJ)\asn1_test_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_test_template_asn1.s.obj: $(OBJ)\asn1_test_template_asn1.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(OBJ)\asn1_err.s.obj: $(OBJ)\asn1_err.c + $(C2OBJ_C_MT) -Fo$@ -Fd$(@D)\ $** + +$(LIBASN1_S): $(LIBASN1_S_OBJS) + $(LIBCON_C) -out:$@ @<< +$(**: = +) +<< + +clean:: + -$(RM) $(LIBASN1_S) + + +# +# Generate list of exports +# +# This target is only used during development to generate a list of +# symbols that are exported from all the object files in LIBASN1_OBJS. +# +exports-list.txt: $(LIBASN1_OBJS) + $(PERL) ..\..\cf\w32-list-externs-from-objs.pl -q -u @<< > $@ +$(**: = +) +<< + +$(OBJ)\asn1_krb5_asn1.c $(OBJ)\krb5_asn1.h: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5.opt + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\krb5.opt \ + $(SRCDIR)\krb5.asn1 krb5_asn1 \ + || ($(RM) $(OBJ)\krb5_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_ocsp_asn1.c $(OBJ)\ocsp_asn1.h: $(BINDIR)\asn1_compile.exe ocsp.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\ocsp.opt \ + $(SRCDIR)\ocsp.asn1 \ + ocsp_asn1 \ + || ($(RM) $(OBJ)\ocsp_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkinit_asn1.c $(OBJ)\pkinit_asn1.h: $(BINDIR)\asn1_compile.exe pkinit.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkinit.asn1 pkinit_asn1 \ + || ($(RM) $(OBJ)\pkinit_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs8_asn1.c $(OBJ)\pkcs8_asn1.h: $(BINDIR)\asn1_compile.exe pkcs8.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs8.asn1 pkcs8_asn1 \ + || ($(RM) $(OBJ)\pkcs8_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs9_asn1.c $(OBJ)\pkcs9_asn1.h: $(BINDIR)\asn1_compile.exe pkcs9.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs9.asn1 pkcs9_asn1 \ + || ($(RM) $(OBJ)\pkcs9_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs10_asn1.c $(OBJ)\pkcs10_asn1.h: $(BINDIR)\asn1_compile.exe pkcs10.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\pkcs10.opt \ + $(SRCDIR)\pkcs10.asn1 \ + pkcs10_asn1 \ + || ($(RM) $(OBJ)\pkcs10_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_pkcs12_asn1.c $(OBJ)\pkcs12_asn1.h: $(BINDIR)\asn1_compile.exe pkcs12.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs12.asn1 pkcs12_asn1 \ + || ($(RM) $(OBJ)\pkcs12_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_digest_asn1.c $(OBJ)\digest_asn1.h: $(BINDIR)\asn1_compile.exe digest.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\digest.asn1 digest_asn1 \ + || ($(RM) $(OBJ)\digest_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_kx509_asn1.c $(OBJ)\kx509_asn1.h: $(BINDIR)\asn1_compile.exe kx509.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\kx509.asn1 kx509_asn1 \ + || ($(RM) $(OBJ)\kx509_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_rfc2459_asn1.c $(OBJ)\rfc2459_asn1.h: $(BINDIR)\asn1_compile.exe rfc2459.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + --option-file=$(SRCDIR)\rfc2459.opt \ + $(SRCDIR)\rfc2459.asn1 rfc2459_asn1 \ + || ($(RM) $(OBJ)\rfc2459_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_rfc4108_asn1.c $(OBJ)\rfc4108_asn1.h: $(BINDIR)\asn1_compile.exe rfc4108.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + $(SRCDIR)\rfc4108.asn1 rfc4108_asn1 \ + || ($(RM) $(OBJ)\rfc4108_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_cms_asn1.c $(OBJ)\cms_asn1.h: $(BINDIR)\asn1_compile.exe cms.asn1 cms.opt + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file --option-file=$(SRCDIR)\cms.opt \ + $(SRCDIR)\cms.asn1 cms_asn1 \ + || ($(RM) $(OBJ)\cms_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(gen_files_crmf) $(OBJ)\crmf_asn1.h: $(BINDIR)\asn1_compile.exe crmf.asn1 crmf.opt + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file --option-file=$(SRCDIR)\crmf.opt \ + $(SRCDIR)\crmf.asn1 crmf_asn1 \ + || ($(RM) $(OBJ)\crmf_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_x690sample_asn1.c $(OBJ)\x690sample_asn1.h: $(BINDIR)\asn1_compile.exe x690sample.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --one-code-file \ + $(SRCDIR)\x690sample.asn1 x690sample_asn1 \ + || ($(RM) $(OBJ)\x690sample_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_test_asn1.c $(OBJ)\test_asn1.h: $(BINDIR)\asn1_compile.exe test.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --option-file=$(SRCDIR)/test.opt \ + --one-code-file \ + $(SRCDIR)\test.asn1 test_asn1 \ + || ($(RM) $(OBJ)\test_asn1.h ; exit /b 1) + cd $(SRCDIR) + +$(OBJ)\asn1_test_template_asn1.c $(OBJ)\test_template_asn1.h: $(BINDIR)\asn1_compile.exe test.asn1 + cd $(OBJ) + $(BINDIR)\asn1_compile.exe \ + --template \ + --option-file=$(SRCDIR)/test.opt \ + --one-code-file \ + $(SRCDIR)\test.asn1 test_template_asn1 \ + || ($(RM) $(OBJ)\test_template_asn1.h ; exit /b 1) + cd $(SRCDIR) + +INCFILES= \ + $(INCDIR)\der.h \ + $(INCDIR)\heim_asn1.h \ + $(INCDIR)\der-protos.h \ + $(INCDIR)\der-private.h \ + $(INCDIR)\asn1-common.h \ + $(INCDIR)\asn1-template.h \ + $(OBJ)\asn1_err.h + +$(INCDIR)\der-protos.h: $(OBJ)\der-protos.h + +GENINCFILES= \ + $(INCDIR)\asn1_err.h \ + $(INCDIR)\cms_asn1.h \ + $(INCDIR)\crmf_asn1.h \ + $(INCDIR)\digest_asn1.h \ + $(INCDIR)\krb5_asn1.h \ + $(INCDIR)\kx509_asn1.h \ + $(INCDIR)\ocsp_asn1.h \ + $(INCDIR)\pkcs12_asn1.h \ + $(INCDIR)\pkcs8_asn1.h \ + $(INCDIR)\pkcs9_asn1.h \ + $(INCDIR)\pkcs10_asn1.h \ + $(INCDIR)\pkinit_asn1.h \ + $(INCDIR)\rfc2459_asn1.h \ + $(INCDIR)\rfc4108_asn1.h \ + $(INCDIR)\x690sample_asn1.h \ + $(OBJ)\krb5_asn1-priv.h \ + $(OBJ)\ocsp_asn1-priv.h \ + $(OBJ)\pkinit_asn1-priv.h \ + $(OBJ)\cms_asn1-priv.h \ + $(OBJ)\crmf_asn1-priv.h \ + $(OBJ)\rfc2459_asn1-priv.h \ + $(OBJ)\rfc4108_asn1-priv.h \ + $(OBJ)\x690sample_asn1-priv.h \ + $(OBJ)\pkcs8_asn1-priv.h \ + $(OBJ)\pkcs9_asn1-priv.h \ + $(OBJ)\pkcs10_asn1-priv.h \ + $(OBJ)\pkcs12_asn1-priv.h \ + $(OBJ)\digest_asn1-priv.h \ + $(OBJ)\kx509_asn1-priv.h \ + $(OBJ)\test_template_asn1.h \ + $(OBJ)\test_template_asn1-priv.h \ + $(OBJ)\test_asn1.h \ + $(OBJ)\test_asn1-priv.h + +libasn1_base_SOURCES= \ + der_locl.h \ + der.c \ + der.h \ + der_get.c \ + der_put.c \ + der_free.c \ + der_print.c \ + der_length.c \ + der_copy.c \ + der_cmp.c \ + der_format.c \ + template.c \ + heim_asn1.h \ + extra.c \ + timegm.c + +libasn1_SOURCES= \ + oid_resolution.c + +$(OBJ)\der-protos.h: $(libasn1_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -q -P remove -o $(OBJ)\der-protos.h $(libasn1_base_SOURCES) $(libasn1_SOURCES) || $(RM) $(OBJ)\der-protos.h + +$(OBJ)\der-private.h: $(libasn1_SOURCES) + $(PERL) ..\..\cf\make-proto.pl -q -P remove -p $(OBJ)\der-private.h $(libasn1_base_SOURCES) $(libasn1_SOURCES) || $(RM) $(OBJ)\der-private.h + +clean:: + -$(RM) $(INCDIR)\der-protos.h + +all:: $(INCFILES) $(GENINCFILES) $(ASN1_BINARIES) $(LIBASN1) $(LIBASN1_S) + +all-tools:: $(LIBEXECDIR)\asn1_print.exe $(BINDIR)\asn1_gen.exe + +clean:: + -$(RM) $(INCFILES) + -$(RM) $(GENINCFILES) + -$(RM) $(ASN1_BINARIES:.exe=.*) + -$(RM) $(LIBASN1) + -$(RM) $(LIBEXECDIR)\asn1_print.* + -$(RM) $(LIBEXECDIR)\asn1_gen.* + +TEST_BINARIES=\ + $(OBJ)\check-der.exe \ + $(OBJ)\check-gen-template.exe \ + $(OBJ)\check-timegm.exe \ + $(OBJ)\check-ber.exe \ + $(OBJ)\check-template.exe + +test-binaries: $(TEST_BINARIES) + +test-run: + cd $(OBJ) + -check-der.exe + -check-gen-template.exe + -check-timegm.exe + -check-ber.exe + -check-template.exe + cd $(SRC) + +test:: test-binaries test-run + +clean:: + -$(RM) $(TEST_BINARIES:.exe=*) + +$(OBJ)\check-ber.exe: $(OBJ)\check-ber.obj \ + $(LIBHEIMDAL) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-der.exe: $(OBJ)\check-der.obj $(OBJ)\check-common.obj \ + $(LIBHEIMDAL) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-gen-template.exe: $(OBJ)\check-gen.obj $(OBJ)\check-common.obj \ + $(LIBHEIMDAL) $(LIBROKEN) $(OBJ)\asn1_test_template_asn1.obj + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-timegm.exe: $(OBJ)\check-timegm.obj \ + $(LIBHEIMDAL) $(LIBROKEN) + $(EXECONLINK) + $(EXEPREP_NODIST) + +$(OBJ)\check-template.exe: $(OBJ)\check-template.obj $(OBJ)\check-common.obj \ + $(LIBHEIMDAL) $(LIBROKEN) $(OBJ)\asn1_test_asn1.obj + $(EXECONLINK) + $(EXEPREP_NODIST) diff --git a/third_party/heimdal/lib/asn1/README-X681.md b/third_party/heimdal/lib/asn1/README-X681.md new file mode 100644 index 0000000..e0d270b --- /dev/null +++ b/third_party/heimdal/lib/asn1/README-X681.md @@ -0,0 +1,1124 @@ +# Automatic Open Type Handling via X.68x Support in Heimdal's ASN.1 Compiler + +## Table of Contents + + 1. [Introduction](#Introduction) + 2. [Typed Holes / Open Types](#typed-holes--open-types) + 3. [ASN.1 IOS, Constraint, and Parameterization](#asn1-ios-constraint-and-parameterization) + - [IOS Crash Course](#ios-crash-course) + 4. [Usage](#Usage) + 5. [Limitations](#Limitations) + 6. [Implementation Design](#implementation-design) + 7. [Moving From C](#moving-from-c) + +## Introduction + +ASN.1 is a set of specifications for "syntax" for defining data schemas, and +"encoding rules" for encoding values of data of types defined in those schemas. +There are many encoding rules, but one syntax. + +The base of ASN.1 _syntax_ is specified by X.680, an ITU-T standard. The +encoding rules are specified by the X.69x series (X.690 through X.697). + +This README is concerned primarily with the X.68x series. + +While X.680 is essential for implementing many Internet (and other) protocols, +and sufficient for implementing all of those, there are extensions in the +remainder of the X.68x series that can make life a lot easier for developers +who have to use ASN.1 for interoperability reasons. + +Various syntax extensions are specified in X.68x series documents: + + - X.681: Information Object specification + - X.682: Constraint specification + - X.683: Parameterization of ASN.1 specifications + +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. Give a +compiler more formally-expressed constraints and it can do more labor-saving +than it could otherwise. + +A subset of these three extensions, X.681, X.682, and X.683, can enable some +rather magical features. These magical features are generally not the focus of +those ITU-T specifications nor of many RFCs that make use of them, but +nonetheless they are of interest to us. + +This README covers some ideas for what this magic is, 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. Hopefully this +README improves that further. + +The magic that we're after is simply the *automatic and recursive handling of +open types by an ASN.1 compiler*. + +Combined with eventual support for the ASN.1 JSON Encoding Rules (JER) [X.697], +this feature could give us unprecendented visibility into really complex data +structures, such as Endorsement Key Certificates (EKcerts) for Trusted Platform +Module (TPM) applications. + +Support for JER and 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 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. + +Indeed, Heimdal's `asn1_print` program currently supports transcoding of DER to +JSON, though it's not quite X.697-compliant JSON! Heimdal does not currently +support parsing JSON-encoded values of ASN.1 types. + +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 deeply nested open types: DNs 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 +hand-coded handling of certificate extensions in `lib/hx509/`. + +The reader should already be familiar with ASN.1, which anyways is a set of two +things: + + - an abstract syntax for specifying schemas for data interchange + + - a set of encoding rules + +A very common thing to see in projects that use ASN.1, as well as projects that +use alternatives to ASN.1, is a pattern known as the "typed hole" or "open +type". + +The ASN.1 Information Object System (IOS) [X.681] is all about automating the +otherwise very annoying task of dealing with "typed holes" / "open types". + +The ASN.1 IOS is not sufficient to implement the magic we're after. Also +needed is constraint specification and parameterization of types. + +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.682-201508-I/en +https://www.itu.int/rec/T-REC-X.683-201508-I/en + + +## Typed Holes / Open Types + +A typed hole or open type is a pattern of data structure that generally looks +like: + +``` + { type_id, bytes_encoding_a_value_of_a_type_identified_by_type_id } +``` + +I.e., an opaque datum and an identifier of what kind of datum that is. This +happens because the structure with the typed hole is used in contexts where it +can't know all possible things that can go in it. In many cases we do know +what all possible things are that can go in a typed hole, but many years ago +didn't, say, or anyways, had a reason to use a typed hole. + +These are used not only in protocols that use ASN.1, but in many protocols that +use syntaxes and encodings unrelated to ASN.1. I.e., these concepts are *not* +ASN.1-specific. + +Many Internet protocols use typed holes, and many use typed holes in ASN.1 +types. For example, PKIX, Kerberos, LDAP, and others, use ASN.1 and typed +holes. + +For examples of an Internet protocol that does not use ASN.1 but which still +has typed holes, see IP, MIME, SSHv2, IKEv2, and others. Most quintessentilly, +IP itself, since IP packet payloads are for some upper layer protocol +identified in the IP packet header. + +In ASN.1 these generally look like: + +```ASN.1 + TypedHole ::= SEQUENCE { + typeId INTEGER, + opaque OCTET STRING + } +``` + +or + +```ASN.1 + -- Old ASN.1 style + TypedHole ::= SEQUENCE { + typeId OBJECT IDENTIFIER, + opaque ANY DEFINED BY typeID + } +``` + +or + +```ASN.1 + -- Old ASN.1 style + TypedHole ::= SEQUENCE { + typeId OBJECT IDENTIFIER, + opaque ANY -- DEFINED BY typeID + } +``` + +or any number of variations. + + Note: the `ANY` variations are no longer conformant to X.680 (the base + ASN.1 specification). + +The pattern is `{ id, hole }` where the `hole` is ultimately an opaque sequence +of bytes whose content's schema is identified by the `id` in the same data +structure. The pattern does not require just two fields, and it does not +require any particular type for the hole, nor for the type ID. Sometimes the +"hole" is an `OCTET STRING`, sometimes it's a `BIT STRING`, sometimes it's an +`ANY` or `ANY DEFINED BY`. Sometimes the hole is even an array of (`SET OF` or +`SEQUENCE OF`, in ASN.1) values of the type identified by the id field. + +An example from PKIX: + +```ASN.1 +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, -- <- type ID + critical BOOLEAN OPTIONAL, + extnValue OCTET STRING, -- <- hole +} +``` + +which shows that typed holes don't always have just three fields, and the type +identifier isn't always an integer. + +Now, Heimdal's ASN.1 compiler generates the obvious C data structure for PKIX's +`Extension` type: + +```C + typedef struct Extension { + heim_oid extnID; + int *critical; + heim_octet_string extnValue; + } Extension; +``` + +and applications using this compiler have to inspect the `extnID` field, +comparing it to any number of OIDs, to determine the type of `extnValue`, then +must call `decode_ThatType()` to decode whatever that octet string has. + +This is very inconvenient. + +Compare this to the handling of discriminated unions (what ASN.1 calls a +`CHOICE`): + +```C + /* + * ASN.1 definition: + * + * DistributionPointName ::= CHOICE { + * fullName [0] IMPLICIT SEQUENCE OF GeneralName, + * nameRelativeToCRLIssuer [1] RelativeDistinguishedName, + * } + */ + + /* C equivalent */ + typedef struct DistributionPointName { + enum DistributionPointName_enum { + choice_DistributionPointName_fullName = 1, + choice_DistributionPointName_nameRelativeToCRLIssuer + } element; + union { + struct DistributionPointName_fullName { + unsigned int len; + GeneralName *val; + } fullName; + RelativeDistinguishedName nameRelativeToCRLIssuer; + } u; + } DistributionPointName; +``` + +The ASN.1 encoding on the wire of a `CHOICE` value, almost no matter the +encoding rules, looks... remarkably like the encoding of a typed hole. Though +generally the alternatives of a discriminated union have to all be encoded with +the same encoding rules, whereas with typed holes the encoded data could be +encoded in radically different encoding rules than the structure containing it +in a typed hole. + +In fact, extensible `CHOICE`s are handled by our compiler as a discriminated +union one of whose alternatives is a typed hole when the `CHOICE` is +extensible: + +```C + typedef struct DigestRepInner { + enum DigestRepInner_enum { + choice_DigestRepInner_asn1_ellipsis = 0, /* <--- unknown CHOICE arm */ + choice_DigestRepInner_error, + choice_DigestRepInner_initReply, + choice_DigestRepInner_response, + choice_DigestRepInner_ntlmInitReply, + choice_DigestRepInner_ntlmResponse, + choice_DigestRepInner_supportedMechs + /* ... */ + } element; + union { + DigestError error; + DigestInitReply initReply; + DigestResponse response; + NTLMInitReply ntlmInitReply; + NTLMResponse ntlmResponse; + DigestTypes supportedMechs; + heim_octet_string asn1_ellipsis; /* <--- unknown CHOICE arm */ + } u; + } DigestRepInner; +``` + +The critical thing to understand is that our compiler automatically decodes +(and encodes) `CHOICE`s' alternatives, but it used to NOT do that for typed +holes because it knows nothing about them. Now, however, our compiler can +do this for typed holes provided the module specifies what the alternatives +are. + +It would be nice if we could treat *all* typed holes like `CHOICE`s whenever +the compiler knows the alternatives! + +And that's exactly what the ASN.1 IOS system makes possible. With ASN.1 IOS +support, our compiler can automatically decode all the `Certificate` +extensions, and all the distinguished name extensions it knows about. + +There is a fair bit of code in `lib/hx509/` that deals with encoding and +decoding things in typed holes where the compiler could just handle that +automatically for us, allowing us to delete a lot of code. + +Even more importantly, if we ever add support for visual encoding rules of +ASN.1, such as JSON Encoding Rules (JER) [X.697] or Generic String Encoding +Rules (GSER) [RFC2641], we could have a utility program to automatically +display or compile DER (and other encodings) of certifcates and many other +interesting data structures. + +Indeed, we do now have such a utility (`asn1_print`), able to transcode DER to +JSON. + +## ASN.1 IOS, Constraint, and Parameterization + +The ASN.1 IOS is additional syntax that allows ASN.1 module authors to express +all the details about typed holes that ASN.1 compilers need to make developers' +lives much easier. + +RFC5912 has lots of examples, such as this `CLASS` corresponding to the +`Extension` type from PKIX: + +```ASN.1 + -- A class that provides some of the details of the PKIX Extension typed + -- hole: + EXTENSION ::= CLASS { + -- The following are fields of a class (as opposed to "members" of + -- SEQUENCE or SET types): + &id OBJECT IDENTIFIER UNIQUE, -- This is a fixed-type value field. + -- UNIQUE -> There can be only one + -- object with this OID + -- in any object set of + -- this class. + -- I.e., this is like a + -- PRIMARY KEY in a SQL + -- TABLE spec. + &ExtnType, -- This is a type field (the hole). + &Critical BOOLEAN DEFAULT {TRUE | FALSE } -- fixed-type value set field. + } WITH SYNTAX { + -- This is a specification of easy to use (but hard-to-parse) syntax for + -- specifying instances of this CLASS: + SYNTAX &ExtnType IDENTIFIED BY &id + [CRITICALITY &Critical] + } + + -- Here's a parameterized Extension type. The formal parameter is an as-yet + -- unspecified set of valid things this hole can carry for some particular + -- instance of this type. The actual parameter will be specified later (see + -- below). + Extension{EXTENSION:ExtensionSet} ::= SEQUENCE { + -- The type ID has to be the &id field of the EXTENSION CLASS of the + -- ExtensionSet object set parameter. + extnID EXTENSION.&id({ExtensionSet}), + -- This is the critical field, whose DEFAULT value should be that of + -- the &Critical field of the EXTENSION CLASS of the ExtensionSet object + -- set parameter. + critical BOOLEAN + -- (EXTENSION.&Critical({ExtensionSet}{@extnID})) + DEFAULT FALSE, + -- Finally, the hole is an OCTET STRING constrained to hold the encoding + -- of the type named by the &ExtnType field of the EXTENSION CLASS of the + -- ExtensionSet object set parameter. + -- + -- Note that for all members of this SEQUENCE, the fields of the object + -- referenced must be of the same object in the ExtensionSet object set + -- parameter. That's how we get to say that some OID implies some type + -- for the hole. + extnValue OCTET STRING (CONTAINING + EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + -- contains the DER encoding of the ASN.1 value + -- corresponding to the extension type identified + -- by extnID + } + + -- This is just a SEQUENCE of Extensions, the parameterized version. + Extensions{EXTENSION:ExtensionSet} ::= + SEQUENCE SIZE (1..MAX) OF Extension{{ExtensionSet}} +``` + +and these uses of it in RFC5280 (PKIX base) where the actual parameter is +given: + +```ASN.1 + -- Here we have an individual "object" specifying that the OID + -- id-ce-authorityKeyIdentifier implies AuthorityKeyIdentifier as the hole + -- type: + ext-AuthorityKeyIdentifier EXTENSION ::= { SYNTAX + AuthorityKeyIdentifier IDENTIFIED BY + id-ce-authorityKeyIdentifier } + + -- And here's the OID, for completeness: + id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + ... + + -- And Here's an object set for the EXTENSION CLASS collecting a bunch of + -- related extensions (here they are the extensions that certificates can + -- carry in their extensions member): + CertExtensions EXTENSION ::= { + ext-AuthorityKeyIdentifier | ext-SubjectKeyIdentifier | + ext-KeyUsage | ext-PrivateKeyUsagePeriod | + ext-CertificatePolicies | ext-PolicyMappings | + ext-SubjectAltName | ext-IssuerAltName | + ext-SubjectDirectoryAttributes | + ext-BasicConstraints | ext-NameConstraints | + ext-PolicyConstraints | ext-ExtKeyUsage | + ext-CRLDistributionPoints | ext-InhibitAnyPolicy | + ext-FreshestCRL | ext-AuthorityInfoAccess | + ext-SubjectInfoAccessSyntax, ... } + ... + + -- Lastly, we have a Certificate, and the place where the Extensions type's + -- actual parameter is specified. + -- + -- This is where the rubber meets the road: + + Certificate ::= SIGNED{TBSCertificate} + + TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier{SIGNATURE-ALGORITHM, + {SignatureAlgorithms}}, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + ... , + [[2: -- If present, version MUST be v2 + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL + ]], + [[3: -- If present, version MUST be v3 -- + extensions [3] Extensions{{CertExtensions}} OPTIONAL + -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + -- The rubber meets the road *here*. + -- + -- This says that the set of *known* certificate + -- extensions are those for which there are "objects" + -- in the "object set" named CertExtensions. + ]], ... } +``` + +Notice that the `extensions` field of `TBSCertificate` is of type `Extensions` +parametrized by the `CertExtensions` "information object set". + +This allows the compiler to know that if any of the OIDs listed in the +`CertExtensions` object set appear as the actual value of the `extnID` member +of an `Extension` value, then the `extnValue` member of the same `Extension` +value must be an instance of the type associated with that OID. For example, +an `Extension` with `extnID` value of `id-ce-authorityKeyIdentifier` must have +an `extnValue` of type `AuthorityKeyIdentifier`. + + +### IOS Crash Course + +The ASN.1 IOS may be... a bit difficult to understand -- the syntax isn't +pretty. And 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]`. Then there's "objects" and "object +sets". Hopefully this section will make all of that comprehensible. + +_Classes_ have fields of various kinds. More on this below. + +_Classes_ can also have zero, one, or more _object sets_ associated with them, +and each object set has zero, one, or more _objects_ that are also themselves +associated with classes. Each object has a setting for each required field of +a class, and possibly also for optional/defaulted fields as well. + +As X.681 explains, IOS object sets really are akin to relational database +tables, while objects are akin to rows of the same, with columns specified by +classes. + +Or one can think of _classes_ as relational tables with one predefined column +naming object sets, and rows being objects grouped into object sets by that +column. IOS supports complex path expressions across these objects (but we +won't need to support that yet). + +These relational entities are immutable in that they are defined in ASN.1 +modules that are compiled and there is no way to change them at run-time, only +query them (although perhaps object sets marked as extensible are intended to +be extensible at run-time?). To mutate them one must edit the ASN.1 module +that defines them and recompile it. IOS entities also have no on-the-wire +representation. + +So far, the IOS seems just so useless to us: we have some, but non-urgent need +to specify immutable relational data. For example, cryptosystem parameters, +which PKIX does define using IOS, but again: not urgent. + +The magic for us lies in being able to document and constrain actual datatypes +using the IOS [X.681], constraint specification [X.682], and type +parameterization [X.683]. We can express the following things: + + - that some _member_ of a `SET` or `SEQUENCE` is of open type + + - that some _member_ of a `SET` or `SEQUENCE` identifies a type encoded into + an open type member of the same (or related) `SET` or `SEQUENCE` + + - what pairs of `{type ID value, type}` are allowed for some `SET`'s or + `SEQUENCE`'s open type members + +With this our ASN.1 compiler has the metadata it needs in order to +auto-generate decoding and encoding of values of open types. + +A termnology point: `CHOICE`, `SET`, and `SEQUENCE` types have "members", but +_classes_ and _objects_ have "fields", and _object sets_ have "elements". + +Objects must have "_settings_" for all the required fields of the object's +class and none, some, or all 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 is +useful that we explain them by reference to how they relate to the members of +`SEQUENCE` types constrained by object sets: + + - A `type field` of a class is one that specifies a `SET` or `SEQUENCE` member + of unknown (i.e., 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. + + This is essentially a "type variable", akin to those seen in high-level + languages like Haskell. + + - 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, naturally. + + - 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 + same class), which can be used to provide rich hierarchical type semantics + that... we mostly don't need for now. + + These define relations between classes, much like `FOREIGN KEY`s in SQL. + + These are also known as `link fields`. + + - 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. + +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 of `EXTENSION` 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. + + Note that `UNIQUE` keyword tells us there can be only one object with any + given value of this field in any object set of this class. (There is no way + to specify the equivalent of a multi-column `PRIMARY KEY` from SQL, only + single-column primary/unique keys. Note that the `&id` field is not marked + `OPTIONAL` or `DEFAULT`, which is like saying it's `NOT NULL` in SQL.) + + - 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. + + In-tree we could avoid having to implement fixed-type value set fields by + renaming this one to `&critical` and eliding its `DEFAULT <ValueSet>` given + that we know there are only two possible values for a `BOOLEAN` field. + + - Ignore the `WITH SYNTAX` clause for now. All it does is specify a + user-friendly but implementor-hostile syntax for specifying objects. + +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 (at least RFC 5912) 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 (or maybe just one), +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({KnownOtherNames}), + -- ^^^^^^^^^^^^^^^^^ + -- rubber & road meet! + ... + } +``` + +(The `CertExtensions` and `KnownOtherNames` object sets are not shown here for +brevity. PKIX doesn't even define an `KnownOtherNames` 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 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 { + 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`, though we can for +`OTHER-NAME`.) + +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. 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. + +## Usage + +To use this feature you must use the `--template` and `--one-code-file` +arguments to `asn1_compile`. C types are generated from ASN.1 types as +described above. + +Note that failure to decode open type values does not cause decoding to fail +altogether. It is important that applications check for undecoded open types. +Open type decoding failures manifest as `NULL` values for the `u` field of the +decoded open type structures (see above). + +For examples of X.681/X.682/X.683 usage, look at `lib/asn1/rfc2459.asn1`. + +## Limitations + + - `AtNotation` supported is very limited. + + - Object set extensibility is not supported. + + - Only one formal (and actual) type parameter is supported at this time. + + - `TYPE-IDENTIFIER` is not built-in at this time. (But users can define it as + specified.) + + - `CLASS` "copying" is not supported at this time. + + - Link fields are not supported. + + - `Information from objects` constructs are not supported. + + - `IMPORTS` of IOS entities are not supported at this time. + + - ... + +## Implementation Design + +NOTE: This has already be implemented in the `master` branch of Heimdal. + + - The required specifications, X.681, X.682, and X.683, are fairly large and + non-trivial. We can implement just the subset of those three that we need + to implement PKIX, just as we already implement just the subset of X.680 + that we need to implement PKIX and Kerberos. + + For dealing with PKIX, the bare minimum of IOS classes we want are: + + - `ATTRIBUTE` (used for `DN` attributes in RFC5280, specifically for the + `SingleAttribute` and `AttributeSet` types, RDNs, and the + `subjectDirectoryAttributes` extension) + - `EXTENSION` (used for `Extension`, i.e., certificate extensions in + RFC5280) + - `TYPE-IDENTIFIER` (used for `OtherName` and for CMS' `Content-Type`) + + The minimal subset of X.681, X.682, and X.683 needed to implement those + three is all we need. + + _Eventually_ we may want to increase that subset so as to implement other + IOS classes from PKIX, such as `DIGEST-ALGORITHM`, and to provide object + sets and query functionality for them to applications so that we can use + standard modules to encode information about cryptosystems. But not right + now. + + Note that there's no object set specified for OTHER-NAME instances, but we + can and have creates our own. We want magic open type decoding to recurse + all the way down and handle DN attributes, extensions, SANs, policy + qualifiers, the works. + + - We'll really want to do this mainly for the template compiler and begin + abandoning the original compiler. The codegen backend generates the same C + types, but no code for automatic, recursive handling of open types. + + Maintaining two compiler backends is difficult enough; adding complex + features beyond X.680 to both is too much work. The template compiler is + simply superior just on account of its output size scaling as `O(N)` instead + of `O(M * N)` where `M` is the number of encoding rules supported and `N` is + the size of 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 + adding new ones, that way code that hasn't been updated to use the automatic + encoding/decoding can still work and we can then update Heimdal in-tree + slowly to take advantage of the new magic. + + Below are the C types for the ASN.1 PKIX types we care about, as generated + by the current prototype. + + `Extension` compiles to: + +```C +typedef struct Extension { + heim_oid extnID; + int critical; + heim_octet_string extnValue; + /* NEW: */ + struct { + enum { + choice_Extension_iosnumunknown = 0, + choice_Extension_iosnum_id_x509_ce_authorityKeyIdentifier, + choice_Extension_iosnum_id_x509_ce_subjectKeyIdentifier, + choice_Extension_iosnum_id_x509_ce_keyUsage, + choice_Extension_iosnum_id_x509_ce_privateKeyUsagePeriod, + choice_Extension_iosnum_id_x509_ce_certificatePolicies, + choice_Extension_iosnum_id_x509_ce_policyMappings, + choice_Extension_iosnum_id_x509_ce_subjectAltName, + choice_Extension_iosnum_id_x509_ce_issuerAltName, + choice_Extension_iosnum_id_x509_ce_basicConstraints, + choice_Extension_iosnum_id_x509_ce_nameConstraints, + choice_Extension_iosnum_id_x509_ce_policyConstraints, + choice_Extension_iosnum_id_x509_ce_extKeyUsage, + choice_Extension_iosnum_id_x509_ce_cRLDistributionPoints, + choice_Extension_iosnum_id_x509_ce_inhibitAnyPolicy, + choice_Extension_iosnum_id_x509_ce_freshestCRL, + choice_Extension_iosnum_id_pkix_pe_authorityInfoAccess, + choice_Extension_iosnum_id_pkix_pe_subjectInfoAccess, + } element; + union { + void *_any; + AuthorityKeyIdentifier* ext_AuthorityKeyIdentifier; + SubjectKeyIdentifier* ext_SubjectKeyIdentifier; + KeyUsage* ext_KeyUsage; + PrivateKeyUsagePeriod* ext_PrivateKeyUsagePeriod; + CertificatePolicies* ext_CertificatePolicies; + PolicyMappings* ext_PolicyMappings; + GeneralNames* ext_SubjectAltName; + GeneralNames* ext_IssuerAltName; + BasicConstraints* ext_BasicConstraints; + NameConstraints* ext_NameConstraints; + PolicyConstraints* ext_PolicyConstraints; + ExtKeyUsage* ext_ExtKeyUsage; + CRLDistributionPoints* ext_CRLDistributionPoints; + SkipCerts* ext_InhibitAnyPolicy; + CRLDistributionPoints* ext_FreshestCRL; + AuthorityInfoAccessSyntax* ext_AuthorityInfoAccess; + SubjectInfoAccessSyntax* ext_SubjectInfoAccessSyntax; + } u; + } _ioschoice_extnValue; +} Extension; +``` + + The `SingleAttribute` and `AttributeSet` types compile to: + +```C +typedef struct SingleAttribute { + heim_oid type; + HEIM_ANY value; + struct { + enum { + choice_SingleAttribute_iosnumunknown = 0, + choice_SingleAttribute_iosnum_id_at_name, + choice_SingleAttribute_iosnum_id_at_surname, + choice_SingleAttribute_iosnum_id_at_givenName, + choice_SingleAttribute_iosnum_id_at_initials, + choice_SingleAttribute_iosnum_id_at_generationQualifier, + choice_SingleAttribute_iosnum_id_at_commonName, + choice_SingleAttribute_iosnum_id_at_localityName, + choice_SingleAttribute_iosnum_id_at_stateOrProvinceName, + choice_SingleAttribute_iosnum_id_at_organizationName, + choice_SingleAttribute_iosnum_id_at_organizationalUnitName, + choice_SingleAttribute_iosnum_id_at_title, + choice_SingleAttribute_iosnum_id_at_dnQualifier, + choice_SingleAttribute_iosnum_id_at_countryName, + choice_SingleAttribute_iosnum_id_at_serialNumber, + choice_SingleAttribute_iosnum_id_at_pseudonym, + choice_SingleAttribute_iosnum_id_domainComponent, + choice_SingleAttribute_iosnum_id_at_emailAddress, + } element; + union { + void *_any; + X520name* at_name; + X520name* at_surname; + X520name* at_givenName; + X520name* at_initials; + X520name* at_generationQualifier; + X520CommonName* at_x520CommonName; + X520LocalityName* at_x520LocalityName; + DirectoryString* at_x520StateOrProvinceName; + DirectoryString* at_x520OrganizationName; + DirectoryString* at_x520OrganizationalUnitName; + DirectoryString* at_x520Title; + heim_printable_string* at_x520dnQualifier; + heim_printable_string* at_x520countryName; + heim_printable_string* at_x520SerialNumber; + DirectoryString* at_x520Pseudonym; + heim_ia5_string* at_domainComponent; + heim_ia5_string* at_emailAddress; + } u; + } _ioschoice_value; +} SingleAttribute; +``` + + and + +```C +typedef struct AttributeSet { + heim_oid type; + struct AttributeSet_values + { + unsigned int len; + HEIM_ANY* val; + } values; + struct { + enum { + choice_AttributeSet_iosnumunknown = 0, + choice_AttributeSet_iosnum_id_at_name, + choice_AttributeSet_iosnum_id_at_surname, + choice_AttributeSet_iosnum_id_at_givenName, + choice_AttributeSet_iosnum_id_at_initials, + choice_AttributeSet_iosnum_id_at_generationQualifier, + choice_AttributeSet_iosnum_id_at_commonName, + choice_AttributeSet_iosnum_id_at_localityName, + choice_AttributeSet_iosnum_id_at_stateOrProvinceName, + choice_AttributeSet_iosnum_id_at_organizationName, + choice_AttributeSet_iosnum_id_at_organizationalUnitName, + choice_AttributeSet_iosnum_id_at_title, + choice_AttributeSet_iosnum_id_at_dnQualifier, + choice_AttributeSet_iosnum_id_at_countryName, + choice_AttributeSet_iosnum_id_at_serialNumber, + choice_AttributeSet_iosnum_id_at_pseudonym, + choice_AttributeSet_iosnum_id_domainComponent, + choice_AttributeSet_iosnum_id_at_emailAddress, + } element; + unsigned int len; + union { + void *_any; + X520name* at_name; + X520name* at_surname; + X520name* at_givenName; + X520name* at_initials; + X520name* at_generationQualifier; + X520CommonName* at_x520CommonName; + X520LocalityName* at_x520LocalityName; + DirectoryString* at_x520StateOrProvinceName; + DirectoryString* at_x520OrganizationName; + DirectoryString* at_x520OrganizationalUnitName; + DirectoryString* at_x520Title; + heim_printable_string* at_x520dnQualifier; + heim_printable_string* at_x520countryName; + heim_printable_string* at_x520SerialNumber; + DirectoryString* at_x520Pseudonym; + heim_ia5_string* at_domainComponent; + heim_ia5_string* at_emailAddress; + } *val; + } _ioschoice_values; +} AttributeSet; +``` + + The `OtherName` type compiles to: + +```C +typedef struct OtherName { + heim_oid type_id; + HEIM_ANY value; + struct { + enum { + choice_OtherName_iosnumunknown = 0, + choice_OtherName_iosnum_id_pkix_on_xmppAddr, + choice_OtherName_iosnum_id_pkix_on_dnsSRV, + choice_OtherName_iosnum_id_pkix_on_hardwareModuleName, + choice_OtherName_iosnum_id_pkix_on_permanentIdentifier, + choice_OtherName_iosnum_id_pkix_on_pkinit_san, + choice_OtherName_iosnum_id_pkix_on_pkinit_ms_san, + } element; + union { + void *_any; + heim_utf8_string* on_xmppAddr; + heim_ia5_string* on_dnsSRV; + HardwareModuleName* on_hardwareModuleName; + PermanentIdentifier* on_permanentIdentifier; + KRB5PrincipalName* on_krb5PrincipalName; + heim_utf8_string* on_pkinit_ms_san; + } u; + } _ioschoice_value; +} OtherName; +``` + + If a caller to `encode_Certificate()` passes a certificate object with + extensions with `_ioselement == choice_Extension_iosnumunknown` (or + whatever, for each open type), then the encoder will use the `extnID` and + `extnValue` fields, otherwise it will use the new `_ioschoice_extnValue` + field and leave `extnID` and `extnValue` cleared. If both are set, the + `extnID` and `extnValue` fields, and also the new `_ioschoice_extnValue` + field, then the encoder will ignore the latter. + + In both cases, the `critical` field gets used as-is. The rule is 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 get mapped to discrete enum values. Object sets get sorted + by object type IDs so that for decoding they can be and are binary-searched. + For encoding and other cases (destructors and copy constructors) we directly + index the object set by the mapped type ID enum. + + - The C header generator remains shared between the two backends. + + - SET and SEQUENCE types containing an open type are represented as follows in + their templates. + +```C + extern const struct asn1_template asn1_CertExtensions[]; + /*...*/ + const struct asn1_template asn1_Extension_tag__22[] = { + /* 0 */ { 0, sizeof(struct Extension), ((void*)5) }, + /* 1 */ { A1_TAG_T(ASN1_C_UNIV, PRIM, UT_OID), + offsetof(struct Extension, extnID), + asn1_AttributeType_tag__1 }, + /* 2 */ { A1_OP_DEFVAL | A1_DV_BOOLEAN, ~0, (void*)0 }, + /* 3 */ { A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Boolean) | A1_FLAG_DEFAULT, + offsetof(struct Extension, critical), + asn1_Extension_tag_critical_24 }, + /* 4 */ { A1_TAG_T(ASN1_C_UNIV, PRIM, UT_OctetString), + offsetof(struct Extension, extnValue), + asn1_Extension_tag_extnValue_25 }, + /* NEW: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ + /* 5 */ { A1_OP_OPENTYPE_OBJSET | 0 | (2 << 10) | 0, + offsetof(Extension, _ioschoice_extnValue), + asn1_CertExtensions } + }; + const struct asn1_template asn1_Extension[] = { + /* 0 */ { 0, sizeof(Extension), ((void*)1) }, + /* 1 */ { A1_TAG_T(ASN1_C_UNIV, CONS, UT_Sequence), + 0, asn1_Extension_tag__22 } + }; + + /* NEW: */ + const struct asn1_template asn1_CertExtensions[] = { + /* + * Header template entry bearing the count of objects in + * this object set: + */ + /* 0 */ { 0, 0, ((void*)18) }, + + /* + * Value of object #0 in this set: two entries, one naming + * a type ID field value, and the other naming the type + * that corresponds to that value. + * + * In this case, the first object is for the + * AuthorityKeyIdentifier type as a certificate extension. + */ + /* 1 */ { A1_OP_OPENTYPE_ID, 0, + (const void*)&asn1_oid_id_x509_ce_authorityKeyIdentifier }, + /* 2 */ { A1_OP_OPENTYPE, sizeof(AuthorityKeyIdentifier), + (const void*)&asn1_AuthorityKeyIdentifier }, + + /* Value of object #1 (SubjectKeyIdentifier): */ + + /* 3 */ { A1_OP_OPENTYPE_ID, 0, + (const void*)&asn1_oid_id_x509_ce_subjectKeyIdentifier }, + /* 4 */ { A1_OP_OPENTYPE, sizeof(SubjectKeyIdentifier), + (const void*)&asn1_SubjectKeyIdentifier }, + /* 5 */ + + /* And so on...*/ + + /* Value of object #17 */ + /* 35 */ { A1_OP_OPENTYPE_ID, 0, + (const void*)&asn1_oid_id_pkix_pe_subjectInfoAccess }, + /* 36 */ { A1_OP_OPENTYPE, sizeof(SubjectInfoAccessSyntax), + (const void*)&asn1_SubjectInfoAccessSyntax } + }; +``` + + After the template entries for all the normal fields of a struct there will + be an object set reference entry identifying the type ID and open type + fields's entries' indices in the same template. The object set has a header + entry followed by pairs of entries each representing a single object and all + of them representing the object set. + + This allows the encoder and decoder to both find the object set quickly, + especially since the objects are sorted by type ID value. + +## Moving From C + + - Generate and output a JSON representation of the compiled ASN.1 module. + + - Code codegen/templategen backends in jq or Haskell or whatever. + + - Code template interpreters in <host> language. + + - Eventually rewrite the compiler itself in Rust or whatever. diff --git a/third_party/heimdal/lib/asn1/README-template.md b/third_party/heimdal/lib/asn1/README-template.md new file mode 100644 index 0000000..9f1b60f --- /dev/null +++ b/third_party/heimdal/lib/asn1/README-template.md @@ -0,0 +1,278 @@ + +#Notes on Heimdal's ASN.1 compiler's "template" backend + +```bash +size .libs/libasn1.dylib +size .libs/libasn1base.a | awk '{sum += $1} END {print sum}' | sed 's/^/TEXT baselib: /' +size .libs/asn1_*.o | awk '{sum += $1} END {print sum}' | sed 's/^/generated code stubs: /' +size *_asn1-template.o | awk '{sum += $1} END {print sum}' | sed 's/^/TEXT stubs: /' +``` + +Notes about the template parser: + + - assumption: code is large, tables smaller + + - size scales better as features as added: + + - adding encoding rules, textual value parsers, comparators, and so on, are + just new template interpreter, and generally that means no change to + templates. + + - so template sizing scales like `O(M + N)` where `M` is the size of the + modules and `N` is the size of the interpreters + + - but codegen sizing scales like `O(M * N)` + + - as we add interpreters the size advantage of templates increases + + - smaller tables and code, more memory sharing, smaller cache footprint, + should lead to better performance + + - templates are shared for encode/decode/free/copy/print interpreters, + whereas none of those operations as generated by the codegen backend + share any code + + - very compressible -- we waste a lot of space in `struct asn1_template` on + 64-bit systems, and still it's smaller than the code generated by the + codegen backend + + Note that the template backend does currently dedup templates, though that + is a quadratic operation that we may eventually have to make optional (right + now it's not a problem). + + If we made the `ptr` field a `uint32_t` instead of a pointer, and wrote a + linker for templates, and squeezed out some bits of `tt` and `offset` (we'll + never need even 8 bits for tags, let alone 20!, and we'll never need 32 bits + for struct sizes and field offsets either, maybe not even 16-bits), we could + cut the size of `struct asn1_template` in half. + + Also, once we add OER/JER we could have an option to not support TLV ERs and + then drop a lot of the tag-related parts of the minified AST that templates + are, further shrinking the templates. + + The smaller the templates, the faster interpreting will be. + + - use explicit stack instead of recursion in template interpreter to reduce + stack use and increase speed + + The code generated by the codegen backend is also recursive, though the + compiler could inline some calls. Using an explicit stack in an iterative + interpreter would likely be a big win. + + - how to generate template based stubs + + (Note: it's now the default for Heimdal itself.) + + Use the `--template` option to `asn1_compile` to use the template backend, + or leave it off to use the codegen backend. + + - the template backend now has more functionality than the codegen backend + + - much easier to extend! adding new encoding rules is just adding a few + functions to template.c, one set of length/encode/decode functions per ER, + so we could add OER/PER/XDR/GSER/JER with very little work outside that one + file and `gen_template.c` (to generate stub functions and possibly slight + alterations to templates) and gen.c (to generate declarations of those stub + functions). + + - template decoding has been fuzzed extensively with American Fuzzy Lop (AFL) + +TODO: + + - Generate templates for enumerations, with their names and values, so that + values of enumerated types can be printed. + + - Remove old fuzzer. Rely on AFL only. + + - Fuzzing tests, always more fuzzing: + + - Instructions: + +``` + $ git clone https://github.com/heimdal/heimdal + $ cd heimdal + $ srcdir=$PWD + $ autoreconf -fi + $ + $ mkdir build + $ cd build + $ + $ ../configure --srcdir=$srcdir ... + $ make -j4 + $ + $ cd lib/asn1 + $ make clean + $ AFL_HARDEN=1 make -j4 asn1_print check CC=afl-gcc # or CC=afl-clang + $ + $ # $srcdir/lib/asn1/fuzz-inputs/ has at least one minimized DER value + $ # produced by taking an EK certificate and truncating the signatureValue + $ # and tbsCertificate.subjectPublicKeyInfo fields then re-encoding, thus + $ # cutting down the size of the certificate by 45%. AFL finds interesting + $ # code paths much faster if the input corpus is minimized. + $ + $ mkdir f + $ ../../libtool --mode=execute afl-fuzz -i $srcdir/lib/asn1/fuzz-inputs -o $PWD/f ./asn1_print '@@' Certificate + $ + $ # Or + $ ../../libtool --mode=execute afl-fuzz -i $srcdir/lib/asn1/fuzz-inputs -o $PWD/f ./asn1_print -A '@@' + $ + $ # Examine crash reports, if any. Each crash report consists of an input + $ # that caused a crash, so run valgrind on each such input: + $ + $ for i in f/crashes/id*; do + > echo $i + > ../../libtool --mode=execute valgrind --num-callers=64 ./asn1_print $i \ + > Certificate IOSCertificationRequest >/dev/null 2> f/crashes/vg-${i##*/} + > done + $ + $ # then review the valgrind output: + $ $PAGER f/crashes/vg-* +``` + + - Here's a screenshot of AFL running on the previous commit: + +``` + american fuzzy lop 2.52b (asn1_print) + +┌─ process timing ─────────────────────────────────────┬─ overall results ─────┐ +│ run time : 1 days, 22 hrs, 39 min, 51 sec │ cycles done : 18 │ +│ last new path : 0 days, 0 hrs, 38 min, 5 sec │ total paths : 2310 │ +│ last uniq crash : none seen yet │ uniq crashes : 0 │ +│ last uniq hang : none seen yet │ uniq hangs : 0 │ +├─ cycle progress ────────────────────┬─ map coverage ─┴───────────────────────┤ +│ now processing : 997* (43.16%) │ map density : 2.19% / 8.74% │ +│ paths timed out : 0 (0.00%) │ count coverage : 3.25 bits/tuple │ +├─ stage progress ────────────────────┼─ findings in depth ────────────────────┤ +│ now trying : interest 16/8 │ favored paths : 319 (13.81%) │ +│ stage execs : 13.1k/13.4k (98.18%) │ new edges on : 506 (21.90%) │ +│ total execs : 91.9M │ total crashes : 0 (0 unique) │ +│ exec speed : 576.2/sec │ total tmouts : 2158 (180 unique) │ +├─ fuzzing strategy yields ───────────┴───────────────┬─ path geometry ────────┤ +│ bit flips : 565/5.60M, 124/5.60M, 74/5.59M │ levels : 19 │ +│ byte flips : 4/699k, 17/375k, 15/385k │ pending : 552 │ +│ arithmetics : 323/20.7M, 8/10.6M, 1/517k │ pend fav : 0 │ +│ known ints : 85/1.76M, 148/9.98M, 175/16.8M │ own finds : 2308 │ +│ dictionary : 0/0, 0/0, 12/6.62M │ imported : n/a │ +│ havoc : 757/6.35M, 0/0 │ stability : 100.00% │ +│ trim : 14.30%/336k, 46.60% ├────────────────────────┘ +└─────────────────────────────────────────────────────┘ [cpu000:196%] +``` + + - TODO: Make building with AFL a ./cofigure option. + + - TODO: Make fuzzing with AFL a make target. + + - Fuzz decode round-tripping (don't just decode, but also encoded the + decoded). + + - Performance testing + + - `ASN1_MALLOC_ENCODE()` as a function, replaces `encode_` and `length_` + + - Fix SIZE constraits + + - Proper implementation of `SET { ... }` + + - Compact types that only contain on entry to not having a header. + + +SIZE - Futher down is later generations of the template parser + +``` + code: + ================== + __TEXT __DATA __OBJC others dec hex + 462848 12288 0 323584 798720 c3000 (O2) + + trivial types: + ================== + __TEXT __DATA __OBJC others dec hex + 446464 12288 0 323584 782336 bf000 (O2) + + OPTIONAL + ================== + __TEXT __DATA __OBJC others dec hex + 425984 16384 0 323584 765952 bb000 (O2) + + SEQ OF + ================== + __TEXT __DATA __OBJC others dec hex + 368640 32768 0 327680 729088 b2000 (O2) + 348160 32768 0 327680 708608 ad000 (Os) + + BOOLEAN + ================== + 339968 32768 0 327680 700416 ab000 (Os) + + TYPE_EXTERNAL: + ================== + 331776 32768 0 327680 692224 a9000 (Os) + + SET OF + ================== + 327680 32768 0 327680 688128 a8000 (Os) + + TYPE_EXTERNAL everywhere + ================== + __TEXT __DATA __OBJC others dec hex + 167936 69632 0 327680 565248 8a000 (Os) + + TAG uses ->ptr (header and trailer) + ================== + 229376 102400 0 421888 753664 b8000 (O0) + + TAG uses ->ptr (header only) + ================== + 221184 77824 0 421888 720896 b0000 (O0) + + BER support for octet string (not working) + ================== + 180224 73728 0 417792 671744 a4000 (O2) + + CHOICE and BIT STRING missign + ================== + __TEXT __DATA __OBJC others dec hex + 172032 73728 0 417792 663552 a2000 (Os) + + No accessor functions to global variable + ================== + __TEXT __DATA __OBJC others dec hex + 159744 73728 0 393216 626688 99000 (Os) + + All types tables (except choice) (id still objects) + ================== + __TEXT __DATA __OBJC others dec hex + 167936 77824 0 421888 667648 a3000 + base lib: 22820 + + __TEXT __DATA __OBJC others dec hex + ================== + 167936 77824 0 421888 667648 a3000 (Os) + baselib: 22820 + generated code stubs: 41472 + TEXT stubs: 112560 + + All types, id still objects + ================== + __TEXT __DATA __OBJC others dec hex + 155648 81920 0 430080 667648 a3000 (Os) + TEXT baselib: 23166 + generated code stubs: 20796 + TEXT stubs: 119891 + + All types, id still objects, dup compression + ================== + __TEXT __DATA __OBJC others dec hex + 143360 65536 0 376832 585728 8f000 (Os) + TEXT baselib: 23166 + generated code stubs: 20796 + TEXT stubs: 107147 + + All types, dup compression, id vars + ================== + __TEXT __DATA __OBJC others dec hex + 131072 65536 0 352256 548864 86000 + TEXT baselib: 23166 + generated code stubs: 7536 + TEXT stubs: 107147 +``` diff --git a/third_party/heimdal/lib/asn1/README.md b/third_party/heimdal/lib/asn1/README.md new file mode 100644 index 0000000..9c4e697 --- /dev/null +++ b/third_party/heimdal/lib/asn1/README.md @@ -0,0 +1,1327 @@ +# Heimdal's ASN.1 Compiler + +This is a new README, and it's not very rich in contents yet. Be sure to check +out the [README on the template backend](/lib/asn1/README-template.md) and the [README +on automatic open type decoding via X.681/X.682/X.683 +annotations](/lib/asn1/README-X681.md). + +## Table of Contents + + 1. [Introduction](#Introduction) + 2. [ASN.1 Support in Heimdal](#asn1-support-in-heimdal) + 3. [News](#News) + 4. [Features](#Features) + 5. [Limitations](#Limitations) + 6. [Compiler Usage](#Compiler-usage) + 7. [APIs Generated by the Compiler](#APIs-generated-by-the-compiler) + 8. [`asn1_print` Usage](#asn1_print-usage) + 9. [Implementation](#implementation) + 10. [Moving From C](#moving-from-c) + +## Introduction + +ASN.1 is a... some would say baroque, perhaps obsolete, archaic even, "syntax" +for expressing data type schemas, and also a set of "encoding rules" (ERs) that +specify many ways to encode values of those types for interchange. + +Some ERs are binary, others are textual. Some binary ERs are tag-length-value +(TLV), others have no need for tagging. Some of the ERs are roundly and +rightly disliked, but then there are XER (XML Encoding Rules) and JER (JSON +Encoding Rules) that really illustrate how the syntax and the encoding rules +really are separate and distinct things. + +ASN.1 is a wheel that everyone loves to reinvent, and often badly. It's worth +knowing a bit about it before reinventing this wheel badly yet again. + +It's also worth pondering that there appears to be ways to map most data +exchange metaschemas and schemas onto others, and therefore too, transliterate +most encodings onto others. + +First, an example of the syntax: + +```ASN.1 +-- This is what a certificate looks like (as in TLS server certificates, or +-- "SSL certs): +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING +} + +-- The main body of a certificate is here though: +TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT 1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT BIT STRING OPTIONAL, + subjectUniqueID [2] IMPLICIT BIT STRING OPTIONAL, + extensions [3] EXPLICIT Extensions OPTIONAL +} +``` + +Here we see something akin to a "structure" or "record" with various named +fields of various types. Some of these are optional, which means they can have +no value given in encodings. One is defaulted, which means that if no values +is given in encodings then the default value is intended. + +Those `[0]` things are called tags and are decidedly obsolete, along with all +"tag-length-value" (TLV) or "self-describing" encoding rules. Tags appear as +lexical tokens in ASN.1 only because a) in the early 80s TLV encodings were +thought fantastic, and b) automatic tagging wasn't invented and implemented +until it was too late. New ASN.1 modules should never need to have those tags +appear in the syntax. + +ASN.1 has a lot of competition, and may even be obsolete. Obsolete +technologies take decades to die out because of the need to interoperate with +the installed base. So even if ASN.1 is obsolete, we find ourselves needing to +implement a large subset of it in order to implement certain important network +protocols. + +Encoding rules? There are many: + + - JSON Encoding Rules (JER) ([X.697](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.697)) + + Use JSON instead of some binary scheme like DER (see below). + + - XML Encoding Rules (XER) ([X.693](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.693)) + + - Generic String Encoding Rules (GSER) ([RFC3641](https://tools.ietf.org/html/rfc3641)) + + - Basic, Distinguished, and Canonical Encoding Rules (BER, DER, CER) ([X.690](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.690) + + These are the dreaded tag-length-value encoding rules. They are redundant, + wasteful, and inefficient in spite of being non-textual (i.e., binary)! + + The descriptor "tag-length-value" is due to all values being encoded as some + bytes for a "tag", then some bytes for the length of the encoded value, then + the encoded value itself. The body of a structured type (e.g., + `Certificate`) is itself a concatenation of the TLV encodings of the fields + of that structured type, in order. + + DER and CER are alternative canonical forms of BER. + + - Packed Encoding Rules (PER) ([X.691](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.691)) and Octet Encoding Rules (OER) ([X.696](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.696)) + + These are a lot like eXternal Data Representation + ([XDR](https://tools.ietf.org/html/rfc4506.html)), but with 1-octet + alignment instead of 4-octet alignment. + +There is also a meta encoding rule system, the Encoding Control Notation (ECN) +([X.692](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.692)) +intended to be able to express all sorts of kinds of encodings. + +Heimdal currently only supports DER for encoding, and DER and BER for decoding, +but soon may support JER as well, and can print values as JSON, though not +compliant with JER. + +The syntax itself is specified by +[X.680](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.680), +with extensions via +[X.681](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.681), +[X.682](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.682), +and +[X.683](https://www.itu.int/rec/T-REC-X/recommendation.asp?lang=en&parent=T-REC-X.683),. + +## ASN.1 Support in Heimdal + +Heimdal contains an implementation of: + + - ASN.1 + - PKIX + - Kerberos + - misc. Heimdal-specific protocols related to PKIX and Kerberos, such as: + + - Online certification authority protocols + - Kerberos KDC replication protocols + - Kerberos administration protocols + +PKIX and Kerberos both require ASN.1 and DER support. + +For historical reasons many ASN.1-using projects have used hand-rolled codecs +that have proven difficult to implement, maintain, and extend, and, of course, +buggy. Heimdal has its own ASN.1 module compiler and library in order to avoid +the pitfalls of hand-rolled codecs, and to satisfy Heimdal's internal needs. + +There are other ASN.1 compilers and libraries out there, of course, but it +would prove difficult to switch compilers as generally ASN.1 compilers lack +sufficient control over generated types and APIs for programming languages. + +Heimdal's ASN.1 compiler supports a large subset of X.680, X.681, X.682, and +X.683, as well as a large subset of X.690, with an architecture that should +make it easy to add support for encoding rules other than X.690. + +## News + +In recent times the following features have been added: + + - Feature parity for the "template" backend, even superiority, as the codegen + backend does not yet support automatic open type decoding/encoding. + + - IMPLICIT tagging support is finally complete. + + - Automatic open type traversal, using a subset of X.681/X.682/X.683 for + expressing the requisite metadata. + + - Decoration of ASN.1 types with "hidden" fields (ones that don't get encoded + or decoded) of ASN.1 or C types. + +## Futures + + - JER support? + + - XDR/NDR/OER support? + + - Generate comparators? (lib/hx509 has a half-baked Certificate comparator) + +## Features + + - Most of X.680 is supported. + + - Most of X.690 is supported for decoding, with only DER supported for + encoding. + + - For cryptographic applications there is a `--preserve-binary=TYPE` compiler + option that causes the `TYPE`'s C `struct` to gain a `_save` field where the + original encoding of the `TYPE` is preserved by the decoder. This allows + cryptographic applications to validate signatures, MACs, authenticated + decryption tags, checksums, etc., without having to re-encode the `TYPE` + (which wouldn't even work if the encoding received were BER and BER were + permitted for that `TYPE`). + + - Unconstrained integer types have a large integer representation in C that is + not terribly useful in common cases. Range and member constraints on + integer types cause the compiler to use `int`, `int64_t`, `unsigned int`, + and/or `uint64_t` as appropriate. + + - The Heimdal ASN.1 compiler currently handles a large subset of X.680, and + (in a branch) a small subset of X.681, X.682, and X.683, which manifests as + automatic handling of all open types contained in `SET`/`SEQUENCE` types + that are parameterized with information object sets. This allows all open + types in PKIX certificates, for example, to get decoded automatically no + matter how deeply nested. We use a TCG EK certificate that has eight + certificate extensions, including subject alternative names and subject + directory attributes where the attribute values are not string types, and + all of these things get decoded automatically. + + - The template backend dedups templates to save space. This is an O(N^2) kind + of feature that we need to make optional, but it works. (When we implement + JER this will have the side-effect of printing the wrong type names in some + cases because two or more types have the same templates and get deduped.) + + - There is an _experimental_ ASN.1 module -> JSON feature in the compiler. It + currently dumps type and value definitions, but not class, or object set + definitions. Even for types, it is not complete, and the JSON schema used + is subject to change *WITHOUT NOTICE*. + + Perhaps eventually we can re-write the compiler as a C-coded ASN.1 -> JSON + stage followed by a jq-coded code and template generator state, which would + make it much easier to extend the compiler. + + - We have an `asn1_print` program that can decode DER from any exported types + from any ASN.1 modules committed in Heimdal: + + ```bash + $ ./asn1_print ek.crt Certificate | + jq '.tbsCertificate.extensions[3]._extnValue[]._values' + ``` + + ```JSON + [ + { + "_type": "TPMSpecification", + "family": "2.0", + "level": 0, + "revision": 138 + } + ] + [ + { + "_type": "TPMSecurityAssertions", + "version": 0, + "fieldUpgradable": true, + "ekGenerationType": "ekgt-injected", + "ekGenerationLocation": "tpmManufacturer", + "ekCertificateGenerationLocation": "tpmManufacturer", + "ccInfo": { + "_type": "CommonCriteriaMeasures", + "version": "3.1", + "assurancelevel": "ealevel4", + "evaluationStatus": "evaluationCompleted", + "plus": true, + "strengthOfFunction": null, + "profileOid": null, + "profileUri": null, + "targetOid": null, + "targetUri": null + }, + "fipsLevel": { + "_type": "FIPSLevel", + "version": "140-2", + "level": "sllevel2", + "plus": false + }, + "iso9000Certified": false, + "iso9000Uri": null + } + ] + ``` + + A complete dump of such a certificate: + + ```bash + $ ./asn1_print ek.crt Certificate | jq . + ``` + + ```JSON + { + "_type": "Certificate", + "tbsCertificate": { + "_type": "TBSCertificate", + "_save": "30820376A00302010202146A0597BA71D7E6D3AC0EDC9EDC95A15B998DE40A300D06092A864886F70D01010B05003055310B3009060355040613024348311E301C060355040A131553544D6963726F656C656374726F6E696373204E56312630240603550403131D53544D2054504D20454B20496E7465726D656469617465204341203035301E170D3138313231343030303030305A170D3238313231343030303030305A300030820122300D06092A864886F70D01010105000382010F003082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5F0D559B10203010001A38201A9308201A5301F0603551D230418301680141ADB994AB58BE57A0CC9B900E7851E1A43C0866030420603551D20043B303930370604551D2000302F302D06082B060105050702011621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F30590603551D110101FF044F304DA44B304931163014060567810502010C0B69643A353335343444323031173015060567810502020C0C53543333485450484148433031163014060567810502030C0B69643A303034393030303830670603551D090460305E301706056781050210310E300C0C03322E300201000202008A304306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100300E0603551D0F0101FF040403020520300C0603551D130101FF0402300030100603551D250409300706056781050801304A06082B06010505070101043E303C303A06082B06010505073002862E687474703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274", + "version": "rfc3280_version_3", + "serialNumber": "6A0597BA71D7E6D3AC0EDC9EDC95A15B998DE40A", + "signature": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.11", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 11 + ], + "name": "id-pkcs1-sha256WithRSAEncryption" + }, + "parameters": "0500" + }, + "issuer": { + "_choice": "rdnSequence", + "value": [ + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.6", + "components": [ + 2, + 5, + 4, + 6 + ], + "name": "id-at-countryName" + }, + "value": { + "_choice": "printableString", + "value": "CH" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.10", + "components": [ + 2, + 5, + 4, + 10 + ], + "name": "id-at-organizationName" + }, + "value": { + "_choice": "printableString", + "value": "STMicroelectronics NV" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.4.3", + "components": [ + 2, + 5, + 4, + 3 + ], + "name": "id-at-commonName" + }, + "value": { + "_choice": "printableString", + "value": "STM TPM EK Intermediate CA 05" + } + } + ] + ] + }, + "validity": { + "_type": "Validity", + "notBefore": { + "_choice": "utcTime", + "value": "2018-12-14T00:00:00Z" + }, + "notAfter": { + "_choice": "utcTime", + "value": "2028-12-14T00:00:00Z" + } + }, + "subject": { + "_choice": "rdnSequence", + "value": [] + }, + "subjectPublicKeyInfo": { + "_type": "SubjectPublicKeyInfo", + "algorithm": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.1", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 1 + ], + "name": "id-pkcs1-rsaEncryption" + }, + "parameters": "0500" + }, + "subjectPublicKey": "2160:3082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5F0D559B10203010001" + }, + "issuerUniqueID": null, + "subjectUniqueID": null, + "extensions": [ + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.35", + "components": [ + 2, + 5, + 29, + 35 + ], + "name": "id-x509-ce-authorityKeyIdentifier" + }, + "critical": false, + "extnValue": "301680141ADB994AB58BE57A0CC9B900E7851E1A43C08660", + "_extnValue_choice": "ext-AuthorityKeyIdentifier", + "_extnValue": { + "_type": "AuthorityKeyIdentifier", + "keyIdentifier": "1ADB994AB58BE57A0CC9B900E7851E1A43C08660", + "authorityCertIssuer": null, + "authorityCertSerialNumber": null + } + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.32", + "components": [ + 2, + 5, + 29, + 32 + ], + "name": "id-x509-ce-certificatePolicies" + }, + "critical": false, + "extnValue": "303930370604551D2000302F302D06082B060105050702011621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F", + "_extnValue_choice": "ext-CertificatePolicies", + "_extnValue": [ + { + "_type": "PolicyInformation", + "policyIdentifier": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.32.0", + "components": [ + 2, + 5, + 29, + 32, + 0 + ], + "name": "id-x509-ce-certificatePolicies-anyPolicy" + }, + "policyQualifiers": [ + { + "_type": "PolicyQualifierInfo", + "policyQualifierId": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.3.6.1.5.5.7.2.1", + "components": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 2, + 1 + ], + "name": "id-pkix-qt-cps" + }, + "qualifier": "1621687474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F" + } + ] + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.17", + "components": [ + 2, + 5, + 29, + 17 + ], + "name": "id-x509-ce-subjectAltName" + }, + "critical": true, + "extnValue": "304DA44B304931163014060567810502010C0B69643A353335343444323031173015060567810502020C0C53543333485450484148433031163014060567810502030C0B69643A3030343930303038", + "_extnValue_choice": "ext-SubjectAltName", + "_extnValue": [ + { + "_choice": "directoryName", + "value": { + "_choice": "rdnSequence", + "value": [ + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.1", + "components": [ + 2, + 23, + 133, + 2, + 1 + ], + "name": "tcg-at-tpmManufacturer" + }, + "value": { + "_choice": "utf8String", + "value": "id:53544D20" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.2", + "components": [ + 2, + 23, + 133, + 2, + 2 + ], + "name": "tcg-at-tpmModel" + }, + "value": { + "_choice": "utf8String", + "value": "ST33HTPHAHC0" + } + } + ], + [ + { + "_type": "AttributeTypeAndValue", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.3", + "components": [ + 2, + 23, + 133, + 2, + 3 + ], + "name": "tcg-at-tpmVersion" + }, + "value": { + "_choice": "utf8String", + "value": "id:00490008" + } + } + ] + ] + } + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.9", + "components": [ + 2, + 5, + 29, + 9 + ], + "name": "id-x509-ce-subjectDirectoryAttributes" + }, + "critical": false, + "extnValue": "305E301706056781050210310E300C0C03322E300201000202008A304306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100", + "_extnValue_choice": "ext-SubjectDirectoryAttributes", + "_extnValue": [ + { + "_type": "AttributeSet", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.16", + "components": [ + 2, + 23, + 133, + 2, + 16 + ], + "name": "tcg-at-tpmSpecification" + }, + "values": [ + "300C0C03322E300201000202008A" + ], + "_values_choice": "at-TPMSpecification", + "_values": [ + { + "_type": "TPMSpecification", + "family": "2.0", + "level": 0, + "revision": 138 + } + ] + }, + { + "_type": "AttributeSet", + "type": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.2.18", + "components": [ + 2, + 23, + 133, + 2, + 18 + ], + "name": "tcg-at-tpmSecurityAssertions" + }, + "values": [ + "30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A0102010100" + ], + "_values_choice": "at-TPMSecurityAssertions", + "_values": [ + { + "_type": "TPMSecurityAssertions", + "version": 0, + "fieldUpgradable": true, + "ekGenerationType": "ekgt-injected", + "ekGenerationLocation": "tpmManufacturer", + "ekCertificateGenerationLocation": "tpmManufacturer", + "ccInfo": { + "_type": "CommonCriteriaMeasures", + "version": "3.1", + "assurancelevel": "ealevel4", + "evaluationStatus": "evaluationCompleted", + "plus": true, + "strengthOfFunction": null, + "profileOid": null, + "profileUri": null, + "targetOid": null, + "targetUri": null + }, + "fipsLevel": { + "_type": "FIPSLevel", + "version": "140-2", + "level": "sllevel2", + "plus": false + }, + "iso9000Certified": false, + "iso9000Uri": null + } + ] + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.15", + "components": [ + 2, + 5, + 29, + 15 + ], + "name": "id-x509-ce-keyUsage" + }, + "critical": true, + "extnValue": "03020520", + "_extnValue_choice": "ext-KeyUsage", + "_extnValue": [ + "keyEncipherment" + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.19", + "components": [ + 2, + 5, + 29, + 19 + ], + "name": "id-x509-ce-basicConstraints" + }, + "critical": true, + "extnValue": "3000", + "_extnValue_choice": "ext-BasicConstraints", + "_extnValue": { + "_type": "BasicConstraints", + "cA": false, + "pathLenConstraint": null + } + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "2.5.29.37", + "components": [ + 2, + 5, + 29, + 37 + ], + "name": "id-x509-ce-extKeyUsage" + }, + "critical": false, + "extnValue": "300706056781050801", + "_extnValue_choice": "ext-ExtKeyUsage", + "_extnValue": [ + { + "_type": "OBJECT IDENTIFIER", + "oid": "2.23.133.8.1", + "components": [ + 2, + 23, + 133, + 8, + 1 + ], + "name": "tcg-kp-EKCertificate" + } + ] + }, + { + "_type": "Extension", + "extnID": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.3.6.1.5.5.7.1.1", + "components": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 1, + 1 + ], + "name": "id-pkix-pe-authorityInfoAccess" + }, + "critical": false, + "extnValue": "303C303A06082B06010505073002862E687474703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274", + "_extnValue_choice": "ext-AuthorityInfoAccess", + "_extnValue": [ + { + "_type": "AccessDescription", + "accessMethod": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.3.6.1.5.5.7.48.2", + "components": [ + 1, + 3, + 6, + 1, + 5, + 5, + 7, + 48, + 2 + ], + "name": "id-pkix-ad-caIssuers" + }, + "accessLocation": { + "_choice": "uniformResourceIdentifier", + "value": "http://secure.globalsign.com/stmtpmekint05.crt" + } + } + ] + } + ] + }, + "signatureAlgorithm": { + "_type": "AlgorithmIdentifier", + "algorithm": { + "_type": "OBJECT IDENTIFIER", + "oid": "1.2.840.113549.1.1.11", + "components": [ + 1, + 2, + 840, + 113549, + 1, + 1, + 11 + ], + "name": "id-pkcs1-sha256WithRSAEncryption" + }, + "parameters": "0500" + }, + "signatureValue": "2048:3D4C381E5B4F1BCBE09C63D52F1F04570CAEA142FD9CD942043B11F8E3BDCF50007AE16CF8869013041E92CDD3280BA4B51FBBD40582ED750219E261A695095674855AACEB520ADAFF9E7E908480A39CDCF900462D9171960FFE55D3AC49E8C981341BBD2EFBCC252A4C18A4F3B7C84CCE42CE70A208C84D2630A7ABFBE72D6271E75B9FF1C971D20EB3DBD763F1E04D834EAA692D2E4001BBF4730A3E3FDA9711AE386524D91C63BE0E516D00D5C6141FCCF6C539F3518E180049865BE16B69CAE1F8CB7FDC474B38F7EE56CBE7D8A89D9BA99B65D5265AEF32AA62426B10E6D75BB8677EC44F755BBC2806FD2B4E04BDF5D44259DBEAA42B6F563DF7AA7506" + } + ``` + + (Notice that OID names look a bit weird. For reasons that may have been + lost to time and may no longer be relevant, these OIDs are defined with + slightly different names in the ASN.1 modules in Heimdal's source tree. + We'll fix this eventually.) + +... + +## Limitations + + - `libasn1`'s and, therefore, `asn1_print`'s JSON support is not X.697 (JER) + compatible. + + - Control over C types generated is very limited, mainly only for integer + types. + + - When using the template backend, `SET { .. }` types are currently not sorted + by tag as they should be, but if the module author sorts them by hand then + DER will be produced. + + - `REAL` is not supported. + + - `EmbeddedPDV` is not supported. + + - `BMPString` is not supported. + + - IA5String is not properly supported -- it's essentially treated as a + `UTF8String` with a different tag. This is true of all the string types. + + - Only types can be imported at this time. Without some rototilling we likely + will not be able to import anything other than types, values, and object + sets. + + - Only simple value syntax is supported. Constructed value syntax (i.e., + values of `SET`, `SEQUENCE`, `SET OF`, and `SEQUENCE OF`), is not supported. + Values of `CHOICE` types are also not supported. + + - There is no way to substitute object sets at run-time. This means that + automatic decoding through open types will spend more CPU cycles than the + application might want, by decoding more types than the application might + care about. The ability to substitute object sets at run-time would require + a change to the APIs generated. + + - ... + +## Compiler Usage + +The various options for the Heimdal ASN.1 compiler are described in its manual +page, which is included below. + +The `--option-file=FILE` option is particularly useful, as it allows additional +compiler options to be read from a file. + +The `--preserve-binary=TYPE-NAME` option is critical for signature validation +as it causes the decoder to save the encoding of the given type so that +signature validation code can easily find the original encoding and thus avoid +having to re-encode or resort to other hacks. E.g., we use this for preserving +the original encoding of the `tbsCertificate` field of `Certificate`. + +The `--sequence=TYPE-NAME` causes the compiler to generate additional utility +functions for adding or removing items from the named type when it is a +`SEQUENCE OF` or `SET OF` type. + +See the manual page `asn1_compile.1`: + +```text +ASN1_COMPILE(1) BSD General Commands Manual ASN1_COMPILE(1) + +NAME + asn1_compile — compile ASN.1 modules + +SYNOPSIS + asn1_compile [--template] [--prefix-enum] [--enum-prefix=PREFIX] + [--encode-rfc1510-bit-string] [--decode-dce-ber] + [--support-ber] [--preserve-binary=TYPE] [--sequence=TYPE] + [--decorate=DECORATION] [--one-code-file] [--gen-name=NAME] + [--option-file=FILE] [--original-order] [--no-parse-units] + [--type-file=C-HEADER-FILE] [--version] [--help] + [FILE.asn1 [NAME]] + +DESCRIPTION + asn1_compile compiles an ASN.1 module into C source code and header + files. + + A fairly large subset of ASN.1 as specified in X.680, and the ASN.1 In‐ + formation Object System as specified in X.681, X.682, and X.683 is sup‐ + ported, with support for the Distinguished Encoding Rules (DER), partial + Basic Encoding Rules (BER) support, and experimental JSON support (encod‐ + ing only at this time). + + See the compiler's README files for details about the C code and inter‐ + faces it generates. + + The Information Object System support includes automatic codec support + for encoding and decoding through “open types” which are also known as + “typed holes”. See RFC 5912 for examples of how to use the ASN.1 Infor‐ + mation Object System via X.681/X.682/X.683 annotations. See the com‐ + piler's README files for more information on ASN.1 Information Object + System support. + + Extensions specific to Heimdal are generally not syntactic in nature but + rather command-line options to this program. For example, one can use + command-line options to: + • enable decoding of BER-encoded values; + • enable RFC1510-style handling of ‘BIT STRING’ types; + • enable saving of as-received encodings of specific types + for the purpose of signature validation; + • generate add/remove utility functions for array types; + • decorate generated ‘struct’ types with fields that are nei‐ + ther encoded nor decoded; + etc. + + ASN.1 x.680 features supported: + • most primitive types (except BMPString and REAL); + • all constructed types, including SET and SET OF; + • explicit and implicit tagging. + + Size and range constraints on the ‘INTEGER’ type cause the compiler to + generate appropriate C types such as ‘int’, ‘unsigned int’, ‘int64_t’, + ‘uint64_t’. Unconstrained ‘INTEGER’ is treated as ‘heim_integer’, which + represents an integer of arbitrary size. + + Caveats and ASN.1 x.680 features not supported: + • JSON encoding support is not quite X.697 (JER) compatible. + Its JSON schema is subject to change without notice. + • Control over C types generated is very limited, mainly only + for integer types. + • When using the template backend, `SET { .. }` types are + currently not sorted by tag as they should be, but if the + module author sorts them by hand then correct DER will be + produced. + • ‘AUTOMATIC TAGS’ is not supported. + • The REAL type is not supported. + • The EmbeddedPDV type is not supported. + • The BMPString type is not supported. + • The IA5String is not properly supported, as it's essen‐ + tially treated as a UTF8String with a different tag. + • All supported non-octet strings are treated as like the + UTF8String type. + • Only types can be imported into ASN.1 modules at this time. + • Only simple value syntax is supported. Constructed value + syntax (i.e., values of SET, SEQUENCE, SET OF, and SEQUENCE + OF types), is not supported. Values of `CHOICE` types are + also not supported. + + Options supported: + + --template + Use the “template” backend instead of the “codegen” backend + (which is the default backend). + + The template backend generates “templates” which are akin to + bytecode, and which are interpreted at run-time. + + The codegen backend generates C code for all functions directly, + with no template interpretation. + + The template backend scales better than the codegen backend be‐ + cause as we add support for more encoding rules and more opera‐ + tions (we may add value comparators) the templates stay mostly + the same, thus scaling linearly with size of module. Whereas the + codegen backend scales linear with the product of module size and + number of encoding rules supported. + + --prefix-enum + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --enum-prefix=PREFIX + This option should be removed because ENUMERATED types should al‐ + ways have their labels prefixed. + + --encode-rfc1510-bit-string + Use RFC1510, non-standard handling of “BIT STRING” types. + + --decode-dce-ber + + --support-ber + + --preserve-binary=TYPE + Generate a field named ‘_save’ in the C struct generated for the + named TYPE. This field is used to preserve the original encoding + of the value of the TYPE. + + This is useful for cryptographic applications so that they can + check signatures of encoded values as-received without having to + re-encode those values. + + For example, the TBSCertificate type should have values preserved + so that Certificate validation can check the signatureValue over + the tbsCertificate's value as-received. + + The alternative of encoding a value to check a signature of it is + brittle. For types where non-canonical encodings (such as BER) + are allowed, this alternative is bound to fail. Thus the point + of this option. + + --sequence=TYPE + Generate add/remove functions for the named ASN.1 TYPE which must + be a ‘SET OF’ or ‘SEQUENCE OF’ type. + + --decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given ASN.1 type FIELD-ASN1-TYPE, but do not encode or decode + it. If the fname ends in a question mark, then treat the field + as OPTIONAL. + + This is useful for adding fields to existing types that can be + used for internal bookkeeping but which do not affect interoper‐ + ability because they are neither encoded nor decoded. For exam‐ + ple, one might decorate a request type with state needed during + processing of the request. + + --decorate=ASN1-TYPE:void*:fname + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + type ‘void *’ (but do not encode or decode it. + + The destructor and copy constructor functions generated by this + compiler for ASN1-TYPE will set this field to the ‘NULL’ pointer. + + --decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header + Add to the C struct generated for the given ASN.1 SET, SEQUENCE, + or CHOICE type named ASN1-TYPE a “hidden” field named fname of + the given external C type FIELD-C-TYPE, declared in the given + header but do not encode or decode this field. If the fname ends + in a question mark, then treat the field as OPTIONAL. + + The header must include double quotes or angle brackets. The + copyfn must be the name of a copy constructor function that takes + a pointer to a source value of the type, and a pointer to a des‐ + tination value of the type, in that order, and which returns zero + on success or else a system error code on failure. The freefn + must be the name of a destructor function that takes a pointer to + a value of the type and which releases resources referenced by + that value, but does not free the value itself (the run-time al‐ + locates this value as needed from the C heap). The freefn should + also reset the value to a pristine state (such as all zeros). + + If the copyfn and freefn are empty strings, then the decoration + field will neither be copied nor freed by the functions generated + for the TYPE. + + --one-code-file + Generate a single source code file. Otherwise a separate code + file will be generated for every type. + + --gen-name=NAME + Use NAME to form the names of the files generated. + + --option-file=FILE + Take additional command-line options from FILE. + + --original-order + Attempt to preserve the original order of type definition in the + ASN.1 module. By default the compiler generates types in a topo‐ + logical sort order. + + --no-parse-units + Do not generate to-int / from-int functions for enumeration + types. + + --type-file=C-HEADER-FILE + Generate an include of the named header file that might be needed + for common type defintions. + + --version + + --help + +NOTES + Currently only the template backend supports automatic encoding and de‐ + coding of open types via the ASN.1 Information Object System and + X.681/X.682/X.683 annotations. + +HEIMDAL February 22, 2021 HEIMDAL +``` + +## APIs Generated by the Compiler + +Every named type in an ASN.1 module gets a corresponding type in C. +Em-dashes in symbols become underscores. + +Every named type in an ASN.1 module also gets several functions generated +associated with it: + + - `int decode_TypeName(const unsigned char *, size_t, TypeName *, size_t *);` + + Decodes a value of `TypeName` in the given byte array of the given size, + into the given `TypeName` object, and outputs the number of bytes parsed. + + Returns 0 on success, or an error that can be formatted as a string using + the `com_err` library. + + - `int encode_TypeName(unsigned char *, size_t, const TypeName *, size_t *);` + + Encodes the given object of `TypeName` type into the given byte array of the + given size, outputting the number of bytes used. + + NOTE WELL: the `unsigned char *` pointer must point to the _last_ byte of + the buffer! + + Returns 0 on success, or an error that can be formatted as a string using + the `com_err` library, including system errors such as `ENOMEM`. + + - `int length_TypeName(const TypeName *);` + + Returns the number of bytes needed to encode the given object. + + - `void free_TypeName(TypeName *);` + + Releases the memory associated with the content of the given object, but + note that the object itself is _not_ released. + + - `int copy_TypeName(const TypeName *, TypeName *);` + + Copies the content of the given `const` object to the destination, + non-`const` object. + + Returns 0 on success, or an error that can be formatted as a string using + the `com_err` library, including system errors such as `ENOMEM`. + + - `char *print_TypeName(const TypeName *, int);` + + Returns a string (JSON) representation of the given object. The `int` + argument is a bitset of flags: + + - `ASN1_PRINT_INDENT` + + Indent the JSON. If not given the the JSON will have no interstitial + whitespace, including newlines. + +You will want to review the data structures generated. They look like: + +```C + typedef struct TBSCertificate TBSCertificate; + typedef struct AlgorithmIdentifier AlgorithmIdentifier; + typedef struct ... ...; + + /* + Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING { + }, + } + */ + + typedef struct Certificate { + TBSCertificate tbsCertificate; + AlgorithmIdentifier signatureAlgorithm; + heim_bit_string signatureValue; + } Certificate; + + /* + TBSCertificate ::= SEQUENCE { + version [0] Version OPTIONAL, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT BIT STRING { + } OPTIONAL, + subjectUniqueID [2] IMPLICIT BIT STRING { + } OPTIONAL, + extensions [3] Extensions OPTIONAL, + } + */ + + typedef struct TBSCertificate { + heim_octet_string _save; + Version *version; + CertificateSerialNumber serialNumber; + AlgorithmIdentifier signature; + Name issuer; + Validity validity; + Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + heim_bit_string *issuerUniqueID; + heim_bit_string *subjectUniqueID; + Extensions *extensions; + } TBSCertificate; +``` + +Note how trivial the mapping onto C is. + +`OPTIONAL` fields become pointer fields, with `NULL` indicating +absence and non-NULL indicating presence. + +And so on. + +## `asn1_print` Usage + +```text +ASN1_PRINT(1) BSD General Commands Manual ASN1_PRINT(1) + +NAME + asn1_print — dump ASN.1 DER encoded values + +SYNOPSIS + asn1_print [-i | --no-indent] [-I | --inner] [-l | --list-types] + [-A | --try-all-types] [-S | --raw-sequence] [-n | --no-print] + [-q | --quiet] [--test-encode] [--test-copy] + [-l -v | --version] [-l -h | --help] [FILE [TypeName...]] + +DESCRIPTION + asn1_print Dumps ASN.1 DER-encoded values. If one or more TypeName argu- + ments are given, then asn1_print will print the value in a JSON-like for- + mat using its knowledge of the ASN.1 modules defining those types, stop- + ping at the first type for which it can successfully decode the value. + If TypeNames are given, they must be the names of ASN.1 types exported by + an ASN.1 modules that are compiled into asn1_print. Use the + --try-all-types option to attempt decoding as all ASN.1 types known to + asn1_print. If neither any TypeName nor --try-all-types are given, then + the value will be parsed and displayed using just the self-describing + nature of DER. + + Options supported: + + -i, --no-indent + Do not indent dump. + + -I, --inner + Try to parse inner structures of OCTET STRING and constructed + values. + + -l, --list-types + List all types known to asn1_print. + + -A, --try-all-types + Attempt to decode the value as any of all types known to + asn1_print. + + -S, --raw-sequence + If a value parses as a given TypeName but any bytes are left + over, try to parse those separately as well until all bytes are + consumed or an error occurs. + + -n, --no-print + For the case where -A or --try-all-types or where a TypeName is + given, do not output a JSON representation of the value, just + attempt to decode it. This is useful for fuzzing. + + -q, --quiet + Similar to -n, --no-print but JSON output will be formatted, just + not output. As with -n, --no-print, this option requires -A -/ + --try-all-types or that a TypeName be given. This is useful for + fuzzing. + + --test-encode + Check that encoding produces the same value as decoding. Useful + for fuzzing. + + --test-copy + Test copy functions. Useful for fuzzing. + + -v, --version + + -h, --help + +HEIMDAL February 22, 2021 HEIMDAL +``` + +## Implementation + +See: + + - `lib/asn1/main.c` for the `main()` function of the compiler + - `lib/asn1/asn1parse.y` for the grammar and most of the parsing into an AST + - `lib/asn1/symbol.h` for the types making up the AST + - `lib/asn1/{hash,symbol}.c` for compiler AST supporting functionality + - `lib/asn1/gen.c` for the C header file generator + - `lib/asn1/gen_template.c` for the template generator + - `lib/asn1/gen_{decode,encode,length,copy,free}.c` for the C code generator + - `lib/asn1/gen_{glue,seq}.c` for misc code generator + - `lib/asn1/template.c` for the template interpreter + - `lib/asn1/der*.c` for primitive type primitives + - `lib/asn1/extra.c` for primitives related to `ANY` + +... + +## Futures + + - Add JER support so we can convert between JER and DER? + + - Add XDR support? There are no ASN.1 Encoding Rules based on XDR, but it is + trivial to construct such for at least that subset of ASN.1 for which the + XDR syntax has equivalent semantics. + + - Add OER support? + + - Add NDR support? There are no ASN.1 Encoding Rules based on NDR, but it is + trivial to construct such for at least that subset of ASN.1 for which the + IDL syntax has equivalent semantics. + + - Perhaps third parties will contribute more control over generated types? + This may require separate publication of the Heimdal ASN.1 compiler from the + rest of Heimdal. + +## Moving From C + + - Generate and output a JSON representation of the compiled ASN.1 module. + + - Code codegen/templategen backends in jq or Haskell or whatever. + + - Code template interpreters in some host language. + + - Eventually rewrite the compiler itself in Rust or whatever. diff --git a/third_party/heimdal/lib/asn1/asn1-common.h b/third_party/heimdal/lib/asn1/asn1-common.h new file mode 100644 index 0000000..7797eed --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1-common.h @@ -0,0 +1,90 @@ +/* $Id$ */ + +#include <stddef.h> +#include <time.h> +#include <krb5-types.h> + +#ifndef __asn1_common_definitions__ +#define __asn1_common_definitions__ + +#ifndef __HEIM_BASE_DATA__ +#define __HEIM_BASE_DATA__ 1 +struct heim_base_data { + size_t length; + void *data; +}; +#endif + +typedef struct heim_integer { + size_t length; + void *data; + int negative; +} heim_integer; + +typedef struct heim_base_data heim_octet_string; + +typedef char *heim_general_string; +typedef char *heim_utf8_string; +typedef struct heim_base_data heim_printable_string; +typedef struct heim_base_data heim_ia5_string; + +typedef struct heim_bmp_string { + size_t length; + uint16_t *data; +} heim_bmp_string; + +typedef struct heim_universal_string { + size_t length; + uint32_t *data; +} heim_universal_string; + +typedef char *heim_visible_string; + +typedef struct heim_oid { + size_t length; + unsigned *components; +} heim_oid; + +typedef struct heim_bit_string { + size_t length; + void *data; +} heim_bit_string; + +typedef struct heim_base_data heim_any; +typedef struct heim_base_data heim_any_set; +typedef struct heim_base_data HEIM_ANY; +typedef struct heim_base_data HEIM_ANY_SET; + +enum asn1_print_flags { + ASN1_PRINT_INDENT = 1, +}; + +#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \ + do { \ + (BL) = length_##T((S)); \ + (B) = malloc((BL)); \ + if((B) == NULL) { \ + (R) = ENOMEM; \ + } else { \ + (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \ + (S), (L)); \ + if((R) != 0) { \ + free((B)); \ + (B) = NULL; \ + } \ + } \ + } while (0) + +#ifdef _WIN32 +#ifndef ASN1_LIB +#define ASN1EXP __declspec(dllimport) +#else +#define ASN1EXP +#endif +#define ASN1CALL __stdcall +#else +#define ASN1EXP +#define ASN1CALL +#endif + +#endif diff --git a/third_party/heimdal/lib/asn1/asn1-template.h b/third_party/heimdal/lib/asn1/asn1-template.h new file mode 100644 index 0000000..07c4461 --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1-template.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* asn1 templates */ + +#ifndef __TEMPLATE_H__ +#define __TEMPLATE_H__ + +/* + * TBD: + * + * - For OER also encode number of optional/default/extension elements into + * header entry's ptr field, not just the number of entries that follow it. + * + * - For JER we'll need to encode encoding options (encode as array, encode as + * object, etc.) + * + * - For open types we'll need to be able to indicate what encoding rules the + * type uses. + * + * - We have too many bits for tags (20) and probably not enough for ops (4 + * bits, and we've used all but one). + */ + +/* header: + * HF flags if not a BIT STRING type + * HBF flags if a BIT STRING type + * + * ptr is count of elements + * offset is size of struct + */ + +/* tag: + * 0..20 tag + * 21 type + * 22..23 class + * 24..27 flags + * 28..31 op + * + * ptr points to template for tagged type + * offset is offset of struct field + */ + +/* parse: + * 0..11 type + * 12..23 unused + * 24..27 flags + * 28..31 op + * + * ptr is NULL + * offset is ... + */ + +/* defval: (next template entry is defaulted) + * + * DV flags (ptr is or points to defval) + * + * ptr is default value or pointer to default value + * offset is all ones + */ + +/* name: first one is the name of the SET/SEQUENCE/CHOICE type + * subsequent ones are the name of the nth field + * + * 0..23 unused + * 24..27 flags A1_NM_* + * 28..31 op + * + * ptr is const char * pointer to the name as C string + * offset is all zeros + */ + +/* objset: + * 0..9 open type ID entry index + * 10..19 open type entry index + * 20..23 unused + * 24..27 flags A1_OS_* + * 28..31 op + * + * ptr points to object set template + * offset is the offset of the choice struct + */ + +/* opentypeid: offset is zero + * ptr points to value if it is not an integer + * ptr is the value if it is an integer + * 0..23 unused + * 24..27 flags A1_OTI_* + * 28..31 op + */ + +/* opentype: offset is sizeof C type for this open type choice + * ptr points to template for type choice + * 0..23 unused + * 24..27 flags + * 28..31 op + */ + +#define A1_OP_MASK (0xf0000000) +#define A1_OP_TYPE (0x10000000) /* templated type */ +#define A1_OP_TYPE_EXTERN (0x20000000) /* templated type (imported) */ +#define A1_OP_TAG (0x30000000) /* a tag */ +#define A1_OP_PARSE (0x40000000) /* primitive type */ +#define A1_OP_SEQOF (0x50000000) /* sequence of */ +#define A1_OP_SETOF (0x60000000) /* set of */ +#define A1_OP_BMEMBER (0x70000000) /* BIT STRING member */ +#define A1_OP_CHOICE (0x80000000) /* CHOICE */ +#define A1_OP_DEFVAL (0x90000000) /* def. value */ +#define A1_OP_OPENTYPE_OBJSET (0xa0000000) /* object set for open type */ +#define A1_OP_OPENTYPE_ID (0xb0000000) /* open type id field */ +#define A1_OP_OPENTYPE (0xc0000000) /* open type field */ +#define A1_OP_NAME (0xd0000000) /* symbol */ +#define A1_OP_TYPE_DECORATE (0xe0000000) /* decoration w/ templated type */ +#define A1_OP_TYPE_DECORATE_EXTERN (0xf0000000) /* decoration w/ some C type */ + /* 0x00.. is still free */ + +#define A1_FLAG_MASK (0x0f000000) +#define A1_FLAG_OPTIONAL (0x01000000) +#define A1_FLAG_IMPLICIT (0x02000000) +#define A1_FLAG_DEFAULT (0x04000000) + +#define A1_TAG_T(CLASS,TYPE,TAG) ((A1_OP_TAG) | (((CLASS) << 22) | ((TYPE) << 21) | (TAG))) +#define A1_TAG_CLASS(x) (((x) >> 22) & 0x3) +#define A1_TAG_TYPE(x) (((x) >> 21) & 0x1) +#define A1_TAG_TAG(x) ((x) & 0x1fffff) + +#define A1_TAG_LEN(t) ((uintptr_t)(t)->ptr) +#define A1_HEADER_LEN(t) ((uintptr_t)(t)->ptr) + +#define A1_PARSE_T(type) ((A1_OP_PARSE) | (type)) +#define A1_PARSE_TYPE_MASK 0xfff +#define A1_PARSE_TYPE(x) (A1_PARSE_TYPE_MASK & (x)) + +#define A1_PF_INDEFINTE 0x1 +#define A1_PF_ALLOW_BER 0x2 + +#define A1_HF_PRESERVE 0x1 +#define A1_HF_ELLIPSIS 0x2 + +#define A1_HBF_RFC1510 0x1 + +#define A1_DV_BOOLEAN 0x01 +#define A1_DV_INTEGER 0x02 +#define A1_DV_INTEGER32 0x04 +#define A1_DV_INTEGER64 0x08 +#define A1_DV_UTF8STRING 0x10 + +#define A1_OS_IS_SORTED (0x01000000) +#define A1_OS_OT_IS_ARRAY (0x02000000) +#define A1_OTI_IS_INTEGER (0x04000000) + + +struct asn1_template { + uint32_t tt; + uint32_t offset; + const void *ptr; +}; + +typedef int (ASN1CALL *asn1_type_decode)(const unsigned char *, size_t, void *, size_t *); +typedef int (ASN1CALL *asn1_type_encode)(unsigned char *, size_t, const void *, size_t *); +typedef size_t (ASN1CALL *asn1_type_length)(const void *); +typedef void (ASN1CALL *asn1_type_release)(void *); +typedef int (ASN1CALL *asn1_type_copy)(const void *, void *); +typedef char * (ASN1CALL *asn1_type_print)(const void *, int); + +struct asn1_type_func { + asn1_type_encode encode; + asn1_type_decode decode; + asn1_type_length length; + asn1_type_copy copy; + asn1_type_release release; + asn1_type_print print; + size_t size; +}; + +struct template_of { + unsigned int len; + void *val; +}; + +enum template_types { + A1T_IMEMBER = 0, + A1T_HEIM_INTEGER, + A1T_INTEGER, + A1T_INTEGER64, + A1T_UNSIGNED, + A1T_UNSIGNED64, + A1T_GENERAL_STRING, + A1T_OCTET_STRING, + A1T_OCTET_STRING_BER, + A1T_IA5_STRING, + A1T_BMP_STRING, + A1T_UNIVERSAL_STRING, + A1T_PRINTABLE_STRING, + A1T_VISIBLE_STRING, + A1T_UTF8_STRING, + A1T_GENERALIZED_TIME, + A1T_UTC_TIME, + A1T_HEIM_BIT_STRING, + A1T_BOOLEAN, + A1T_OID, + A1T_TELETEX_STRING, + A1T_NUM_ENTRY +}; + +extern struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY]; + +#define ABORT_ON_ERROR() abort() + +#define DPOC(data,offset) ((const void *)(((const unsigned char *)data) + offset)) +#define DPO(data,offset) ((void *)(((unsigned char *)data) + offset)) + +/* + * These functions are needed by the generated template stubs and are + * really internal functions. Since they are part of der-private.h + * that contains extra prototypes that really a private we included a + * copy here. + */ + +int +_asn1_copy_top ( + const struct asn1_template * /*t*/, + const void * /*from*/, + void * /*to*/); + +void +_asn1_free_top(const struct asn1_template *, void *); + +char * +_asn1_print_top(const struct asn1_template *, int, const void *); + +int +_asn1_decode_top ( + const struct asn1_template * /*t*/, + unsigned /*flags*/, + const unsigned char * /*p*/, + size_t /*len*/, + void * /*data*/, + size_t * /*size*/); + +int +_asn1_encode ( + const struct asn1_template * /*t*/, + unsigned char * /*p*/, + size_t /*len*/, + const void * /*data*/, + size_t * /*size*/); + +int +_asn1_encode_fuzzer ( + const struct asn1_template * /*t*/, + unsigned char * /*p*/, + size_t /*len*/, + const void * /*data*/, + size_t * /*size*/); + +void +_asn1_free ( + const struct asn1_template * /*t*/, + void * /*data*/); + +size_t +_asn1_length ( + const struct asn1_template * /*t*/, + const void * /*data*/); + +size_t +_asn1_length_fuzzer ( + const struct asn1_template * /*t*/, + const void * /*data*/); + + +#endif diff --git a/third_party/heimdal/lib/asn1/asn1_compile-version.rc b/third_party/heimdal/lib/asn1/asn1_compile-version.rc new file mode 100644 index 0000000..120fb85 --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_compile-version.rc @@ -0,0 +1,36 @@ +/*********************************************************************** + * Copyright (c) 2010, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + **********************************************************************/ + +#define RC_FILE_TYPE VFT_APP +#define RC_FILE_DESC_0409 "ASN.1 Compiler" +#define RC_FILE_ORIG_0409 "asn1_compile.exe" + +#include "../../windows/version.rc" diff --git a/third_party/heimdal/lib/asn1/asn1_compile.1 b/third_party/heimdal/lib/asn1/asn1_compile.1 new file mode 100644 index 0000000..9af2767 --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_compile.1 @@ -0,0 +1,355 @@ +.\" Copyright (c) 2019 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 22, 2021 +.Dt ASN1_COMPILE 1 +.Os HEIMDAL +.Sh NAME +.Nm asn1_compile +.Nd compile ASN.1 modules +.Sh SYNOPSIS +.Nm +.Bk -words +.Op Fl Fl template +.Op Fl Fl prefix-enum +.Op Fl Fl enum-prefix=PREFIX +.Op Fl Fl encode-rfc1510-bit-string +.Op Fl Fl decode-dce-ber +.Op Fl Fl support-ber +.Op Fl Fl preserve-binary=TYPE +.Op Fl Fl sequence=TYPE +.Op Fl Fl decorate=DECORATION +.Op Fl Fl one-code-file +.Op Fl Fl gen-name=NAME +.Op Fl Fl option-file=FILE +.Op Fl Fl original-order +.Op Fl Fl no-parse-units +.Op Fl Fl type-file=C-HEADER-FILE +.Op Fl Fl version +.Op Fl Fl help +.Op Ar FILE.asn1 Op Ar NAME +.Ek +.Sh DESCRIPTION +.Nm +compiles an ASN.1 module into C source code and header files. +.Pp +A fairly large subset of ASN.1 as specified in X.680, and the +ASN.1 Information Object System as specified in X.681, X.682, and +X.683 is supported, with support for the Distinguished Encoding +Rules (DER), partial Basic Encoding Rules (BER) support, and +experimental JSON support (encoding only at this time). +.Pp +See the compiler's README files for details about the C code and +interfaces it generates. +.Pp +The Information Object System support includes automatic codec +support for encoding and decoding through +.Dq open types +which are also known as +.Dq typed holes . +See RFC 5912 for examples of how to use the ASN.1 +Information Object System via X.681/X.682/X.683 annotations. See +the compiler's README files for more information on ASN.1 +Information Object System support. +.Pp +Extensions specific to Heimdal are generally not syntactic in +nature but rather command-line options to this program. +For example, one can use command-line options to: +.Bl -bullet -compact -width Ds -offset indent +.It +enable decoding of BER-encoded values; +.It +enable RFC1510-style handling of +.Sq BIT STRING +types; +.It +enable saving of as-received encodings of specific types for the +purpose of signature validation; +.It +generate add/remove utility functions for array types; +.It +decorate generated +.Sq struct +types with fields that are neither encoded nor decoded; +.El +etc. +.Pp +ASN.1 x.680 features supported: +.Bl -bullet -compact -width Ds -offset indent +.It +most primitive types (except BMPString and REAL); +.It +all constructed types, including SET and SET OF; +.It +explicit and implicit tagging. +.El +.Pp +Size and range constraints on the +.Sq INTEGER +type cause the compiler to generate appropriate C types such as +.Sq int , +.Sq unsigned int , +.Sq int64_t , +.Sq uint64_t . +Unconstrained +.Sq INTEGER +is treated as +.Sq heim_integer , +which represents an integer of arbitrary size. +.Pp +Caveats and ASN.1 x.680 features not supported: +.Bl -bullet -compact -width Ds -offset indent +.It +JSON encoding support is not quite X.697 (JER) compatible. +Its JSON schema is subject to change without notice. +.It +Control over C types generated is very limited, mainly only for +integer types. +.It +When using the template backend, `SET { .. }` types are currently +not sorted by tag as they should be, but if the module author +sorts them by hand then correct DER will be produced. +.It +.Sq AUTOMATIC TAGS +is not supported. +.It +The +.Va REAL +type is not supported. +.It +The +.Va EmbeddedPDV +type is not supported. +.It +The +.Va BMPString +type is not supported. +.It +The +.Va IA5String +is not properly supported, as it's essentially treated as a +.Va UTF8String +with a different tag. +.It +All supported non-octet strings are treated as like the +.Va UTF8String +type. +.It +Only types can be imported into ASN.1 modules at this time. +.It +Only simple value syntax is supported. +Constructed value syntax (i.e., values of SET, SEQUENCE, SET OF, +and SEQUENCE OF types), is not supported. +Values of `CHOICE` types are also not supported. +.El +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl Fl template +Use the +.Dq template +backend instead of the +.Dq codegen +backend (which is the default backend). +.Pp +The template backend generates +.Dq templates +which are akin to bytecode, and which are interpreted at +run-time. +.Pp +The codegen backend generates C code for all functions directly, +with no template interpretation. +.Pp +The template backend scales better than the codegen backend +because as we add support for more encoding rules and more +operations (we may add value comparators) the templates stay +mostly the same, thus scaling linearly with size of module. +Whereas the codegen backend scales linear with the product of +module size and number of encoding rules supported. +.It Fl Fl prefix-enum +This option should be removed because ENUMERATED types should +always have their labels prefixed. +.It Fl Fl enum-prefix=PREFIX +This option should be removed because ENUMERATED types should +always have their labels prefixed. +.It Fl Fl encode-rfc1510-bit-string +Use RFC1510, non-standard handling of +.Dq BIT STRING +types. +.It Fl Fl decode-dce-ber +.It Fl Fl support-ber +.It Fl Fl preserve-binary=TYPE +Generate a field named +.Sq _save +in the C struct generated for the named +.Ar TYPE . +This field is used to preserve the original encoding of the value +of the +.Ar TYPE . +.Pp +This is useful for cryptographic applications so that they can +check signatures of encoded values as-received without having to +re-encode those values. +.Pp +For example, the TBSCertificate type should have values preserved +so that Certificate validation can check the signatureValue over +the tbsCertificate's value as-received. +.Pp +The alternative of encoding a value to check a signature of it is +brittle. +For types where non-canonical encodings (such as BER) are +allowed, this alternative is bound to fail. +Thus the point of this option. +.It Fl Fl sequence=TYPE +Generate add/remove functions for the named ASN.1 +.Ar TYPE +which must be a +.Sq SET OF +or +.Sq SEQUENCE OF +type. +.It Fl Fl decorate=ASN1-TYPE:FIELD-ASN1-TYPE:fname[?] +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of the given ASN.1 type +.Ar FIELD-ASN1-TYPE , +but do not encode or decode it. +If the +.Ar fname +ends in a question mark, then treat the field as OPTIONAL. +.Pp +This is useful for adding fields to existing types that can be +used for internal bookkeeping but which do not affect +interoperability because they are neither encoded nor decoded. +For example, one might decorate a request type with state needed +during processing of the request. +.It Fl Fl decorate=ASN1-TYPE:void*:fname +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of type +.Sq void * +(but do not encode or decode it. +.Pp +The destructor and copy constructor functions generated by this +compiler for +.Ar ASN1-TYPE +will set this field to the +.Sq NULL +pointer. +.It Fl Fl decorate=ASN1-TYPE:FIELD-C-TYPE:fname[?]:[copyfn]:[freefn]:header +Add to the C struct generated for the given ASN.1 SET, SEQUENCE, or +CHOICE type named +.Ar ASN1-TYPE +a +.Dq hidden +field named +.Ar fname +of the given external C type +.Ar FIELD-C-TYPE , +declared in the given +.Ar header +but do not encode or decode this field. +If the +.Ar fname +ends in a question mark, then treat the field as OPTIONAL. +.Pp +The +.Ar header +must include double quotes or angle brackets. +The +.Ar copyfn +must be the name of a copy constructor function that takes a +pointer to a source value of the type, and a pointer to a +destination value of the type, in that order, and which returns +zero on success or else a system error code on failure. +The +.Ar freefn +must be the name of a destructor function that takes a pointer to +a value of the type and which releases resources referenced by +that value, but does not free the value itself (the run-time +allocates this value as needed from the C heap). +The +.Ar freefn +should also reset the value to a pristine state (such as all +zeros). +.Pp +If the +.Ar copyfn +and +.Ar freefn +are empty strings, then the decoration field will neither be +copied nor freed by the functions generated for the +.Ar TYPE . +.It Fl Fl one-code-file +Generate a single source code file. +Otherwise a separate code file will be generated for every type. +.It Fl Fl gen-name=NAME +Use +.Ar NAME +to form the names of the files generated. +.It Fl Fl option-file=FILE +Take additional command-line options from +.Ar FILE . +The options file must have one command-line option per-line, but +leading whitespace is ignored, and lines that start with a hash +symbol +.Sq ( # ) +are comments and are ignored. +.It Fl Fl original-order +Attempt to preserve the original order of type definition in the +ASN.1 module. +By default the compiler generates types in a topological sort +order. +.It Fl Fl no-parse-units +Do not generate to-int / from-int functions for enumeration +types. +.It Fl Fl type-file=C-HEADER-FILE +Generate an include of the named header file that might be needed +for common type defintions. +.It Fl Fl version +.It Fl Fl help +.El +.Sh NOTES +Currently only the template backend supports automatic encoding +and decoding of open types via the ASN.1 Information Object +System and X.681/X.682/X.683 annotations. diff --git a/third_party/heimdal/lib/asn1/asn1_err.et b/third_party/heimdal/lib/asn1/asn1_err.et new file mode 100644 index 0000000..ac7a9eb --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_err.et @@ -0,0 +1,29 @@ +# +# Error messages for the asn.1 library +# +# This might look like a com_err file, but is not +# +id "$Id$" + +error_table asn1 +prefix ASN1 +error_code BAD_TIMEFORMAT, "ASN.1 failed call to system time library" +error_code MISSING_FIELD, "ASN.1 structure is missing a required field" +error_code MISPLACED_FIELD, "ASN.1 unexpected field number" +error_code TYPE_MISMATCH, "ASN.1 type numbers are inconsistent" +error_code OVERFLOW, "ASN.1 value too large" +error_code OVERRUN, "ASN.1 encoding ended unexpectedly" +error_code BAD_ID, "ASN.1 identifier doesn't match expected value" +error_code BAD_LENGTH, "ASN.1 length doesn't match expected value" +error_code BAD_FORMAT, "ASN.1 badly-formatted encoding" +error_code PARSE_ERROR, "ASN.1 parse error" +error_code EXTRA_DATA, "ASN.1 extra data past end of end structure" +error_code BAD_CHARACTER, "ASN.1 invalid character in string" +error_code MIN_CONSTRAINT, "ASN.1 too few elements" +error_code MAX_CONSTRAINT, "ASN.1 too many elements" +error_code EXACT_CONSTRAINT, "ASN.1 wrong number of elements" +error_code INDEF_OVERRUN, "ASN.1 BER indefinte encoding overrun" +error_code INDEF_UNDERRUN, "ASN.1 BER indefinte encoding underun" +error_code GOT_BER, "ASN.1 got BER encoded when expected DER" +error_code INDEF_EXTRA_DATA, "ASN.1 EoC tag contained data" +end diff --git a/third_party/heimdal/lib/asn1/asn1_gen.c b/third_party/heimdal/lib/asn1/asn1_gen.c new file mode 100644 index 0000000..6a0244f --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_gen.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <com_err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <getarg.h> +#include <hex.h> +#include <err.h> + +RCSID("$Id$"); + +static int +doit(const char *fn) +{ + char buf[2048]; + char *fnout = NULL; + const char *bname; + unsigned long line = 0; + FILE *f, *fout; + size_t offset = 0; + + f = fopen(fn, "r"); + if (f == NULL) + err(1, "fopen"); + + bname = strrchr(fn, '/'); + if (bname) + bname++; + else + bname = fn; + + if (asprintf(&fnout, "%s.out", bname) < 0 || fnout == NULL) + errx(1, "malloc"); + + fout = fopen(fnout, "w"); + if (fout == NULL) + err(1, "fopen: output file"); + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *ptr, *class, *type, *tag, *length, *data, *foo; + int ret, l, c, ty, ta; + unsigned char p[6], *pdata; + size_t sz; + + line++; + + buf[strcspn(buf, "\r\n")] = '\0'; + if (buf[0] == '#' || buf[0] == '\0') + continue; + + ptr = buf; + while (isspace((unsigned char)*ptr)) + ptr++; + + class = strtok_r(ptr, " \t\n", &foo); + if (class == NULL) errx(1, "class missing on line %lu", line); + type = strtok_r(NULL, " \t\n", &foo); + if (type == NULL) errx(1, "type missing on line %lu", line); + tag = strtok_r(NULL, " \t\n", &foo); + if (tag == NULL) errx(1, "tag missing on line %lu", line); + length = strtok_r(NULL, " \t\n", &foo); + if (length == NULL) errx(1, "length missing on line %lu", line); + data = strtok_r(NULL, " \t\n", &foo); + + c = der_get_class_num(class); + if (c == -1) errx(1, "no valid class on line %lu", line); + ty = der_get_type_num(type); + if (ty == -1) errx(1, "no valid type on line %lu", line); + ta = der_get_tag_num(tag); + if (ta == -1) + ta = atoi(tag); + + l = atoi(length); + + printf("line: %3lu offset: %3lu class: %d type: %d " + "tag: %3d length: %3d %s\n", + line, (unsigned long)offset, c, ty, ta, l, + data ? "<have data>" : "<no data>"); + + ret = der_put_length_and_tag(p + sizeof(p) - 1, sizeof(p), + l, + c, + ty, + ta, + &sz); + if (ret) + errx(1, "der_put_length_and_tag: %d", ret); + + if (fwrite(p + sizeof(p) - sz , sz, 1, fout) != 1) + err(1, "fwrite length/tag failed"); + offset += sz; + + if (data) { + size_t datalen; + + datalen = strlen(data) / 2; + pdata = emalloc(sz); + + if (hex_decode(data, pdata, datalen) != datalen) + errx(1, "failed to decode data"); + + if (fwrite(pdata, datalen, 1, fout) != 1) + err(1, "fwrite data failed"); + offset += datalen; + + free(pdata); + } + } + printf("line: eof offset: %lu\n", (unsigned long)offset); + + if (fclose(fout) == EOF) + err(1, "writes to file %s failed", fnout); + fclose(f); + return 0; +} + + +static int version_flag; +static int help_flag; +struct getargs args[] = { + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + arg_printusage(args, num_args, NULL, "parse-file"); + exit(code); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname (argv[0]); + + if(getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if(help_flag) + usage(0); + if(version_flag) { + print_version(NULL); + exit(0); + } + argv += optidx; + argc -= optidx; + if (argc != 1) + usage (1); + + return doit (argv[0]); +} diff --git a/third_party/heimdal/lib/asn1/asn1_print.1 b/third_party/heimdal/lib/asn1/asn1_print.1 new file mode 100644 index 0000000..8066b0b --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_print.1 @@ -0,0 +1,135 @@ +.\" Copyright (c) 2021 Kungliga Tekniska Högskolan +.\" (Royal Institute of Technology, Stockholm, Sweden). +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id$ +.\" +.Dd February 22, 2021 +.Dt ASN1_PRINT 1 +.Os HEIMDAL +.Sh NAME +.Nm asn1_print +.Nd dump ASN.1 DER encoded values +.Sh SYNOPSIS +.Nm +.Bk -words +.Oo Fl i \*(Ba Xo Fl Fl no-indent Xc Oc +.Oo Fl I \*(Ba Xo Fl Fl inner Xc Oc +.Oo Fl l \*(Ba Xo Fl Fl list-types Xc Oc +.Oo Fl A \*(Ba Xo Fl Fl try-all-types Xc Oc +.Oo Fl S \*(Ba Xo Fl Fl raw-sequence Xc Oc +.Oo Fl n \*(Ba Xo Fl Fl no-print Xc Oc +.Oo Fl q \*(Ba Xo Fl Fl quiet Xc Oc +.Oo Xo Fl Fl test-encode Xc Oc +.Oo Xo Fl Fl test-copy Xc Oc +.Oo Fl l v \*(Ba Xo +.Fl Fl version +.Xc +.Oc +.Oo Fl l h \*(Ba Xo +.Fl Fl help +.Xc +.Oc +.Op Ar FILE Op Ar TypeName... +.Ek +.Sh DESCRIPTION +.Nm +Dumps ASN.1 DER-encoded values. +If one or more +.Ar TypeName +arguments are given, then +.Nm +will print the value in a JSON-like format using its knowledge of +the ASN.1 modules defining those types, stopping at the first type +for which it can successfully decode the value. +If +.Ar TypeNames +are given, they must be the names of ASN.1 types exported by an +ASN.1 modules that are compiled into +.Nm . +Use the +.Fl Fl try-all-types +option to attempt decoding as all ASN.1 types known to +.Nm . +If neither any +.Ar TypeName +nor +.Fl Fl try-all-types +are given, then the value will be parsed and displayed using just +the self-describing nature of DER. +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl i, Fl Fl no-indent +Do not indent dump. +.It Fl I, Fl Fl inner +Try to parse inner structures of OCTET STRING and constructed values. +.It Fl l, Fl Fl list-types +List all types known to +.Nm . +.It Fl A, Fl Fl try-all-types +Attempt to decode the value as any of all types known to +.Nm . +.It Fl S, Fl Fl raw-sequence +If a value parses as a given +.Ar TypeName +but any bytes are left over, try to parse those separately as +well until all bytes are consumed or an error occurs. +.It Fl n, Fl Fl no-print +For the case where +.Fl A +or +.Fl Fl try-all-types +or where a +.Ar TypeName +is given, do not output a JSON representation of the value, just +attempt to decode it. +This is useful for fuzzing. +.It Fl q, Fl Fl quiet +Similar to +.Fl n, Fl Fl no-print +but JSON output will be formatted, just not output. +As with +.Fl n, Fl Fl no-print, +this option requires +.Fl A / Fl Fl try-all-types +or that a +.Ar TypeName +be given. +This is useful for fuzzing. +.It Fl Fl test-encode +Check that encoding produces the same value as decoding. +Useful for fuzzing. +.It Fl Fl test-copy +Test copy functions. +Useful for fuzzing. +.It Fl v, Fl Fl version +.It Fl h, Fl Fl help +.El diff --git a/third_party/heimdal/lib/asn1/asn1_print.c b/third_party/heimdal/lib/asn1/asn1_print.c new file mode 100644 index 0000000..9ef6ffd --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1_print.c @@ -0,0 +1,692 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <com_err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dlfcn.h> +#include <getarg.h> +#include <err.h> +#include <der.h> +#include "cms_asn1.h" +#include "digest_asn1.h" +#include "krb5_asn1.h" +#include "kx509_asn1.h" +#include "ocsp_asn1.h" +#include "pkcs10_asn1.h" +#include "pkcs12_asn1.h" +#include "pkcs8_asn1.h" +#include "pkcs9_asn1.h" +#include "pkinit_asn1.h" +#include "rfc2459_asn1.h" +#include "rfc4108_asn1.h" +#ifdef ASN1_PRINT_SUPPORTED +#include "x690sample_template_asn1.h" +#else +#include "x690sample_asn1.h" +#endif + +static int quiet_flag = 0; +static int print_flag = 1; +static int test_copy_flag; +static int test_encode_flag; +static int sequence_flag; +static int try_all_flag; +static int indent_flag = 1; +static int inner_flag; + +static unsigned long indefinite_form_loop; +static unsigned long indefinite_form_loop_max = 10000; + +typedef size_t (*lengther)(void *); +typedef int (*copyer)(const void *, void *); +typedef int (*encoder)(unsigned char *, size_t, void *, size_t *); +typedef int (*decoder)(const unsigned char *, size_t, void *, size_t *); +typedef char *(*printer)(const void *, int); +typedef void (*releaser)(void *); +const struct types { + const char *name; + size_t sz; + copyer cpy; + lengther len; + decoder decode; + encoder encode; + printer print; + releaser release; +} types[] = { +#define ASN1_SYM_INTVAL(n, gn, gns, i) +#define ASN1_SYM_OID(n, gn, gns) +#ifdef ASN1_PRINT_SUPPORTED +#define ASN1_SYM_TYPE(n, gn, gns) \ + { \ + n, \ + sizeof(gns), \ + (copyer)copy_ ## gns, \ + (lengther)length_ ## gns, \ + (decoder)decode_ ## gns, \ + (encoder)encode_ ## gns, \ + (printer)print_ ## gns, \ + (releaser)free_ ## gns, \ + }, +#else +#define ASN1_SYM_TYPE(n, gn, gns) \ + { \ + n, \ + sizeof(gns), \ + (copyer)copy_ ## gns, \ + (lengther)length_ ## gns, \ + (decoder)decode_ ## gns, \ + (encoder)encode_ ## gns, \ + 0, \ + (releaser)free_ ## gns, \ + }, +#endif +#include "cms_asn1_syms.c" +#include "digest_asn1_syms.c" +#include "krb5_asn1_syms.c" +#include "kx509_asn1_syms.c" +#include "ocsp_asn1_syms.c" +#include "pkcs10_asn1_syms.c" +#include "pkcs12_asn1_syms.c" +#include "pkcs8_asn1_syms.c" +#include "pkcs9_asn1_syms.c" +#include "pkinit_asn1_syms.c" +#include "rfc2459_asn1_syms.c" +#include "rfc4108_asn1_syms.c" +#ifdef ASN1_PRINT_SUPPORTED +#include "x690sample_template_asn1_syms.c" +#else +#include "x690sample_asn1_syms.c" +#endif +}; + +struct types sorted_types[sizeof(types)/sizeof(types[0])]; + +static size_t +loop (unsigned char *buf, size_t len, int indent) +{ + unsigned char *start_buf = buf; + + while (len > 0) { + int ret; + Der_class class; + Der_type type; + unsigned int tag; + size_t sz; + size_t length; + size_t loop_length = 0; + int end_tag = 0; + const char *tagname; + + ret = der_get_tag (buf, len, &class, &type, &tag, &sz); + if (ret) + errx (1, "der_get_tag: %s", error_message (ret)); + if (sz > len) + errx (1, "unreasonable length (%u) > %u", + (unsigned)sz, (unsigned)len); + buf += sz; + len -= sz; + if (indent_flag) { + int i; + for (i = 0; i < indent; ++i) + printf (" "); + } + printf ("%s %s ", der_get_class_name(class), der_get_type_name(type)); + tagname = der_get_tag_name(tag); + if (class == ASN1_C_UNIV && tagname != NULL) + printf ("%s = ", tagname); + else + printf ("tag %d = ", tag); + ret = der_get_length (buf, len, &length, &sz); + if (ret) + errx (1, "der_get_tag: %s", error_message (ret)); + if (sz > len) + errx (1, "unreasonable tag length (%u) > %u", + (unsigned)sz, (unsigned)len); + buf += sz; + len -= sz; + if (length == ASN1_INDEFINITE) { + if ((class == ASN1_C_UNIV && type == PRIM && tag == UT_OctetString) || + (class == ASN1_C_CONTEXT && type == CONS) || + (class == ASN1_C_UNIV && type == CONS && tag == UT_Sequence) || + (class == ASN1_C_UNIV && type == CONS && tag == UT_Set)) { + printf("*INDEFINITE FORM*"); + } else { + fflush(stdout); + errx(1, "indef form used on unsupported object"); + } + end_tag = 1; + if (indefinite_form_loop > indefinite_form_loop_max) + errx(1, "indefinite form used recursively more then %lu " + "times, aborting", indefinite_form_loop_max); + indefinite_form_loop++; + length = len; + } else if (length > len) { + printf("\n"); + fflush(stdout); + errx (1, "unreasonable inner length (%u) > %u", + (unsigned)length, (unsigned)len); + } + if (class == ASN1_C_CONTEXT || class == ASN1_C_APPL) { + printf ("%lu bytes [%u]", (unsigned long)length, tag); + if (type == CONS) { + printf("\n"); + loop_length = loop (buf, length, indent + 2); + } else { + printf(" IMPLICIT content\n"); + } + } else if (class == ASN1_C_UNIV) { + switch (tag) { + case UT_EndOfContent: + printf (" INDEFINITE length was %lu\n", + (unsigned long)(buf - start_buf)); + break; + case UT_Set : + case UT_Sequence : + printf ("%lu bytes {\n", (unsigned long)length); + loop_length = loop (buf, length, indent + 2); + if (indent_flag) { + int i; + for (i = 0; i < indent; ++i) + printf (" "); + printf ("}\n"); + } else + printf ("} indent = %d\n", indent / 2); + break; + case UT_Integer : { + int val; + + if (length <= sizeof(val)) { + ret = der_get_integer (buf, length, &val, NULL); + if (ret) + errx (1, "der_get_integer: %s", error_message (ret)); + printf ("integer %d\n", val); + } else { + heim_integer vali; + char *p; + + ret = der_get_heim_integer(buf, length, &vali, NULL); + if (ret) + errx (1, "der_get_heim_integer: %s", + error_message (ret)); + ret = der_print_hex_heim_integer(&vali, &p); + if (ret) + errx (1, "der_print_hex_heim_integer: %s", + error_message (ret)); + printf ("BIG NUM integer: length %lu %s\n", + (unsigned long)length, p); + free(p); + } + break; + } + case UT_OctetString : { + heim_octet_string str; + size_t i; + + ret = der_get_octet_string (buf, length, &str, NULL); + if (ret) + errx (1, "der_get_octet_string: %s", error_message (ret)); + printf ("(length %lu), ", (unsigned long)length); + + if (inner_flag) { + Der_class class2; + Der_type type2; + unsigned int tag2; + + ret = der_get_tag(str.data, str.length, + &class2, &type2, &tag2, &sz); + if (ret || sz > str.length || + type2 != CONS || tag2 != UT_Sequence) + goto just_an_octet_string; + + printf("{\n"); + loop (str.data, str.length, indent + 2); + for (i = 0; i < indent; ++i) + printf (" "); + printf ("}\n"); + + } else { + unsigned char *uc; + + just_an_octet_string: + uc = (unsigned char *)str.data; + for (i = 0; i < min(16,length); ++i) + printf ("%02x", uc[i]); + printf ("\n"); + } + free (str.data); + break; + } + case UT_IA5String : + case UT_PrintableString : { + heim_printable_string str; + unsigned char *s; + size_t n; + + memset(&str, 0, sizeof(str)); + + ret = der_get_printable_string (buf, length, &str, NULL); + if (ret) + errx (1, "der_get_general_string: %s", + error_message (ret)); + s = str.data; + printf("\""); + for (n = 0; n < str.length; n++) { + if (isprint(s[n])) + printf ("%c", s[n]); + else + printf ("#%02x", s[n]); + } + printf("\"\n"); + der_free_printable_string(&str); + break; + } + case UT_GeneralizedTime : + case UT_GeneralString : + case UT_VisibleString : + case UT_UTF8String : { + heim_general_string str; + + ret = der_get_general_string (buf, length, &str, NULL); + if (ret) + errx (1, "der_get_general_string: %s", + error_message (ret)); + printf ("\"%s\"\n", str); + free (str); + break; + } + case UT_OID: { + heim_oid o; + char *p; + + ret = der_get_oid(buf, length, &o, NULL); + if (ret) + errx (1, "der_get_oid: %s", error_message (ret)); + ret = der_print_heim_oid_sym(&o, '.', &p); + der_free_oid(&o); + if (ret) + errx (1, "der_print_heim_oid_sym: %s", error_message (ret)); + printf("%s\n", p); + free(p); + + break; + } + case UT_Enumerated: { + int num; + + ret = der_get_integer (buf, length, &num, NULL); + if (ret) + errx (1, "der_get_enum: %s", error_message (ret)); + + printf("%u\n", num); + break; + } + default : + printf ("%lu bytes\n", (unsigned long)length); + break; + } + } + if (end_tag) { + if (loop_length == 0) + errx(1, "zero length INDEFINITE data ? indent = %d\n", + indent / 2); + if (loop_length < length) + length = loop_length; + if (indefinite_form_loop == 0) + errx(1, "internal error in indefinite form loop detection"); + indefinite_form_loop--; + } else if (loop_length) + errx(1, "internal error for INDEFINITE form"); + buf += length; + len -= length; + } + return 0; +} + +static int +type_cmp(const void *va, const void *vb) +{ + const struct types *ta = (const struct types *)va; + const struct types *tb = (const struct types *)vb; + + return strcmp(ta->name, tb->name); +} + +static int +dotype(unsigned char *buf, size_t len, char **argv, size_t *size) +{ + const char *typename = ""; + size_t matches = 0; + size_t sz; + size_t tried = 0; + size_t i = 0; + void *v; + int ret = 0; + + *size = len; + + memcpy(sorted_types, types, sizeof(types)); + qsort(sorted_types, + sizeof(types)/sizeof(types[0]), + sizeof(types[0]), + type_cmp); + + while ((try_all_flag && i < sizeof(types)/sizeof(types[0])) || + (typename = (argv++)[0])) { + + if (try_all_flag) { + typename = sorted_types[i].name; + } else { + size_t right = sizeof(types)/sizeof(types[0]) - 1; + size_t left = 0; + size_t mid = (left + right) >> 1; + int c = -1; + + while (left <= right) { + mid = (left + right) >> 1; + c = strcmp(sorted_types[mid].name, typename); + if (c < 0) + left = mid + 1; + else if (c > 0) + right = mid - 1; + else + break; + } + if (c != 0) + errx(1, "Type %s not found", typename); + i = mid; + } + v = ecalloc(1, sorted_types[i].sz); + ret = sorted_types[i].decode(buf, len, v, &sz); + if (ret == 0) { + matches++; + if (!quiet_flag && sz == len) { + fprintf(stderr, "Match: %s\n", typename); + } else if (sequence_flag) { + *size = sz; + } else if (!quiet_flag) { + fprintf(stderr, "Prefix match: %s\n", typename); + } + if (print_flag) { + static int warned = 0; + + if (!sorted_types[i].print) { + if (!warned) + warnx("Missing print support; try enabling / not " + "disabling ASN.1 templating in build " + "configuration"); + warned = 1; + } else { + char *s; + + s = sorted_types[i].print(v, indent_flag ? ASN1_PRINT_INDENT : 0); + if (!s) + err(1, "Could not print %s\n", typename); + if (!quiet_flag) + printf("%s\n", s); + free(s); + } + } + if (test_encode_flag) { + unsigned char *der = emalloc(sz); + size_t wants = sorted_types[i].len(v); + + if (wants != sz) + errx(1, "Encoding will not round trip"); + ret = sorted_types[i].encode(der + (sz - 1), sz, v, &sz); + if (ret != 0) + errx(1, "Encoding failed"); + if (memcmp(buf, der, sz) != 0) + errx(1, "Encoding did not round trip"); + free(der); + } + if (test_copy_flag) { + void *vcpy = ecalloc(1, sorted_types[i].sz); + + ret = sorted_types[i].cpy(v, vcpy); + if (ret != 0) + errx(1, "Copy function failed"); + if (test_encode_flag) { + unsigned char *der = emalloc(sz); + size_t wants = sorted_types[i].len(vcpy); + + if (wants != sz) + errx(1, "Encoding of copy will not round trip"); + ret = sorted_types[i].encode(der + (sz - 1), sz, vcpy, &sz); + if (ret != 0) + errx(1, "Encoding of copy failed"); + if (memcmp(buf, der, sz) != 0) + errx(1, "Encoding of copy did not round trip"); + free(der); + } + sorted_types[i].release(vcpy); + free(vcpy); + } + } + sorted_types[i].release(v); + free(v); + tried++; + i++; + + if (ret == 0 && !try_all_flag && !argv[0]) + return 0; + + if (!try_all_flag && argv[0]) + continue; + + if (try_all_flag) { + if (i < sizeof(types)/sizeof(types[0])) + continue; + if (matches) + break; + } + if (tried > 1) + errx(1, "No type matched the input value"); + + /* XXX Use com_err */ + switch (ret) { + case ASN1_BAD_TIMEFORMAT: + errx(1, "Could not decode and print data as type %s: " + "Bad time format", typename); + case ASN1_MISSING_FIELD: + errx(1, "Could not decode and print data as type %s: " + "Missing required field", typename); + case ASN1_MISPLACED_FIELD: + errx(1, "Could not decode and print data as type %s: " + "Fields out of order", typename); + case ASN1_TYPE_MISMATCH: + errx(1, "Could not decode and print data as type %s: " + "Type mismatch", typename); + case ASN1_OVERFLOW: + errx(1, "Could not decode and print data as type %s: " + "DER value too large", typename); + case ASN1_OVERRUN: + errx(1, "Could not decode and print data as type %s: " + "DER value too short", typename); + case ASN1_BAD_ID: + errx(1, "Could not decode and print data as type %s: " + "DER tag is unexpected", typename); + case ASN1_BAD_LENGTH: + errx(1, "Could not decode and print data as type %s: " + "DER length does not match value", typename); + case ASN1_BAD_FORMAT: + case ASN1_PARSE_ERROR: + errx(1, "Could not decode and print data as type %s: " + "DER badly formatted", typename); + case ASN1_EXTRA_DATA: + errx(1, "Could not decode and print data as type %s: " + "Extra data past end of end structure", typename); + case ASN1_BAD_CHARACTER: + errx(1, "Could not decode and print data as type %s: " + "Invalid character encoding in string", typename); + case ASN1_MIN_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Too few elements", typename); + case ASN1_MAX_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Too many elements", typename); + case ASN1_EXACT_CONSTRAINT: + errx(1, "Could not decode and print data as type %s: " + "Wrong count of elements", typename); + case ASN1_INDEF_OVERRUN: + errx(1, "Could not decode and print data as type %s: " + "BER indefinte encoding overun", typename); + case ASN1_INDEF_UNDERRUN: + errx(1, "Could not decode and print data as type %s: " + "BER indefinte encoding underun", typename); + case ASN1_GOT_BER: + errx(1, "Could not decode and print data as type %s: " + "BER encoding when DER expected", typename); + case ASN1_INDEF_EXTRA_DATA: + errx(1, "Could not decode and print data as type %s: " + "End-of-contents tag contains data", typename); + default: + errx(1, "Could not decode and print data as type %s", typename); + } + } + return 0; +} + +static int +doit(char **argv) +{ + int fd = open(argv[0], O_RDONLY); + struct stat sb; + unsigned char *buf; + size_t len; + int ret; + + if(fd < 0) + err(1, "opening %s for read", argv[0]); + if (fstat (fd, &sb) < 0) + err(1, "stat %s", argv[0]); + len = sb.st_size; + buf = emalloc(len); + if (read(fd, buf, len) != len) + errx(1, "read failed"); + close(fd); + + argv++; + if (argv[0] || try_all_flag) { + size_t off = 0; + size_t sz = 0; + + do { + ret = dotype(buf + off, len - off, argv, &sz); + off += sz; + } while (ret == 0 && sequence_flag && off < len); + } else { + ret = loop(buf, len, 0); + } + free(buf); + return ret; +} + + +static int list_types_flag; +static int version_flag; +static int help_flag; +struct getargs args[] = { + { "indent", 'i', arg_negative_flag, &indent_flag, + "\tdo not indent dump", NULL }, + { "inner", 'I', arg_flag, &inner_flag, + "\ttry to parse inner structures of OCTET STRING", NULL }, + { "list-types", 'l', arg_flag, &list_types_flag, + "\tlist ASN.1 types known to this program", NULL }, + { "try-all-types", 'A', arg_flag, &try_all_flag, + "\ttry all known types", NULL }, + { "raw-sequence", 'S', arg_flag, &sequence_flag, + "\ttry parsing leftover data", NULL }, + { "test-encode", 0, arg_flag, &test_encode_flag, + "\ttest encode round trip (for memory debugging and fuzzing)", NULL }, + { "test-copy", 0, arg_flag, &test_copy_flag, + "\ttest copy operation (for memory debugging and fuzzing)", NULL }, + { "print", 'n', arg_negative_flag, &print_flag, + "\ttest copy operation (for memory debugging and fuzzing)", NULL }, + { "quiet", 'q', arg_flag, &quiet_flag, + "\tOutput nothing (exit status 0 means type matched)", NULL }, + { "version", 'v', arg_flag, &version_flag, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + arg_printusage(args, num_args, NULL, "dump-file [TypeName [TypeName ...]]"); + exit(code); +} + +int +main(int argc, char **argv) +{ + int optidx = 0; + + setprogname(argv[0]); + initialize_asn1_error_table(); + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if (help_flag) + usage(0); + if (version_flag) { + print_version(NULL); + exit(0); + } + argv += optidx; + argc -= optidx; + + if (sequence_flag && try_all_flag) + errx(1, "--raw-sequence and --try-all-types are mutually exclusive"); + if (quiet_flag && !try_all_flag && argc < 2) + errx(1, "--quiet requires --try-all-types or that a TypeName be given"); + if (!print_flag && !try_all_flag && argc < 2) + errx(1, "--no-print requires --try-all-types or that a TypeName be given"); + + if (list_types_flag) { + size_t i; + + if (argc) + errx(1, "--list-types is exclusive of other options or arguments"); + + for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) + printf("%s\n", types[i].name); + exit(0); + } + + if (argc < 1) + usage(1); + return doit(argv); +} diff --git a/third_party/heimdal/lib/asn1/asn1parse.y b/third_party/heimdal/lib/asn1/asn1parse.y new file mode 100644 index 0000000..d9e3fba --- /dev/null +++ b/third_party/heimdal/lib/asn1/asn1parse.y @@ -0,0 +1,2036 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +%{ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include "symbol.h" +#include "lex.h" +#include "gen_locl.h" +#include "der.h" + +static Type *new_type (Typetype t); +/*static IOSClass *new_class(struct fieldhead *);*/ +/*static IOSObject *new_object(struct objfieldhead *);*/ +/*IOSObjectSet *new_object_set(struct objectshead *);*/ +static struct objectshead *add_object_set_spec(struct objectshead *, IOSObject *); +static ObjectField *new_field_setting(char *, Type *, struct value *); +static struct objfieldhead *add_field_setting(struct objfieldhead *, ObjectField *); +static struct fieldhead *add_field_spec(struct fieldhead *, Field *); +static Field *new_type_field(char *, int, Type *); +static Field *new_fixed_type_value_field(char *, Type *, int, int, struct value *); +static Type *parametrize_type(Type *, IOSClass *); +static Type *type_from_class_field(IOSClass *, const char *); +static void validate_object_set(IOSObjectSet *); +/*static Type *type_from_object(const char *, const char *);*/ +static struct constraint_spec *new_constraint_spec(enum ctype); +static Type *new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype); +void yyerror (const char *); +#define yyerror yyerror +static struct objid *new_objid(const char *label, int value); +static void add_oid_to_tail(struct objid *, struct objid *); +static void fix_labels(Symbol *s); + +struct string_list { + char *string; + struct string_list *next; +}; + +static int default_tag_env = TE_EXPLICIT; +static unsigned long idcounter; + +/* Declarations for Bison */ +#define YYMALLOC malloc +#define YYFREE free + +%} + +%union { + int64_t constant; + struct value *value; + struct range *range; + char *name; + Type *type; + IOSClass *class; + IOSObjectSet *objectset; + IOSObject *object; + Field *field; + ObjectField *objfield; + Member *member; + IOSClass *formalparam; + struct objid *objid; + char *defval; + struct string_list *sl; + struct tagtype tag; + struct memhead *members; + struct fieldhead *fields; + struct objectshead *objects; + struct objfieldhead *objfields; + struct constraint_spec *constraint_spec; +} + +%token kw_ABSENT +%token kw_ABSTRACT_SYNTAX +%token kw_ALL +%token kw_APPLICATION +%token kw_AUTOMATIC +%token kw_BEGIN +%token kw_BIT +%token kw_BMPString +%token kw_BOOLEAN +%token kw_BY +%token kw_CHARACTER +%token kw_CHOICE +%token kw_CLASS +%token kw_COMPONENT +%token kw_COMPONENTS +%token kw_CONSTRAINED +%token kw_CONTAINING +%token kw_DEFAULT +%token kw_DEFINITIONS +%token kw_EMBEDDED +%token kw_ENCODED +%token kw_END +%token kw_ENUMERATED +%token kw_EXCEPT +%token kw_EXPLICIT +%token kw_EXPORTS +%token kw_EXTENSIBILITY +%token kw_EXTERNAL +%token kw_FALSE +%token kw_FROM +%token kw_GeneralString +%token kw_GeneralizedTime +%token kw_GraphicString +%token kw_IA5String +%token kw_IDENTIFIER +%token kw_IMPLICIT +%token kw_IMPLIED +%token kw_IMPORTS +%token kw_INCLUDES +%token kw_INSTANCE +%token kw_INTEGER +%token kw_INTERSECTION +%token kw_ISO646String +%token kw_MAX +%token kw_MIN +%token kw_MINUS_INFINITY +%token kw_NULL +%token kw_NumericString +%token kw_OBJECT +%token kw_OCTET +%token kw_OF +%token kw_OPTIONAL +%token kw_ObjectDescriptor +%token kw_PATTERN +%token kw_PDV +%token kw_PLUS_INFINITY +%token kw_PRESENT +%token kw_PRIVATE +%token kw_PrintableString +%token kw_REAL +%token kw_RELATIVE_OID +%token kw_SEQUENCE +%token kw_SET +%token kw_SIZE +%token kw_STRING +%token kw_SYNTAX +%token kw_T61String +%token kw_TAGS +%token kw_TRUE +%token kw_TYPE_IDENTIFIER +%token kw_TeletexString +%token kw_UNION +%token kw_UNIQUE +%token kw_UNIVERSAL +%token kw_UTCTime +%token kw_UTF8String +%token kw_UniversalString +%token kw_VideotexString +%token kw_VisibleString +%token kw_WITH + +%token RANGE +%token EEQUAL +%token ELLIPSIS + +%token <name> TYPE_IDENTIFIER referencename +%token <name> CLASS_IDENTIFIER +%token <name> VALUE_IDENTIFIER +%token <name> STRING + +%token <constant> NUMBER +%type <constant> SignedNumber +%type <constant> Class tagenv +%type <constant> DummyReference + +%type <name> Identifier + +/* + * The NULL keyword being both a value and a type causes a reduce/reduce + * conflict in the FieldSetting production since its alternatives are + * + * '&' Identifier Type + * + * and + * + * '&' Identifier Value + * + * and NULL is both a type and a value. + * + * For now we work around this by having a ValueExNull production that excludes + * the NULL value. To really get past this will require unifying the type and + * value types (e.g., via type punning). + */ +%type <value> Value ValueExNull +%type <value> BuiltinValue BuiltinValueExNull +%type <value> IntegerValue +%type <value> BooleanValue +%type <value> ObjectIdentifierValue +%type <value> CharacterStringValue +%type <value> NullValue +%type <value> DefinedValue +%type <value> ReferencedValue +%type <value> Valuereference + +%type <class> DefinedObjectClass ParamGovernor +%type <class> ObjectClassDefn +%type <class> Parameter + +%type <type> Type +%type <type> BuiltinType +%type <type> BitStringType +%type <type> BooleanType +%type <type> ChoiceType +%type <type> ConstrainedType +%type <type> UnconstrainedType +%type <type> EnumeratedType +%type <type> IntegerType +%type <type> NullType +%type <type> OctetStringType +%type <type> SequenceType +%type <type> SequenceOfType +%type <type> SetType +%type <type> SetOfType +%type <type> TaggedType +%type <type> ReferencedType +%type <type> DefinedType +%type <type> UsefulType +%type <type> ObjectIdentifierType +%type <type> CharacterStringType +%type <type> RestrictedCharactedStringType +%type <type> ObjectClassFieldType +%type <type> ParameterizedType +/*%type <type> TypeFromObject*/ + +%type <objectset> ObjectSet DefinedObjectSet +%type <objectset> ActualParameter +%type <object> Object DefinedObject ObjectDefn +%type <objfield> FieldSetting + +%type <tag> Tag + +%type <field> FieldSpec TypeFieldSpec FixedTypeValueFieldSpec +%type <fields> FieldSpecList +%type <member> ComponentType +%type <member> NamedBit +%type <member> NamedNumber +%type <member> NamedType +%type <members> ComponentTypeList +%type <members> Enumerations +%type <members> NamedBitList +%type <members> NamedNumberList +%type <objects> ObjectSetSpec +%type <objfields> FieldSettings + +%type <objid> objid objid_list objid_element objid_opt +%type <range> range size + +%type <sl> referencenames + +%type <constraint_spec> Constraint +%type <constraint_spec> ConstraintSpec +%type <constraint_spec> SubtypeConstraint +%type <constraint_spec> GeneralConstraint +%type <constraint_spec> ContentsConstraint +%type <constraint_spec> UserDefinedConstraint +%type <constraint_spec> SimpleTableConstraint TableConstraint +%type <constraint_spec> ComponentRelationConstraint + + +%start ModuleDefinition + +%% + +/* + * We have sinned by allowing types to have names that start with lower-case, + * and values that have names that start with upper-case. + * + * UPDATE: We sin no more. However, parts of this block comment are still + * relevant. + * + * That worked when we only supported basic X.680 because the rules for + * TypeAssignment and ValueAssignment are clearly unambiguous in spite of the + * case issue. + * + * We now pay the price because X.681 adds productions where the only thing we + * have to help us distinguish certain rules is the form of an identifier: the + * case of its first letter. + * + * We have cleansed our sin by not allowing wrong-case identifiers any more. + * + * Some historical instances of this sin in-tree: + * + * - DOMAIN-X500-COMPRESS (value (enum) but name starts with upper-case) + * - krb5int32 (type but name starts with lower-case) + * - krb5uint32 (type but name starts with lower-case) + * - hdb_keyset (type but name starts with lower-case) + * - hdb_entry (type but name starts with lower-case) + * - hdb_entry_alias (type but name starts with lower-case) + * - HDB_DB_FORMAT INTEGER (value (int) but name starts with upper-case) + * + * We have fixed all of these and others, in some cases leaving behind aliases + * in header files as needed. + * + * We have one shift/reduce conflict (shift ObjectClassAssignment, reduce + * TypeAssignment) and one reduce/reduce conflict (ObjectAssignment vs + * ValueAssignment) that we avoid by requiring CLASS names to start with an + * underscore. + * + * In the FieldSetting rule, also, we get a reduce/reduce conflict if we use + * `Identifier' instead of `TYPE_IDENTIFIER' for type field settings and + * `VALUE_IDENTIFIER' for value field settings, and then we can't make + * progress. + * + * Looking forward, we may not (will not) be able to distinguish ValueSet and + * ObjectSet field settings from each other either, and we may not (will not) + * be able distinguish Object and Value field settings from each other as well. + * To deal with those we will have to run-time type-tag and type-pun the C + * structures for valueset/objectset and value/object, and have one rule for + * each of those that inspects the type of the item to decide what kind of + * setting it is. + * + * Sadly, the extended syntax for ASN.1 (x.680 + x.681/2/3) appears to have + * ambiguities that cannot be resolved with bison/yacc. + */ +Identifier : TYPE_IDENTIFIER { $$ = $1; } + | VALUE_IDENTIFIER { $$ = $1; }; + +ModuleDefinition: Identifier objid_opt kw_DEFINITIONS TagDefault ExtensionDefault + EEQUAL kw_BEGIN ModuleBody kw_END + { + struct objid **o = objid2list($2); + size_t i; + + fprintf(jsonfile, + "{\"module\":\"%s\",\"tagging\":\"%s\",\"objid\":[", $1, + default_tag_env == TE_EXPLICIT ? "explicit" : "implicit"); + + for (i = 0; o && o[i]; i++) { + fprintf(jsonfile, "%s{\"value\":%d", i ? "," : "", o[i]->value); + if (o[i]->label) + fprintf(jsonfile, ",\"label\":\"%s\"", o[i]->label); + fprintf(jsonfile, "}"); + } + fprintf(jsonfile, "]}\n"); + free(o); + } + ; + +TagDefault : kw_EXPLICIT kw_TAGS + { default_tag_env = TE_EXPLICIT; } + | kw_IMPLICIT kw_TAGS + { default_tag_env = TE_IMPLICIT; } + | kw_AUTOMATIC kw_TAGS + { lex_error_message("automatic tagging is not supported"); } + | /* empty */ + ; + +ExtensionDefault: kw_EXTENSIBILITY kw_IMPLIED + { lex_error_message("no extensibility options supported"); } + | /* empty */ + ; + +ModuleBody : Exports Imports AssignmentList + | /* empty */ + ; + +Imports : kw_IMPORTS SymbolsImported ';' + | /* empty */ + ; + +SymbolsImported : SymbolsFromModuleList + | /* empty */ + ; + +SymbolsFromModuleList: SymbolsFromModule + | SymbolsFromModuleList SymbolsFromModule + ; + +SymbolsFromModule: referencenames kw_FROM Identifier objid_opt + { + /* + * FIXME We really could use knowing what kind of thing the + * identifier identifies -- a type, a value, what? + * + * Our sin of allowing type names to start with lower-case + * and values with upper-case means we can't tell. So we + * assume it's types only, but that means we can't import + * OID values, but we really want to! + * + * One thing we could do is not force `s->stype = Stype' + * here, instead set it to a new `Sunknown' value so that + * the first place that refers to this symbol with enough + * context to imply a symbol type can set it. + */ + struct string_list *sl; + for(sl = $1; sl != NULL; sl = sl->next) { + Symbol *s = addsym(sl->string); + s->stype = Stype; + gen_template_import(s); + } + add_import($3); + } + ; + +Exports : kw_EXPORTS referencenames ';' + { + struct string_list *sl; + for(sl = $2; sl != NULL; sl = sl->next) + add_export(sl->string); + } + | kw_EXPORTS kw_ALL + | /* empty */ + ; + +AssignmentList : Assignment + | Assignment AssignmentList + ; + +Assignment : TypeAssignment + | ValueAssignment + | ParameterizedTypeAssignment + | ObjectClassAssignment + | ObjectAssignment + | ObjectSetAssignment + /* | ParameterizedAssignment // from X.683 */ + ; + +referencenames : Identifier ',' referencenames + { + $$ = emalloc(sizeof(*$$)); + $$->string = $1; + $$->next = $3; + } + | Identifier + { + $$ = emalloc(sizeof(*$$)); + $$->string = $1; + $$->next = NULL; + } + ; + +DefinedObjectClass + : CLASS_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sclass) + lex_error_message ("%s is not a class\n", $1); + $$ = s->iosclass; + }; + +ObjectClassAssignment + : CLASS_IDENTIFIER EEQUAL ObjectClassDefn + { + Symbol *s = addsym($1); + s->stype = Sclass; + s->iosclass = $3; + s->iosclass->symbol = s; + fix_labels(s); + } + | CLASS_IDENTIFIER EEQUAL DefinedObjectClass + { + Symbol *s = addsym($1); + s->stype = Sclass; + s->iosclass = $3; + } + /* | ParameterizedObjectClass */ + ; + +ObjectClassDefn : kw_CLASS '{' FieldSpecList '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->fields = $3; + $$->id = idcounter++; + }; + +ObjectAssignment: VALUE_IDENTIFIER DefinedObjectClass EEQUAL Object + { + Symbol *s = addsym($1); + s->stype = Sobj; + s->object = $4; + s->object->iosclass = $2; + if (!s->object->symbol) + s->object->symbol = s; + fix_labels(s); + } + ; + +ObjectSetAssignment + : TYPE_IDENTIFIER DefinedObjectClass EEQUAL ObjectSet + { + Symbol *s = addsym($1); + s->stype = Sobjset; + s->iosclass = $2; + s->objectset = $4; + s->objectset->symbol = s->objectset->symbol ? s->objectset->symbol : s; + s->objectset->iosclass = $2; + validate_object_set($4); + generate_template_objectset_forwards(s); + } + ; + +ObjectSet : '{' ObjectSetSpec '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->objects = $2; + $$->id = idcounter++; + } + ; + +ObjectSetSpec : DefinedObject + { $$ = add_object_set_spec(NULL, $1); } + | ObjectSetSpec '|' DefinedObject + { $$ = add_object_set_spec($1, $3); } + ; + +Object : DefinedObject + | ObjectDefn + /* | ObjectFromObject */ + /* | ParameterizedObject */ + ; + +DefinedObject : VALUE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sobj) + lex_error_message ("%s is not an object\n", $1); + $$ = s->object; + } + ; + +DefinedObjectSet: TYPE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != Sobjset && s->stype != SUndefined) + lex_error_message ("%s is not an object set\n", $1); + $$ = s->objectset; + } + ; + + +ObjectDefn : '{' FieldSettings '}' /* DefaultSyntax */ + { + $$ = ecalloc(1, sizeof(*$$)); + $$->objfields = $2; + $$->id = idcounter++; + } + /* | DefinedSyntax */ + ; + +FieldSettings : FieldSetting + { + $$ = add_field_setting(NULL, $1); + } + | FieldSettings ',' FieldSetting + { + $$ = add_field_setting($1, $3); + } + ; + +/* See note on `Identifier' */ +FieldSetting : '&' Identifier Type + { $$ = new_field_setting($2, $3, NULL); } + | '&' Identifier ValueExNull + { $$ = new_field_setting($2, NULL, $3); } + /* | '&' TYPE_IDENTIFIER ValueSet */ + /* | '&' VALUE_IDENTIFIER Object */ + /* | '&' TYPE_IDENTIFIER ObjectSet */ + ; + +/* Fields of a class */ +FieldSpecList : FieldSpec + { $$ = add_field_spec(NULL, $1); } + | FieldSpecList ',' FieldSpec + { $$ = add_field_spec($1, $3); }; + +/* + * Fields of a CLASS + * + * There are seven kinds of class/object fields: + * + * - type fields, + * - fixed-type value fields, + * - fixed-type value set fields, + * - variable-type value fields + * - variable-type value set fields + * - object fields + * - object set fields + * + * We care only to support the bare minimum to treat open types as a CHOICE of + * sorts and automatically encode/decode values in open types. That's: type + * fields and fixed-type value fields. + */ +FieldSpec : TypeFieldSpec + | FixedTypeValueFieldSpec + /* | VariableTypeValueFieldSpec */ + /* | VariableTypeValueSetFieldSpec */ + /* | FixedTypeValueSetFieldSpec */ + /* | ObjectFieldSpec */ + /* | ObjectSetFieldSpec */ + ; +TypeFieldSpec : '&' Identifier + { $$ = new_type_field($2, 0, NULL); } + | '&' Identifier kw_OPTIONAL + { $$ = new_type_field($2, 1, NULL); } + | '&' Identifier kw_DEFAULT Type + { $$ = new_type_field($2, 1, $4); } + ; + +FixedTypeValueFieldSpec + : '&' Identifier Type + { $$ = new_fixed_type_value_field($2, $3, 0, 0, NULL); } + | '&' Identifier Type kw_UNIQUE + { $$ = new_fixed_type_value_field($2, $3, 1, 0, NULL); } + | '&' Identifier Type kw_UNIQUE kw_OPTIONAL + { $$ = new_fixed_type_value_field($2, $3, 1, 1, NULL); } + | '&' Identifier Type kw_UNIQUE kw_DEFAULT Value + { $$ = new_fixed_type_value_field($2, $3, 1, 0, $6); } + | '&' Identifier Type kw_OPTIONAL + { $$ = new_fixed_type_value_field($2, $3, 0, 1, NULL); } + | '&' Identifier Type kw_DEFAULT Value + { $$ = new_fixed_type_value_field($2, $3, 0, 0, $5); }; + +/* + * Now we need a bit of X.683, just enough to parse PKIX. + * + * E.g., we need to parse this sort of type definition, which isn't quite the + * final type definition because the ExtensionSet will be provided later. + * + *-- <- ObjectClassDefn -> + * EXTENSION ::= CLASS { + * &id OBJECT IDENTIFIER UNIQUE, + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- FixedTypeValueFieldSpec + * + * &ExtnType, + * -- ^^^^^^^^^ + * -- TypeFieldSpec + * + * &Critical BOOLEAN DEFAULT {TRUE | FALSE } + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- FixedTypeValueFieldSpec + * } WITH SYNTAX { + * SYNTAX &ExtnType IDENTIFIED BY &id + * [CRITICALITY &Critical] + * } + * + *-- <--------- ParameterizedTypeAssignment --------> + * -- NOTE: The name of this type has to be Extension, really. + * -- But the name of the Extension type with the actual + * -- parameter provided also has to be Extension. + * -- We could disallow that and require that the various + * -- Extension types all have different names, then we'd + * -- let the one with the actual parameter in PKIX be the + * -- one named Extension. Or we could find a way to let + * -- them all share one symbol name, or at least two: + * -- the one with the formal parameter, and just one with + * -- an actual parameter. + * -- + * -- Also, IMPORTing types that have formal parameters is + * -- almost certainly going to require parsing the IMPORTed + * -- module. Until we do that, users will be able to work + * -- around that by just copying CLASSes and pameterized + * -- type definitions around. But when we do start parsing + * -- IMPORTed modules we might need to do something about + * -- many types possibly having the same names, though we + * -- might do nothing and simply say "don't do that!". + * Extension{EXTENSION:ExtensionSet} ::= SEQUENCE { + * -- ^^^^^^^^^^^^ + * -- is a DummyReference, which is a Reference, basically + * -- it is an object set variable which will have an object + * -- set value supplied where constrained types are defined + * -- from this one, possibly anonymous types where + * -- SEQUENCE/SET members of this type are defined. + * -- ^^^^^^^^^ + * -- is a ParamGovernor, really, just Governor, either a Type or + * -- DefinedObjectClass (we only need DefinedObjectClass) + * -- ^^^^^^^^^^^^^^^^^^^^^^ + * -- is a Parameter + * -- ^^^^^^^^^^^^^^^^^^^^^^^^ + * -- is a ParameterList (we need only support one param though) + * extnID EXTENSION.&id({ExtensionSet}), + * -- ^^^^^^^^^^^^^^^^ + * -- simple table constraint limiting id to OIDs + * -- from ExtensionSet + * -- ^^^^^^^^^^^^^ + * -- a reference to the id field of the EXTENSION CLASS + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING (CONTAINING + * -- ObjectClassFieldType + * -- vvvvvvvvvvvvvvvvvvv + * EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + * -- ^^^^^^^^^ + * -- AtNotation + * -- ^^^^^^^^^^^^^^ + * -- DefinedObjectSet + * -- ^^^^^^^^^^^^^^^^^^^^^^^^ + * -- ComponentRelationConstraint + * -- says that extnValue will contain + * -- a value of a type identified by + * -- the OID in extnID in the object + * -- set ExtensionSet (which is a set + * -- of {OID, type} objects) + * -- ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * -- ConstraintSpec + * -- ^^^^^^^^^^^^^^^^^^^ + * -- another type ref + * } + * + * Then later we'll see (ParameterizedType, a part of DefinedType): + * + * TBSCertificate ::= SEQUENCE { + * ... + * -- Here is where the object set is linked into the + * -- whole thing, making *magic* possible. This is + * -- where the real Extensions type is defined. Sadly + * -- this might mean we can't have a C type named + * -- Extensions. Hmmm. We might need an ASN.1 + * -- extension that lets use do this: + * -- + * -- Extension ::= Extension{{CertExtensions}} + * -- + * -- or + * -- + * -- Extension ::= ParameterizedExtension{{CertExtensions}} + * -- + * -- and then rename the Extension type above to this. + * -- Then we can define Extensions as a SEQUENCE OF + * -- that. + * -- + * -- <- ParameterizedType -> + * extensions [3] Extensions{{CertExtensions}} OPTIONAL + * -- ^^^^^^^^^^^^^^ + * -- ObjectSetSpec + * -- ^^^^^^^^^^^^^^^^ + * -- ObjectSet + * -- ^^^^^^^^^^^^^^^^^^ + * -- ActualParameterList + * -- ^^^^^^^^^^ + * -- Type + * } + * + * Then: + * + * -- Object set, limits what Extensions can be in TBSCertificate. + *-- <- ObjectSetAssignment -> + * CertExtensions EXTENSION ::= { + * -- ^^^^^^^^^ + * -- DefinedObjectClass + *-- ^^^^^^^^^^^^^^ + *-- objectsetreference, for us, IDENTIFIER + * ext-AuthorityKeyIdentifier | ext-SubjectKeyIdentifier | ... + * } + * + * and: + * + * -- ObjectAssignment (with defined syntax, which we're not going to support): + * -- + * -- Defines one particular object in the CertExtensions object set. + * -- We don't need th SYNTAX bits though -- ETOOMUCHWORK. + * -- This says that the OID id-ce-authorityKeyIdentifier means the extnValue + * -- is a DER-encoded AuthorityKeyIdentifier. + * ext-AuthorityKeyIdentifier EXTENSION ::= { SYNTAX + * AuthorityKeyIdentifier IDENTIFIED BY + * id-ce-authorityKeyIdentifier } + * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + * + * -- ObjectAssignment (with default syntax): + * ext-AuthorityKeyIdentifier EXTENSION ::= { + * -- fields don't have to be in order since we have the field names + * &extnId id-ce-authorityKeyIdentifier, + * &extnValue AuthorityKeyIdentifier + * } + * + * -- Plain old type def using only X.680 + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + * + * In terms of compilation, we'll want to support only the template backend, + * though we'll generate the same C types for both, the template backend and + * the codegen backend. + * + * The generators should see a type for Extension that includes a) the + * parametrization (relating members in the SEQUENCE to fields in the CLASS), + * and b) the object set CertExtensions for the _same_ class. + * + * - The C types for ASN.1 parametrized types with object set parameters + * should be laid out just as before, but with additional fields: + * + * typedef struct Extension { + * heim_oid extnID; + * int *critical; + * heim_octet_string extnValue; + * // NEW FIELDS BELOW + * enum { + * opentypechoice_unknown_Extension = 0 + * opentypechoice_Extension_id_ce_authorityKeyIdentifier, + * ... + * } _element; + * union { + * // er, what should this be named?! we have no name information + * // and naming it after its object value name is probably not a good + * // idea or not easy. We do have the OID value and possible name + * // though, so we should use that: + * AuthorityKeyIdentifier id_ce_authorityKeyIdentifier; + * ... + * } _u; + * } Extension; + * + * - The template for this should consist of new struct asn1_template entries + * following the ones for the normal fields of Extension. The first of these + * should have an OP that indicates that the following N entries correspond + * to the object set that specifies this open type, then the following N + * entries should each point to an object in the object set. Or maybe the + * object set should be a separate template -- either way. We'll also want a + * flag to indicate whether the object set is sorted (none of the type IDs + * are IMPORTed) or not (some of the type IDs are IMPORTed) so we can binary + * search the object set at encode/decode time. + * + * Hmm, we can assume the object sets are already sorted when there's + * IMPORTed IDs -- the author can do it. Yes, they're sets, but lexically + * they must be in some order. + * + * I like that, actually, requiring that the module author manually sort the + * object sets, at least when they refer to type IDs that are IMPORTed. Or + * maybe forbid object sets that use IMPORTed type IDs -- the module author + * can always copy their definitions anyways. + */ + +TypeAssignment : Identifier EEQUAL Type + { + Symbol *s = addsym($1); + s->stype = Stype; + s->type = $3; + fix_labels(s); + + /* + * Hack: make sure that non-anonymous enumeration types get + * a symbol tacked on so we can generate a template for + * their members for value printing. + */ + if (s->type->type == TTag && $3->symbol == NULL && + $3->subtype != NULL && $3->subtype->type == TInteger && + $3->subtype->symbol == NULL) { + $3->subtype->symbol = s; + } + if (original_order) + generate_type(s); + else + generate_type_header_forwards(s); + } + ; + +ParameterizedTypeAssignment + /* For now we'll only support one parameter -- enough for PKIX */ + : Identifier '{' Parameter '}' EEQUAL Type + { + char *pname = NULL; + Symbol *s; + + if (asprintf(&pname, "%s{%s:x}", $1, $3->symbol->name) == -1 || + pname == NULL) + err(1, "Out of memory"); + s = addsym(pname); + free($1); + s->stype = Sparamtype; + s->type = parametrize_type($6, $3); + s->type->symbol = s; + fix_labels(s); + } + ; + +/* + * We're not going to support governor variables for now. We don't need to. + * + * Also, we're not going to support more than one formal parameter. + * Correspondingly we'll only support a single actual parameter (the count of + * formal and actual parameters has to match, naturally). + */ + +Parameter : ParamGovernor ':' DummyReference + { $$ = $1; }; + /* | DummyReference */ + ; + +DummyReference : TYPE_IDENTIFIER { $$ = idcounter++; }; + +ParamGovernor : DefinedObjectClass + { $$ = $1; } + /* | DummyGovernor */ + /* | Type */ + ; + +UnconstrainedType : BitStringType + | BooleanType + | CharacterStringType + | ChoiceType + | EnumeratedType + | IntegerType + | NullType + | ObjectIdentifierType + | OctetStringType + | SequenceType + | SetType + | ObjectClassFieldType; /* X.681 */ + +Type : BuiltinType | ReferencedType | ConstrainedType ; + +BuiltinType : BitStringType + | BooleanType + | CharacterStringType + | ChoiceType + | EnumeratedType + | IntegerType + | NullType + | ObjectIdentifierType + | OctetStringType + | SequenceType + | SequenceOfType + | SetType + | SetOfType + | TaggedType + | ObjectClassFieldType /* X.681 */ + /* | InstanceOfType // X.681 */ + ; + +ObjectClassFieldType + : DefinedObjectClass '.' '&' Identifier + { $$ = type_from_class_field($1, $4); }; + +BooleanType : kw_BOOLEAN + { + $$ = new_tag(ASN1_C_UNIV, UT_Boolean, + TE_EXPLICIT, new_type(TBoolean)); + } + ; + + /* + * The spec says the values in a ValueRange are Values, but a) all + * the various value ranges do not involve OBJECT IDENTIFIER, b) + * we only support integer value ranges at this time (as opposed + * to, e.g., time ranges, and we don't even support time values at + * this time), c) allowing OBJECT IDENTIFIER here causes a + * shift-reduce conflict, so we limit ourselves to integer values + * in ranges. We could always define IntegerValueRange, + * TimeValueRange, etc. when we add support for more value types. + */ +range : IntegerValue RANGE IntegerValue + { + if($1->type != integervalue) + lex_error_message("Non-integer used in first part of range"); + if($1->type != integervalue) + lex_error_message("Non-integer in second part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = $3->u.integervalue; + } + | IntegerValue RANGE kw_MAX + { + if($1->type != integervalue) + lex_error_message("Non-integer in first part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = INT_MAX; + } + | kw_MIN RANGE IntegerValue + { + if($3->type != integervalue) + lex_error_message("Non-integer in second part of range"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = INT_MIN; + $$->max = $3->u.integervalue; + } + | IntegerValue + { + if($1->type != integervalue) + lex_error_message("Non-integer used in limit"); + $$ = ecalloc(1, sizeof(*$$)); + $$->min = $1->u.integervalue; + $$->max = $1->u.integervalue; + } + ; + + +IntegerType : kw_INTEGER + { + $$ = new_tag(ASN1_C_UNIV, UT_Integer, + TE_EXPLICIT, new_type(TInteger)); + } + | kw_INTEGER '{' NamedNumberList '}' + { + $$ = new_type(TInteger); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$); + } + ; + +NamedNumberList : NamedNumber + { + $$ = emalloc(sizeof(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | NamedNumberList ',' NamedNumber + { + HEIM_TAILQ_INSERT_TAIL($1, $3, members); + $$ = $1; + } + | NamedNumberList ',' ELLIPSIS + { $$ = $1; } /* XXX used for Enumerations */ + ; + +NamedNumber : Identifier '(' SignedNumber ')' + { + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->val = $3; + $$->optional = 0; + $$->ellipsis = 0; + $$->type = NULL; + } + | Identifier '(' DefinedValue ')' + { + if ($3->type != integervalue) + lex_error_message("Named number %s not a numeric value", + $3->s->name); + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->val = $3->u.integervalue; + $$->optional = 0; + $$->ellipsis = 0; + $$->type = NULL; + } + ; + +EnumeratedType : kw_ENUMERATED '{' Enumerations '}' + { + $$ = new_type(TInteger); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Enumerated, TE_EXPLICIT, $$); + } + ; + +Enumerations : NamedNumberList /* XXX */ + ; + +BitStringType : kw_BIT kw_STRING + { + $$ = new_type(TBitString); + $$->members = emalloc(sizeof(*$$->members)); + HEIM_TAILQ_INIT($$->members); + $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); + } + | kw_BIT kw_STRING '{' NamedBitList '}' + { + $$ = new_type(TBitString); + $$->members = $4; + $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$); + } + ; + +ObjectIdentifierType: kw_OBJECT kw_IDENTIFIER + { + $$ = new_tag(ASN1_C_UNIV, UT_OID, + TE_EXPLICIT, new_type(TOID)); + } + ; +OctetStringType : kw_OCTET kw_STRING size + { + Type *t = new_type(TOctetString); + t->range = $3; + if (t->range) { + if (t->range->min < 0) + lex_error_message("can't use a negative SIZE range " + "length for OCTET STRING"); + } + $$ = new_tag(ASN1_C_UNIV, UT_OctetString, + TE_EXPLICIT, t); + } + ; + +NullType : kw_NULL + { + $$ = new_tag(ASN1_C_UNIV, UT_Null, + TE_EXPLICIT, new_type(TNull)); + } + ; + +size : + { $$ = NULL; } + | kw_SIZE '(' range ')' + { $$ = $3; } + ; + + +SequenceType : kw_SEQUENCE '{' /* ComponentTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TSequence); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + | kw_SEQUENCE '{' '}' + { + $$ = new_type(TSequence); + $$->members = NULL; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + ; + +SequenceOfType : kw_SEQUENCE size kw_OF Type + { + $$ = new_type(TSequenceOf); + $$->range = $2; + if ($$->range) { + if ($$->range->min < 0) + lex_error_message("can't use a negative SIZE range " + "length for SEQUENCE OF"); + } + + $$->subtype = $4; + $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$); + } + ; + +SetType : kw_SET '{' /* ComponentTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TSet); + $$->members = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + | kw_SET '{' '}' + { + $$ = new_type(TSet); + $$->members = NULL; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + ; + +SetOfType : kw_SET kw_OF Type + { + $$ = new_type(TSetOf); + $$->subtype = $3; + $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$); + } + ; + +ChoiceType : kw_CHOICE '{' /* AlternativeTypeLists */ ComponentTypeList '}' + { + $$ = new_type(TChoice); + $$->members = $3; + } + ; + +ReferencedType : DefinedType + | UsefulType + /* | TypeFromObject // X.681 */ + /* | ValueSetFromObjects // X.681 */ + ; + +/* +TypeFromObject : VALUE_IDENTIFIER '.' '&' TYPE_IDENTIFIER + { $$ = type_from_object($1, $4); }; + */ + +DefinedType : TYPE_IDENTIFIER + { + Symbol *s = addsym($1); + $$ = new_type(TType); + if(s->stype != Stype && s->stype != SUndefined) + lex_error_message ("%s is not a type\n", $1); + else + $$->symbol = s; + } + | ParameterizedType + { $$ = $1; } + ; + + /* + * Should be ActualParameterList, but we'll do just one for now + * as that's enough for PKIX. + */ +ParameterizedType + : Identifier '{' ActualParameter '}' /* XXX ActualParameterList */ + { + Symbol *s, *ps; + char *pname = NULL; + + if ($3 == NULL) { + lex_error_message("Unknown ActualParameter object set parametrizing %s\n", $1); + exit(1); + } + + /* Lookup the type from a ParameterizedTypeAssignment */ + if (asprintf(&pname, "%s{%s:x}", $1, + $3->iosclass->symbol->name) == -1 || + pname == NULL) + err(1, "Out of memory"); + ps = addsym(pname); + if (ps->stype != Sparamtype) + lex_error_message ("%s is not a parameterized type\n", $1); + + s = addsym($1); + $$ = ps->type; /* XXX copy, probably */ + if (!ps->type) + errx(1, "Wrong class (%s) parameter for parameterized " + "type %s", $3->iosclass->symbol->name, $1); + s->stype = Stype; + if(s->stype != Stype && s->stype != SUndefined) + lex_error_message ("%s is not a type\n", $1); + else + $$->symbol = s; + $$->actual_parameter = $3; + if ($$->type == TTag) + $$->subtype->actual_parameter = $3; + } + +/* + * Per X.683 $1 for ActualParameter should be any of: a Type, a Value, a + * ValueSet, a DefinedObjectClass, an Object, or an ObjectSet. For PKIX we + * need nothing more than an ObjectSet here. + * + * Also, we can't lexically or syntactically tell the difference between all + * these things, though fortunately we can for ObjectSet. + */ +ActualParameter : DefinedObjectSet + { $$ = $1; }; + +UsefulType : kw_GeneralizedTime + { + $$ = new_tag(ASN1_C_UNIV, UT_GeneralizedTime, + TE_EXPLICIT, new_type(TGeneralizedTime)); + } + | kw_UTCTime + { + $$ = new_tag(ASN1_C_UNIV, UT_UTCTime, + TE_EXPLICIT, new_type(TUTCTime)); + } + ; + +ConstrainedType : UnconstrainedType Constraint + { + $$ = $1; + if ($2->ctype == CT_RANGE) { + if ($1->type != TTag || $1->subtype->type != TInteger) + lex_error_message("RANGE constraints apply only to INTEGER types"); + $$->subtype->range = $2->u.range; + free($2); + } else { + $$->constraint = $2; + } + /* if (Constraint.type == contentConstraint) { + assert(Constraint.u.constraint.type == octetstring|bitstring-w/o-NamedBitList); // remember to check type reference too + if (Constraint.u.constraint.type) { + assert((Constraint.u.constraint.type.length % 8) == 0); + } + } + if (Constraint.u.constraint.encoding) { + type == der-oid|ber-oid + } + */ + } + ; + + +Constraint : '(' ConstraintSpec ')' + { + $$ = $2; + } + ; + +ConstraintSpec : SubtypeConstraint | GeneralConstraint + ; + +SubtypeConstraint: range + { + $$ = new_constraint_spec(CT_RANGE); + $$->u.range = $1; + } + +GeneralConstraint: ContentsConstraint + | UserDefinedConstraint + | TableConstraint + ; + +ContentsConstraint: kw_CONTAINING Type + { + $$ = new_constraint_spec(CT_CONTENTS); + $$->u.content.type = $2; + $$->u.content.encoding = NULL; + } + | kw_ENCODED kw_BY Value + { + if ($3->type != objectidentifiervalue) + lex_error_message("Non-OID used in ENCODED BY constraint"); + $$ = new_constraint_spec(CT_CONTENTS); + $$->u.content.type = NULL; + $$->u.content.encoding = $3; + } + | kw_CONTAINING Type kw_ENCODED kw_BY Value + { + if ($5->type != objectidentifiervalue) + lex_error_message("Non-OID used in ENCODED BY constraint"); + $$ = new_constraint_spec(CT_CONTENTS); + $$->u.content.type = $2; + $$->u.content.encoding = $5; + } + ; + +UserDefinedConstraint: kw_CONSTRAINED kw_BY '{' '}' + { + $$ = new_constraint_spec(CT_USER); + } + ; + +TableConstraint : SimpleTableConstraint + { $$ = $1; } + | ComponentRelationConstraint + { $$ = $1; }; + +SimpleTableConstraint + : '{' TYPE_IDENTIFIER '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->ctype = CT_TABLE_CONSTRAINT; + $$->u.content.crel.objectname = $2; + $$->u.content.crel.membername = 0; + }; + +/* + * In X.682, ComponentRelationConstraint is a fantastically more complicated + * production. The stuff in the second set of braces is a list of AtNotation, + * and AtNotation is '@' followed by some number of '.'s, followed by a + * ComponentIdList, which is a non-empty set of identifiers separated by '.'s. + * The number of '.'s is a "level" used to identify a SET, SEQUENCE, or CHOICE + * where the path of member identifiers is rooted that ultimately identifies + * the field providing the constraint. + * + * So in + * + * extnValue OCTET STRING + * (CONTAINING + * EXTENSION.&ExtnType({ExtensionSet}{@extnID})) + * ^^^^^^^^^^^^^^^^^^^ + * ObjectClassFieldType + * meaning the open type field + * &ExtnType of EXTENSION + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * GeneralConstraint + * ^^^^^^^^^^^^^^^^^^^^^^^ + * ComponentRelationConstraint + * ^^^^^^^^^^^^^^ + * DefinedObjectSet + * ^^^^^^^^ + * '{' AtNotation ',' + '}' + * + * we have EXTENSION.&ExtnType is the ObjectClassFieldType, and + * ({ExtensionSet}{@extnID}) is the ComponentRelationConstraint on the + * extnValue member, where {ExtensionSet} is the DummyReference from the formal + * parameter of the enclosing parameterized type, and {@extnID} is the + * AtNotation list identifying the field of the class/objects-in-the-object-set + * that will be identifying the type of the extnValue field. + * + * We need just the one AtNotation component. + */ +ComponentRelationConstraint + : '{' TYPE_IDENTIFIER '}' '{' '@' Identifier '}' + { + $$ = ecalloc(1, sizeof(*$$)); + $$->ctype = CT_TABLE_CONSTRAINT; + $$->u.content.crel.objectname = $2; + $$->u.content.crel.membername = $6; + }; + +TaggedType : Tag tagenv Type + { + $$ = new_type(TTag); + $$->tag = $1; + $$->tag.tagenv = $2; + if (template_flag) { + $$->subtype = $3; + } else if ($2 == TE_IMPLICIT) { + Type *t = $3; + + /* + * FIXME We shouldn't do this... The logic for + * dealing with IMPLICIT tags belongs elsewhere. + */ + while (t->type == TType) { + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + break; + } + /* + * IMPLICIT tags of CHOICE types are EXPLICIT + * instead. + */ + if (t->type == TChoice) { + $$->implicit_choice = 1; + $$->tag.tagenv = TE_EXPLICIT; + } + if($3->type == TTag && $2 == TE_IMPLICIT) { + $$->subtype = $3->subtype; + free($3); + } else { + $$->subtype = $3; + } + } else { + $$->subtype = $3; + } + } + ; + +Tag : '[' Class NUMBER ']' + { + $$.tagclass = $2; + $$.tagvalue = $3; + $$.tagenv = default_tag_env; + } + ; + +Class : /* */ + { + $$ = ASN1_C_CONTEXT; + } + | kw_UNIVERSAL + { + $$ = ASN1_C_UNIV; + } + | kw_APPLICATION + { + $$ = ASN1_C_APPL; + } + | kw_PRIVATE + { + $$ = ASN1_C_PRIVATE; + } + ; + +tagenv : /* */ + { + $$ = default_tag_env; + } + | kw_EXPLICIT + { + $$ = default_tag_env; + } + | kw_IMPLICIT + { + $$ = TE_IMPLICIT; + } + ; + + +ValueAssignment : VALUE_IDENTIFIER Type EEQUAL Value + { + Symbol *s; + s = addsym ($1); + + s->stype = SValue; + s->value = $4; + generate_constant (s); + /* + * Save this value's name so we can know some name for + * this value wherever _a_ name may be needed for it. + * + * This is useful for OIDs used as type IDs in objects + * sets of classes with open types. We'll generate + * enum labels from those OIDs' names. + */ + s->value->s = s; + } + ; + +CharacterStringType: RestrictedCharactedStringType + ; + +RestrictedCharactedStringType: kw_GeneralString + { + $$ = new_tag(ASN1_C_UNIV, UT_GeneralString, + TE_EXPLICIT, new_type(TGeneralString)); + } + | kw_TeletexString + { + $$ = new_tag(ASN1_C_UNIV, UT_TeletexString, + TE_EXPLICIT, new_type(TTeletexString)); + } + | kw_UTF8String + { + $$ = new_tag(ASN1_C_UNIV, UT_UTF8String, + TE_EXPLICIT, new_type(TUTF8String)); + } + | kw_PrintableString + { + $$ = new_tag(ASN1_C_UNIV, UT_PrintableString, + TE_EXPLICIT, new_type(TPrintableString)); + } + | kw_VisibleString + { + $$ = new_tag(ASN1_C_UNIV, UT_VisibleString, + TE_EXPLICIT, new_type(TVisibleString)); + } + | kw_IA5String + { + $$ = new_tag(ASN1_C_UNIV, UT_IA5String, + TE_EXPLICIT, new_type(TIA5String)); + } + | kw_BMPString + { + $$ = new_tag(ASN1_C_UNIV, UT_BMPString, + TE_EXPLICIT, new_type(TBMPString)); + } + | kw_UniversalString + { + $$ = new_tag(ASN1_C_UNIV, UT_UniversalString, + TE_EXPLICIT, new_type(TUniversalString)); + } + + ; + +ComponentTypeList: ComponentType + { + $$ = emalloc(sizeof(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | ComponentTypeList ',' ComponentType + { + HEIM_TAILQ_INSERT_TAIL($1, $3, members); + $$ = $1; + } + | ComponentTypeList ',' ELLIPSIS + { + struct member *m = ecalloc(1, sizeof(*m)); + m->name = estrdup("..."); + m->gen_name = estrdup("asn1_ellipsis"); + m->ellipsis = 1; + HEIM_TAILQ_INSERT_TAIL($1, m, members); + $$ = $1; + } + ; + +NamedType : Identifier Type + { + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->type = $2; + $$->ellipsis = 0; + } + ; + +ComponentType : NamedType + { + $$ = $1; + $$->optional = 0; + $$->defval = NULL; + } + | NamedType kw_OPTIONAL + { + $$ = $1; + $$->optional = 1; + $$->defval = NULL; + } + | NamedType kw_DEFAULT Value + { + $$ = $1; + $$->optional = 0; + $$->defval = $3; + } + ; + +NamedBitList : NamedBit + { + $$ = emalloc(sizeof(*$$)); + HEIM_TAILQ_INIT($$); + HEIM_TAILQ_INSERT_HEAD($$, $1, members); + } + | NamedBitList ',' NamedBit + { + HEIM_TAILQ_INSERT_TAIL($1, $3, members); + $$ = $1; + } + ; + +NamedBit : Identifier '(' NUMBER ')' + { + $$ = emalloc(sizeof(*$$)); + $$->name = $1; + $$->gen_name = estrdup($1); + output_name ($$->gen_name); + $$->val = $3; + $$->optional = 0; + $$->ellipsis = 0; + $$->type = NULL; + } + ; + +objid_opt : objid + | /* empty */ { $$ = NULL; } + ; + +objid : '{' objid_list '}' + { + $$ = $2; + } + ; + +objid_list : /* empty */ + { + $$ = NULL; + } + | objid_element objid_list + { + if ($2) { + $$ = $2; + add_oid_to_tail($2, $1); + } else { + $$ = $1; + } + } + ; + +objid_element : Identifier '(' NUMBER ')' + { + $$ = new_objid($1, $3); + } + | Identifier + { + Symbol *s = addsym($1); + if(s->stype != SValue || + s->value->type != objectidentifiervalue) { + lex_error_message("%s is not an object identifier\n", + s->name); + exit(1); + } + $$ = s->value->u.objectidentifiervalue; + } + | NUMBER + { + $$ = new_objid(NULL, $1); + } + ; + +Value : BuiltinValue + | ReferencedValue + ; + +ValueExNull : BuiltinValueExNull + | ReferencedValue + ; + +BuiltinValue : BooleanValue + | CharacterStringValue + | IntegerValue + | ObjectIdentifierValue + | NullValue + ; + +BuiltinValueExNull + : BooleanValue + | CharacterStringValue + | IntegerValue + | ObjectIdentifierValue + ; + +ReferencedValue : DefinedValue + ; + +DefinedValue : Valuereference + ; + +Valuereference : VALUE_IDENTIFIER + { + Symbol *s = addsym($1); + if(s->stype != SValue) + lex_error_message ("%s is not a value\n", + s->name); + else + $$ = s->value; + } + ; + +CharacterStringValue: STRING + { + $$ = emalloc(sizeof(*$$)); + $$->type = stringvalue; + $$->u.stringvalue = $1; + } + ; + +BooleanValue : kw_TRUE + { + $$ = emalloc(sizeof(*$$)); + $$->type = booleanvalue; + $$->u.booleanvalue = 1; + } + | kw_FALSE + { + $$ = emalloc(sizeof(*$$)); + $$->type = booleanvalue; + $$->u.booleanvalue = 0; + } + ; + +IntegerValue : SignedNumber + { + $$ = emalloc(sizeof(*$$)); + $$->type = integervalue; + $$->u.integervalue = $1; + } + ; + +SignedNumber : NUMBER + ; + +NullValue : kw_NULL + { + } + ; + +ObjectIdentifierValue: objid + { + $$ = emalloc(sizeof(*$$)); + $$->type = objectidentifiervalue; + $$->u.objectidentifiervalue = $1; + } + ; + +%% + +void +yyerror (const char *s) +{ + lex_error_message ("%s\n", s); +} + +static Type * +new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype) +{ + Type *t; + if(oldtype->type == TTag && oldtype->tag.tagenv == TE_IMPLICIT) { + t = oldtype; + oldtype = oldtype->subtype; /* XXX */ + } else + t = new_type (TTag); + + t->tag.tagclass = tagclass; + t->tag.tagvalue = tagvalue; + t->tag.tagenv = tagenv; + t->subtype = oldtype; + return t; +} + +static struct objid * +new_objid(const char *label, int value) +{ + struct objid *s; + s = emalloc(sizeof(*s)); + s->label = label; + s->value = value; + s->next = NULL; + return s; +} + +static void +add_oid_to_tail(struct objid *head, struct objid *tail) +{ + struct objid *o; + o = head; + while (o->next) + o = o->next; + o->next = tail; +} + +static Type * +new_type (Typetype tt) +{ + Type *t = ecalloc(1, sizeof(*t)); + t->type = tt; + t->id = idcounter++; + return t; +} + +static struct constraint_spec * +new_constraint_spec(enum ctype ct) +{ + struct constraint_spec *c = ecalloc(1, sizeof(*c)); + c->ctype = ct; + return c; +} + +static void fix_labels2(Type *t, const char *prefix); +static void fix_labels1(struct memhead *members, const char *prefix) +{ + Member *m; + + if(members == NULL) + return; + HEIM_TAILQ_FOREACH(m, members, members) { + if (asprintf(&m->label, "%s_%s", prefix, m->gen_name) < 0) + errx(1, "malloc"); + if (m->label == NULL) + errx(1, "malloc"); + if(m->type != NULL) + fix_labels2(m->type, m->label); + } +} + +static void fix_labels2(Type *t, const char *prefix) +{ + for(; t; t = t->subtype) + fix_labels1(t->members, prefix); +} + +static void +fix_labels(Symbol *s) +{ + char *p = NULL; + if (asprintf(&p, "choice_%s", s->gen_name) < 0 || p == NULL) + errx(1, "malloc"); + if (s->type) + fix_labels2(s->type, p); + free(p); +} + +static struct objectshead * +add_object_set_spec(struct objectshead *lst, IOSObject *o) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, o, objects); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, o, objects); + } + return lst; +} + +static struct objfieldhead * +add_field_setting(struct objfieldhead *lst, ObjectField *f) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, f, objfields); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, f, objfields); + } + return lst; +} + +static struct fieldhead * +add_field_spec(struct fieldhead *lst, Field *f) +{ + if (lst == NULL) { + lst = emalloc(sizeof(*lst)); + HEIM_TAILQ_INIT(lst); + HEIM_TAILQ_INSERT_HEAD(lst, f, fields); + } else { + HEIM_TAILQ_INSERT_TAIL(lst, f, fields); + } + return lst; +} + +static ObjectField * +new_field_setting(char *n, Type *t, struct value *v) +{ + ObjectField *of; + + of = ecalloc(1, sizeof(*of)); + of->value = v; + of->type = t; + of->name = n; + return of; +} + +static Field * +new_type_field(char *n, int optional, Type *t) +{ + Field *f; + + f = ecalloc(1, sizeof(*f)); + f->optional = optional; + f->unique = 0; + f->defval = 0; + f->type = t; + f->name = n; + return f; +} + +static Field * +new_fixed_type_value_field(char *n, Type *t, int unique, int optional, struct value *defval) +{ + Field *f; + + f = ecalloc(1, sizeof(*f)); + f->optional = optional; + f->unique = unique; + f->defval = defval; + f->type = t; + f->name = n; + return f; +} + +static Type * +parametrize_type(Type *t, IOSClass *c) +{ + Type *type; + + type = new_type(TType); + *type = *t; /* XXX Copy, or use subtype; this only works as long as we don't cleanup! */ + type->formal_parameter = c; + return type; +} + +static Type * +type_from_class_field(IOSClass *c, const char *n) +{ + Field *f; + Type *t; + + HEIM_TAILQ_FOREACH(f, c->fields, fields) { + if (strcmp(f->name, n) == 0) { + t = new_type(TType); + if (f->type) { + *t = *f->type; + } else { + Symbol *s = addsym("HEIM_ANY"); + if(s->stype != Stype && s->stype != SUndefined) + errx(1, "Do not define HEIM_ANY, only import it\n"); + s->stype = Stype; + t->symbol = s; + } + t->typeref.iosclass = c; + t->typeref.field = f; + return t; + } + } + return NULL; +} + +static void +validate_object_set(IOSObjectSet *os) +{ + IOSObject **objects; + ObjectField *of; + IOSObject *o; + Field *cf; + size_t nobjs, i; + + /* Check unique fields */ + HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) { + if (!cf->unique) + continue; + if (!cf->type) + errx(1, "Type fields of classes can't be UNIQUE (%s)", + os->iosclass->symbol->name); + sort_object_set(os, cf, &objects, &nobjs); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + if (strcmp(cf->name, of->name) != 0) + continue; + if (!of->value) + errx(1, "Value not specified for required UNIQUE field %s of object %s", + cf->name, objects[i]->symbol->name); + break; + } + if (i == 0) + continue; + if (object_cmp(&objects[i - 1], &objects[i]) == 0) + errx(1, "Duplicate values of UNIQUE field %s of objects %s and %s", + cf->name, objects[i - 1]->symbol->name, + objects[i]->symbol->name); + } + free(objects); + } + + /* Check required fields */ + HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) { + if (cf->optional || cf->defval || !cf->type) + continue; + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + int specified = 0; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, cf->name) != 0) + continue; + if (of->value) + specified = 1; + break; + } + if (!specified) + errx(1, "Value not specified for required non-UNIQUE field %s of object %s", + cf->name, o->symbol->name); + } + } +} diff --git a/third_party/heimdal/lib/asn1/canthandle.asn1 b/third_party/heimdal/lib/asn1/canthandle.asn1 new file mode 100644 index 0000000..4378428 --- /dev/null +++ b/third_party/heimdal/lib/asn1/canthandle.asn1 @@ -0,0 +1,15 @@ +-- $Id$ -- + +CANTHANDLE DEFINITIONS ::= BEGIN + +-- Currently the compiler handles SET { ... } types, but does NOT sort +-- their members as should be done in the case of conforming DER encoders. +-- The workaround is to sort the members of such types manually in their +-- definitions. See X.690, section 10.3, and X.680, section 8.6 for details. + +-- Can't handle primitives in SET OF, causing the compiler to crash +-- Workaround is to define a type that is only an integer and use that + +Baz ::= SET OF INTEGER + +END diff --git a/third_party/heimdal/lib/asn1/check-ber.c b/third_party/heimdal/lib/asn1/check-ber.c new file mode 100644 index 0000000..57450f4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-ber.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <der_locl.h> +#include <rfc2459_asn1.h> +#include <cms_asn1.h> + + +RCSID("$Id$"); + +static const unsigned char *contentdata = (unsigned char *) + "\x30\x80\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02\xa0\x80\x30" + "\x80\x02\x01\x03\x31\x0b\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05" + "\x00\x30\x80\x06\x07\x2b\x06\x01\x05\x02\x03\x01\xa0\x80\x24\x80" + "\x04\x40\x30\x3e\xa0\x3c\x30\x3a\xa0\x05\x02\x03\x0e\x03\x86\xa1" + "\x11\x18\x0f\x32\x30\x30\x38\x31\x32\x31\x33\x31\x39\x34\x35\x34" + "\x32\x5a\xa2\x06\x02\x04\xba\xbd\x97\x8a\xa3\x16\x04\x14\x41\x28" + "\x79\xa8\xd0\xe4\xb1\x0f\xb1\xfc\xa6\x0b\x4d\x2b\x85\x3d\xd9\x17" + "\x3f\xdc\x00\x00\x00\x00\x00\x00\xa0\x82\x0b\x6c\x30\x82\x05\x57" + "\x30\x82\x04\x3f\xa0\x03\x02\x01\x02\x02\x03\x47\x3d\x05\x30\x0d" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x81\x86" + "\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x1d\x30" + "\x1b\x06\x03\x55\x04\x0a\x13\x14\x41\x70\x70\x6c\x65\x20\x43\x6f" + "\x6d\x70\x75\x74\x65\x72\x2c\x20\x49\x6e\x63\x2e\x31\x2d\x30\x2b" + "\x06\x03\x55\x04\x0b\x13\x24\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d" + "\x70\x75\x74\x65\x72\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74" + "\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x31\x29\x30\x27\x06" + "\x03\x55\x04\x03\x13\x20\x41\x70\x70\x6c\x65\x20\x2e\x4d\x61\x63" + "\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74" + "\x68\x6f\x72\x69\x74\x79\x30\x1e\x17\x0d\x30\x38\x31\x30\x30\x31" + "\x30\x38\x30\x36\x33\x33\x5a\x17\x0d\x30\x39\x31\x30\x30\x32\x30" + "\x38\x30\x36\x33\x33\x5a\x30\x71\x31\x0b\x30\x09\x06\x03\x55\x04" + "\x06\x13\x02\x55\x53\x31\x13\x30\x11\x06\x03\x55\x04\x0a\x13\x0a" + "\x41\x70\x70\x6c\x65\x20\x49\x6e\x63\x2e\x31\x0f\x30\x0d\x06\x03" + "\x55\x04\x0b\x13\x06\x6d\x65\x2e\x63\x6f\x6d\x31\x15\x30\x13\x06" + "\x03\x55\x04\x03\x13\x0c\x62\x69\x74\x63\x6f\x6c\x6c\x65\x63\x74" + "\x6f\x72\x31\x25\x30\x23\x06\x03\x55\x04\x0d\x13\x1c\x4d\x6f\x62" + "\x69\x6c\x65\x4d\x65\x20\x53\x68\x61\x72\x69\x6e\x67\x20\x43\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x30\x81\xa3\x30\x0d\x06\x09" + "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x91\x00\x30" + "\x81\x8d\x02\x81\x81\x00\xe1\x15\xd8\xfa\xe9\xc2\xb7\x2e\xf0\xd9" + "\xbe\xdb\x0c\xd8\xcb\xf3\x88\x13\xd7\x22\xf8\x4d\xf4\xb6\x31\x17" + "\xe5\x92\x42\xef\x15\xe4\x5f\x12\x58\x3d\x8d\x0b\xa4\x03\x76\xe0" + "\xd0\xf2\x46\xb4\x4b\x14\x78\x23\x1c\x38\xb0\x99\xff\x36\x6f\x0e" + "\x26\xdf\x76\xd0\x01\x03\x7a\xd9\xcd\x1c\x92\xa6\x10\x5e\xed\x8a" + "\xb0\xfe\x9b\x8c\x96\xb0\x91\x9f\x97\xd0\xf4\x9c\x81\x8e\xbf\xb5" + "\x41\x24\x81\xb0\x1b\xb3\x8c\xd3\x92\x5c\xfd\x2b\x04\x61\xc3\x21" + "\x6c\xa9\xe4\xa0\xfe\xa5\x1c\x76\xfd\xda\x3b\x81\x7c\xa0\x5c\x2c" + "\xf6\x8f\x6e\x74\x52\x35\x02\x07\x01\x00\x01\x00\x01\x00\x01\xa3" + "\x82\x02\x60\x30\x82\x02\x5c\x30\x0c\x06\x03\x55\x1d\x13\x01\x01" + "\xff\x04\x02\x30\x00\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff\x04" + "\x04\x03\x02\x03\x88\x30\x28\x06\x03\x55\x1d\x25\x04\x21\x30\x1f" + "\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x02\x06\x0a\x2a\x86\x48\x86" + "\xf7\x63\x64\x03\x02\x01\x06\x07\x2b\x06\x01\x05\x02\x03\x04\x30" + "\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x11\xb3\x15\xb5\xab\x31" + "\xbb\xa5\x48\xee\xd6\x33\xd2\x86\xc3\x0b\x2a\x4c\x5e\x94\x30\x1f" + "\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x7a\x7d\x90\xb1\x30" + "\x59\x08\x92\x91\xf9\x53\xb9\x71\x1d\x35\x33\x67\x34\x8b\xd5\x30" + "\x81\xa5\x06\x08\x2b\x06\x01\x05\x05\x07\x01\x01\x04\x81\x98\x30" + "\x81\x95\x30\x27\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x01\x86\x1b" + "\x68\x74\x74\x70\x3a\x2f\x2f\x63\x65\x72\x74\x69\x6e\x66\x6f\x2e" + "\x6d\x65\x2e\x63\x6f\x6d\x2f\x6f\x63\x73\x70\x30\x44\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x30\x02\x86\x38\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x63\x61\x73\x69\x67\x6e\x65\x72\x73\x2e\x68\x74\x6d" + "\x6c\x30\x24\x06\x03\x55\x1d\x12\x86\x1d\x68\x74\x74\x70\x3a\x2f" + "\x2f\x63\x65\x72\x74\x69\x6e\x66\x6f\x2e\x6d\x65\x2e\x63\x6f\x6d" + "\x2f\x43\x41\x2e\x63\x65\x72\x30\x82\x01\x28\x06\x03\x55\x1d\x20" + "\x04\x82\x01\x1f\x30\x82\x01\x1b\x30\x82\x01\x17\x06\x09\x2a\x86" + "\x48\x86\xf7\x63\x64\x05\x02\x30\x82\x01\x08\x30\x40\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x02\x01\x16\x34\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x74\x65\x72\x6d\x73\x2e\x68\x74\x6d\x6c\x30\x81\xc3" + "\x06\x08\x2b\x06\x01\x05\x05\x07\x02\x02\x30\x81\xb6\x1a\x81\xb3" + "\x52\x65\x6c\x69\x61\x6e\x63\x65\x20\x6f\x6e\x20\x74\x68\x69\x73" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x62\x79\x20" + "\x61\x6e\x79\x20\x70\x61\x72\x74\x79\x20\x61\x73\x73\x75\x6d\x65" + "\x73\x20\x61\x63\x63\x65\x70\x74\x61\x6e\x63\x65\x20\x6f\x66\x20" + "\x74\x68\x65\x20\x74\x68\x65\x6e\x20\x61\x70\x70\x6c\x69\x63\x61" + "\x62\x6c\x65\x20\x73\x74\x61\x6e\x64\x61\x72\x64\x20\x74\x65\x72" + "\x6d\x73\x20\x61\x6e\x64\x20\x63\x6f\x6e\x64\x69\x74\x69\x6f\x6e" + "\x73\x20\x6f\x66\x20\x75\x73\x65\x2c\x20\x63\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x70\x6f\x6c\x69\x63\x79\x20\x61\x6e\x64" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x20\x70" + "\x72\x61\x63\x74\x69\x63\x65\x20\x73\x74\x61\x74\x65\x6d\x65\x6e" + "\x74\x73\x2e\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05" + "\x05\x00\x03\x82\x01\x01\x00\x39\xb1\x81\xbe\x55\xf1\xb1\xe4\x16" + "\x5d\x7c\x5b\x6a\xe8\xcf\xee\xaa\x87\x91\x81\xf2\x57\x0d\x32\x6c" + "\xc6\x47\xdc\x71\x70\xfa\x7c\x47\x84\x7f\xa5\x69\x1b\x4c\x52\x98" + "\x7f\xc8\x1f\x62\x06\x83\xae\x0a\xef\x55\x29\x35\xb3\xa0\x04\x88" + "\xa6\x45\x0a\xd0\xd7\x4e\x5c\x63\x3e\xe7\xb2\x28\x85\xd3\x01\x56" + "\x2b\x89\xb5\x60\x9a\xa5\x9d\x85\x0d\x76\x9e\xe1\x4a\x54\x8b\x6f" + "\xad\xc4\xc2\x43\x2f\x18\xaa\x18\x1a\x64\x2f\x2e\xe3\xc9\xb8\xa8" + "\xdd\xba\x53\xc4\x18\xcf\x4e\x30\xbf\x06\xa7\xdb\x12\x34\x24\x5c" + "\x71\x60\x2a\xd2\x93\xef\x54\x83\x4e\x5d\xc5\x5f\x00\x8d\x02\x85" + "\xe5\x17\x68\x46\xfa\xd4\x45\x96\x71\xf7\x93\x58\x4d\x83\x6b\x01" + "\xcb\xdb\x7d\x61\x67\x69\xbe\xf1\x4c\x4b\xe2\x3e\xf6\x4e\x62\x77" + "\x26\x86\xc4\x3b\x96\x38\x27\x0b\x02\x0d\x07\xc9\x95\x53\x6d\x03" + "\xff\x61\xfb\x67\x7f\x8a\x2e\x2f\xc5\xff\x5a\xf9\x53\xd8\xb3\xae" + "\xf1\x05\x27\x92\x79\x22\xd5\x55\x6e\xd6\xbf\xdb\x9d\xad\xbf\xbf" + "\x7d\x15\xd8\x1c\x3d\x63\x86\xf1\xf1\x78\xfe\xfb\x62\x06\x8c\xf4" + "\x0f\xa8\x91\xa8\x7c\xef\x51\x96\x09\x52\x68\xec\x09\xdd\xb9\x9a" + "\x62\x49\xac\xbe\x20\x20\x9b\x30\x82\x06\x0d\x30\x82\x04\xf5\xa0" + "\x03\x02\x01\x02\x02\x01\x0f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7" + "\x0d\x01\x01\x05\x05\x00\x30\x81\x86\x31\x0b\x30\x09\x06\x03\x55" + "\x04\x06\x13\x02\x55\x53\x31\x1d\x30\x1b\x06\x03\x55\x04\x0a\x13" + "\x14\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x2c" + "\x20\x49\x6e\x63\x2e\x31\x2d\x30\x2b\x06\x03\x55\x04\x0b\x13\x24" + "\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x20\x43" + "\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f" + "\x72\x69\x74\x79\x31\x29\x30\x27\x06\x03\x55\x04\x03\x13\x20\x41" + "\x70\x70\x6c\x65\x20\x52\x6f\x6f\x74\x20\x43\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x30" + "\x1e\x17\x0d\x30\x35\x30\x32\x31\x30\x32\x30\x33\x38\x32\x37\x5a" + "\x17\x0d\x31\x31\x31\x31\x31\x30\x32\x30\x33\x38\x32\x37\x5a\x30" + "\x81\x86\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31" + "\x1d\x30\x1b\x06\x03\x55\x04\x0a\x13\x14\x41\x70\x70\x6c\x65\x20" + "\x43\x6f\x6d\x70\x75\x74\x65\x72\x2c\x20\x49\x6e\x63\x2e\x31\x2d" + "\x30\x2b\x06\x03\x55\x04\x0b\x13\x24\x41\x70\x70\x6c\x65\x20\x43" + "\x6f\x6d\x70\x75\x74\x65\x72\x20\x43\x65\x72\x74\x69\x66\x69\x63" + "\x61\x74\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x31\x29\x30" + "\x27\x06\x03\x55\x04\x03\x13\x20\x41\x70\x70\x6c\x65\x20\x2e\x4d" + "\x61\x63\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41" + "\x75\x74\x68\x6f\x72\x69\x74\x79\x30\x82\x01\x22\x30\x0d\x06\x09" + "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00" + "\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xbb\x73\x84\xb0\x48\x36\x64" + "\xf8\x1f\xa2\x57\x89\xb6\xe2\x71\x3c\x36\x5e\x56\xeb\xdb\x96\x16" + "\x23\x1c\x81\xd0\x14\x2d\xd6\xf0\x4b\x22\x9b\x3f\xb7\x7a\x2c\xa2" + "\xf0\x69\x48\x33\xb7\x9e\xef\x68\xe7\xbc\x30\x07\x73\xbc\x61\xb0" + "\x01\x51\xef\x44\xdf\xdb\x45\x04\x96\x80\x2c\x7b\xe8\x93\x1f\x89" + "\x92\x60\x21\xcd\x34\x55\x00\x66\x31\x03\x01\x01\x44\x25\x94\x0b" + "\x42\x78\xca\x5a\x05\x1e\x77\x73\x24\x75\x6a\xc8\x45\x9c\xef\x2b" + "\x2a\x51\x29\x8f\xeb\x7e\x62\xd7\xfa\xcd\x32\xfd\x31\xe8\xcd\xde" + "\xab\x0d\xb5\xb4\x56\xc2\x68\x51\x09\x0c\x29\xe5\x38\x7b\x50\x68" + "\xbe\x00\x87\x8c\x56\xef\xd3\x1b\xa3\xc9\x6e\xa6\x74\x43\xeb\x83" + "\xd4\x63\x5f\x13\x79\x1e\xf8\x85\xbf\xbf\x73\x69\x36\xc5\x56\x12" + "\x6c\xe4\xee\xaf\x86\xab\x65\xb6\x04\xf0\x5a\x63\x2d\xa3\x31\x6c" + "\xe8\x48\x10\x65\xc0\x74\x45\x0d\x97\x58\x90\x3d\x91\x83\x14\xf2" + "\x6f\xba\xad\x2f\x6c\x41\x6e\x3c\xb7\x8f\x72\x4a\x1d\xf0\xb7\x1a" + "\xc0\xf0\x72\x0b\x3d\x9d\x7a\x8b\x4d\xb0\x33\xb7\x5f\x83\xef\x08" + "\x5b\x5f\x35\x35\x3b\x52\xdf\x30\xb1\x00\x6c\xa6\x3a\x86\xc4\xf4" + "\x7c\xe1\x79\x74\x5f\x0b\x35\xb8\xe1\x02\x03\x01\x00\x01\xa3\x82" + "\x02\x82\x30\x82\x02\x7e\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff" + "\x04\x04\x03\x02\x01\x86\x30\x0f\x06\x03\x55\x1d\x13\x01\x01\xff" + "\x04\x05\x30\x03\x01\x01\xff\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16" + "\x04\x14\x7a\x7d\x90\xb1\x30\x59\x08\x92\x91\xf9\x53\xb9\x71\x1d" + "\x35\x33\x67\x34\x8b\xd5\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30" + "\x16\x80\x14\x2b\xd0\x69\x47\x94\x76\x09\xfe\xf4\x6b\x8d\x2e\x40" + "\xa6\xf7\x47\x4d\x7f\x08\x5e\x30\x82\x01\x28\x06\x03\x55\x1d\x20" + "\x04\x82\x01\x1f\x30\x82\x01\x1b\x30\x82\x01\x17\x06\x09\x2a\x86" + "\x48\x86\xf7\x63\x64\x05\x02\x30\x82\x01\x08\x30\x40\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x02\x01\x16\x34\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x74\x65\x72\x6d\x73\x2e\x68\x74\x6d\x6c\x30\x81\xc3" + "\x06\x08\x2b\x06\x01\x05\x05\x07\x02\x02\x30\x81\xb6\x1a\x81\xb3" + "\x52\x65\x6c\x69\x61\x6e\x63\x65\x20\x6f\x6e\x20\x74\x68\x69\x73" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x62\x79\x20" + "\x61\x6e\x79\x20\x70\x61\x72\x74\x79\x20\x61\x73\x73\x75\x6d\x65" + "\x73\x20\x61\x63\x63\x65\x70\x74\x61\x6e\x63\x65\x20\x6f\x66\x20" + "\x74\x68\x65\x20\x74\x68\x65\x6e\x20\x61\x70\x70\x6c\x69\x63\x61" + "\x62\x6c\x65\x20\x73\x74\x61\x6e\x64\x61\x72\x64\x20\x74\x65\x72" + "\x6d\x73\x20\x61\x6e\x64\x20\x63\x6f\x6e\x64\x69\x74\x69\x6f\x6e" + "\x73\x20\x6f\x66\x20\x75\x73\x65\x2c\x20\x63\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x70\x6f\x6c\x69\x63\x79\x20\x61\x6e\x64" + "\x20\x63\x65\x72\x74\x69\x66\x69\x63\x61\x74\x69\x6f\x6e\x20\x70" + "\x72\x61\x63\x74\x69\x63\x65\x20\x73\x74\x61\x74\x65\x6d\x65\x6e" + "\x74\x73\x2e\x30\x43\x06\x03\x55\x1d\x1f\x04\x3c\x30\x3a\x30\x38" + "\xa0\x36\xa0\x34\x86\x32\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77" + "\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65\x72\x74\x69" + "\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69\x74\x79\x2f" + "\x72\x6f\x6f\x74\x2e\x63\x72\x6c\x30\x81\xa9\x06\x08\x2b\x06\x01" + "\x05\x05\x07\x01\x01\x04\x81\x9c\x30\x81\x99\x30\x44\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x30\x02\x86\x38\x68\x74\x74\x70\x3a\x2f\x2f" + "\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63\x65" + "\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72\x69" + "\x74\x79\x2f\x63\x61\x73\x69\x67\x6e\x65\x72\x73\x2e\x68\x74\x6d" + "\x6c\x30\x51\x06\x03\x55\x1d\x12\x86\x4a\x68\x74\x74\x70\x3a\x2f" + "\x2f\x77\x77\x77\x2e\x61\x70\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x63" + "\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x61\x75\x74\x68\x6f\x72" + "\x69\x74\x79\x2f\x41\x70\x70\x6c\x65\x43\x6f\x6d\x70\x75\x74\x65" + "\x72\x52\x6f\x6f\x74\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65" + "\x2e\x63\x65\x72\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01" + "\x05\x05\x00\x03\x82\x01\x01\x00\x16\x06\xe5\x56\x65\x44\x7d\xd0" + "\xaa\x99\x29\xe5\xc6\x97\x0b\x02\x43\x25\x88\x8c\x42\xba\xfb\xd6" + "\x5b\xb7\x20\x10\x69\x04\x4e\x91\x81\x08\xec\xf5\x23\x1f\xd2\x6d" + "\x3f\x35\xae\xdb\xff\xb8\xc9\x2b\x4b\x28\x73\xc4\x26\x03\xe1\x92" + "\x5e\xb2\x84\x0d\xa7\x13\xc6\x34\x54\xf1\x49\x1f\xa9\x47\x88\xb1" + "\x40\x9b\xd3\x61\x93\x5b\xcf\xc7\x53\xe7\x9f\x54\x7b\x30\xc6\xb8" + "\x3a\x89\x6f\x06\x09\x45\xa1\x94\x98\xbe\x8b\xea\x25\x7d\x91\x89" + "\xf9\x27\x62\xb9\x5f\x2d\xea\xa9\xe7\x96\x5c\xbe\xe5\x84\x6d\xe8" + "\x50\x27\xb4\xb1\xea\x9f\xf7\x92\x0d\x54\x86\xf0\x37\x31\x47\x0d" + "\x54\xde\x91\xe8\x78\xe8\x61\x27\x7c\xc3\xea\xd0\xfc\x21\xa1\x08" + "\xc8\xe5\x01\x0e\x15\xf5\x61\x60\xce\xff\xbd\x44\xd6\x8a\x1b\x67" + "\xf8\x1f\x82\xe2\xa6\xb3\xfc\x3a\xc7\x30\xae\x93\x89\x29\x2e\x81" + "\x43\x0c\x9b\xd5\x18\xa6\x74\x66\x7d\x1c\x79\xe6\x22\xef\xba\xf8" + "\x23\xb3\xd3\x50\x76\x20\xde\x7a\x93\x91\x40\xcd\x16\xad\x82\x6a" + "\xe6\xe7\x25\xf5\xb3\xbb\x36\x61\x38\x8f\xaf\x36\x5f\x4b\xae\xc1" + "\xc6\x89\x99\xb1\xb1\xd9\xf1\xa3\x51\x50\xa1\x00\x3d\xdd\x16\x89" + "\xcf\x35\x05\x62\xa0\x8b\x48\x0a\x31\x82\x01\x35\x30\x82\x01\x31" + "\x02\x01\x01\x30\x81\x8e\x30\x81\x86\x31\x0b\x30\x09\x06\x03\x55" + "\x04\x06\x13\x02\x55\x53\x31\x1d\x30\x1b\x06\x03\x55\x04\x0a\x13" + "\x14\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x2c" + "\x20\x49\x6e\x63\x2e\x31\x2d\x30\x2b\x06\x03\x55\x04\x0b\x13\x24" + "\x41\x70\x70\x6c\x65\x20\x43\x6f\x6d\x70\x75\x74\x65\x72\x20\x43" + "\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f" + "\x72\x69\x74\x79\x31\x29\x30\x27\x06\x03\x55\x04\x03\x13\x20\x41" + "\x70\x70\x6c\x65\x20\x2e\x4d\x61\x63\x20\x43\x65\x72\x74\x69\x66" + "\x69\x63\x61\x74\x65\x20\x41\x75\x74\x68\x6f\x72\x69\x74\x79\x02" + "\x03\x47\x3d\x05\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x30" + "\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x04\x81" + "\x80\x6d\xba\xa5\x44\x89\x98\x2d\x5e\xc4\xf6\xc0\x1e\x36\x70\x63" + "\x43\xf6\x61\x3c\x0b\x43\x32\x50\x54\x95\x1e\x51\x41\x17\xd2\x7f" + "\x47\x00\x21\x92\x61\xbf\x42\x63\xa4\xc8\x3a\x7f\x8d\x36\xea\xf1" + "\x2d\x9f\x0c\x30\xbc\xe1\x5e\x16\xea\xcc\x01\xdf\xbd\x6b\xc8\xc3" + "\xad\x12\x0e\x6a\x4d\xd5\xad\x15\x41\xcd\xde\xb9\xf9\xf5\xf2\xdc" + "\x65\xaf\x61\x28\x68\x40\x52\x59\xf8\xb8\xa6\xec\xce\xed\x5e\x16" + "\x7b\xbd\x72\x5e\x6a\x6e\x8b\x29\xb2\x97\x22\xe9\x99\xa3\xd6\xa9" + "\x0e\xb3\x5e\xd3\x18\x24\x06\x20\x78\xc8\xa7\xa8\xe7\x76\x3a\x8a" + "\x19\x00\x00\x00\x00\x00\x00"; + +static size_t contentlen = 3367; + + +static int +test_ber(void) +{ + ContentInfo ci; + size_t size; + int ret; + + ret = decode_ContentInfo(contentdata, contentlen, &ci, &size); + if (ret) + return 1; + + free_ContentInfo(&ci); + return 0; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_ber(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-common.c b/third_party/heimdal/lib/asn1/check-common.c new file mode 100644 index 0000000..8a6b5da --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-common.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 1999 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <roken.h> + +#include "asn1-common.h" +#include "check-common.h" + +struct map_page { + void *start; + size_t size; + void *data_start; + size_t data_size; + enum map_type type; +}; + +/* #undef HAVE_MMAP */ + +void * +map_alloc(enum map_type type, const void *buf, + size_t size, struct map_page **map) +{ +#ifndef HAVE_MMAP + unsigned char *p; + size_t len = size + sizeof(long) * 2; + int i; + + *map = ecalloc(1, sizeof(**map)); + + p = emalloc(len); + (*map)->type = type; + (*map)->start = p; + (*map)->size = len; + (*map)->data_start = p + sizeof(long); + for (i = sizeof(long); i > 0; i--) + p[sizeof(long) - i] = 0xff - i; + for (i = sizeof(long); i > 0; i--) + p[len - i] = 0xff - i; +#else + unsigned char *p; + int flags, ret, fd; + size_t pagesize = getpagesize(); + + *map = ecalloc(1, sizeof(**map)); + + (*map)->type = type; + +#ifdef MAP_ANON + flags = MAP_ANON; + fd = -1; +#else + flags = 0; + fd = open ("/dev/zero", O_RDONLY); + if(fd < 0) + err (1, "open /dev/zero"); +#endif + flags |= MAP_PRIVATE; + + (*map)->size = size + pagesize - (size % pagesize) + pagesize * 2; + + p = (unsigned char *)mmap(0, (*map)->size, PROT_READ | PROT_WRITE, + flags, fd, 0); + if (p == (unsigned char *)MAP_FAILED) + err (1, "mmap"); + + (*map)->start = p; + + ret = mprotect (p, pagesize, 0); + if (ret < 0) + err (1, "mprotect"); + + ret = mprotect (p + (*map)->size - pagesize, pagesize, 0); + if (ret < 0) + err (1, "mprotect"); + + switch (type) { + case OVERRUN: + (*map)->data_start = p + (*map)->size - pagesize - size; + break; + case UNDERRUN: + (*map)->data_start = p + pagesize; + break; + default: + abort(); + } +#endif + (*map)->data_size = size; + if (buf) + memcpy((*map)->data_start, buf, size); + return (*map)->data_start; +} + +void +map_free(struct map_page *map, const char *test_name, const char *map_name) +{ +#ifndef HAVE_MMAP + unsigned char *p = map->start; + int i; + + for (i = sizeof(long); i > 0; i--) + if (p[sizeof(long) - i] != 0xff - i) + errx(1, "%s: %s underrun %d\n", test_name, map_name, i); + for (i = sizeof(long); i > 0; i--) + if (p[map->size - i] != 0xff - i) + errx(1, "%s: %s overrun %lu\n", test_name, map_name, + (unsigned long)map->size - i); + free(map->start); +#else + int ret; + + ret = munmap (map->start, map->size); + if (ret < 0) + err (1, "munmap"); +#endif + free(map); +} + +static void +print_bytes (unsigned const char *buf, size_t len) +{ + int i; + + for (i = 0; i < len; ++i) + printf ("%02x ", buf[i]); +} + +#ifndef MAP_FAILED +#define MAP_FAILED (-1) +#endif + +static char *current_test = "<uninit>"; +static char *current_state = "<uninit>"; + +static RETSIGTYPE +segv_handler(int sig) +{ + int fd; + char msg[] = "SIGSEGV i current test: "; + /* For compilers that insist we check write(2)'s result here */ + int e = 1; + + fd = open("/dev/stdout", O_WRONLY, 0600); + if (fd >= 0) { + + if (write(fd, msg, sizeof(msg)) == -1 || + write(fd, current_test, strlen(current_test)) == -1 || + write(fd, " ", 1) == -1 || + write(fd, current_state, strlen(current_state)) == -1 || + write(fd, "\n", 1) == -1) + e = 2; + (void) close(fd); + } + _exit(e); +} + +int +generic_test (const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *encode)(unsigned char *, size_t, void *, size_t *), + size_t (ASN1CALL *length)(void *), + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *), + void (ASN1CALL *free_data)(void *), + int (*cmp)(void *a, void *b), + int (ASN1CALL *copy)(const void *from, void *to)) +{ + unsigned char *buf, *buf2; + int i; + int failures = 0; + void *data; + struct map_page *data_map, *buf_map, *buf2_map; + +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; +#endif + + for (i = 0; i < ntests; ++i) { + int ret; + size_t sz, consumed_sz, length_sz, buf_sz; + void *to = NULL; + + current_test = tests[i].name; + + current_state = "init"; + +#ifdef HAVE_SIGACTION + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; +#ifdef SA_RESETHAND + sa.sa_flags |= SA_RESETHAND; +#endif + sa.sa_handler = segv_handler; + sigaction (SIGSEGV, &sa, &osa); +#endif + + data = map_alloc(OVERRUN, NULL, data_size, &data_map); + + buf_sz = tests[i].byte_len; + buf = map_alloc(UNDERRUN, NULL, buf_sz, &buf_map); + + current_state = "encode"; + ret = (*encode) (buf + buf_sz - 1, buf_sz, + tests[i].val, &sz); + if (ret != 0) { + printf ("encoding of %s failed %d\n", tests[i].name, ret); + ++failures; + continue; + } + if (sz != tests[i].byte_len) { + printf ("encoding of %s has wrong len (%lu != %lu)\n", + tests[i].name, + (unsigned long)sz, (unsigned long)tests[i].byte_len); + ++failures; + continue; + } + + current_state = "length"; + length_sz = (*length) (tests[i].val); + if (sz != length_sz) { + printf ("length for %s is bad (%lu != %lu)\n", + tests[i].name, (unsigned long)length_sz, (unsigned long)sz); + ++failures; + continue; + } + + current_state = "memcmp"; + if (memcmp (buf, tests[i].bytes, tests[i].byte_len) != 0) { + printf ("encoding of %s has bad bytes:\n" + "correct: ", tests[i].name); + print_bytes ((unsigned char *)tests[i].bytes, tests[i].byte_len); + printf ("\nactual: "); + print_bytes (buf, sz); + printf ("\n"); +#if 0 + rk_dumpdata("correct", tests[i].bytes, tests[i].byte_len); + rk_dumpdata("actual", buf, sz); + exit (1); +#endif + ++failures; + continue; + } + + buf2 = map_alloc(OVERRUN, buf, sz, &buf2_map); + + current_state = "decode"; + ret = (*decode) (buf2, sz, data, &consumed_sz); + if (ret != 0) { + printf ("decoding of %s failed %d\n", tests[i].name, ret); + ++failures; + continue; + } + if (sz != consumed_sz) { + printf ("different length decoding %s (%ld != %ld)\n", + tests[i].name, + (unsigned long)sz, (unsigned long)consumed_sz); + ++failures; + continue; + } + current_state = "cmp"; + if ((*cmp)(data, tests[i].val) != 0) { + printf ("%s: comparison failed\n", tests[i].name); + ++failures; + continue; + } + + current_state = "copy"; + if (copy) { + to = emalloc(data_size); + ret = (*copy)(data, to); + if (ret != 0) { + printf ("copy of %s failed %d\n", tests[i].name, ret); + ++failures; + continue; + } + + current_state = "cmp-copy"; + if ((*cmp)(data, to) != 0) { + printf ("%s: copy comparison failed\n", tests[i].name); + ++failures; + continue; + } + } + + current_state = "free"; + if (free_data) { + (*free_data)(data); + if (to) { + (*free_data)(to); + free(to); + } + } + + current_state = "free"; + map_free(buf_map, tests[i].name, "encode"); + map_free(buf2_map, tests[i].name, "decode"); + map_free(data_map, tests[i].name, "data"); + +#ifdef HAVE_SIGACTION + sigaction (SIGSEGV, &osa, NULL); +#endif + } + current_state = "done"; + return failures; +} + +/* + * check for failures + * + * a test size (byte_len) of -1 means that the test tries to trigger a + * integer overflow (and later a malloc of to little memory), just + * allocate some memory and hope that is enough for that test. + */ + +int +generic_decode_fail (const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *)) +{ + unsigned char *buf; + int i; + int failures = 0; + void *data; + struct map_page *data_map, *buf_map; + +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; +#endif + + for (i = 0; i < ntests; ++i) { + int ret; + size_t sz; + const void *bytes; + + current_test = tests[i].name; + + current_state = "init"; + +#ifdef HAVE_SIGACTION + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; +#ifdef SA_RESETHAND + sa.sa_flags |= SA_RESETHAND; +#endif + sa.sa_handler = segv_handler; + sigaction (SIGSEGV, &sa, &osa); +#endif + + data = map_alloc(OVERRUN, NULL, data_size, &data_map); + + if (tests[i].byte_len < 0xffffff && tests[i].byte_len >= 0) { + sz = tests[i].byte_len; + bytes = tests[i].bytes; + } else { + sz = 4096; + bytes = NULL; + } + + buf = map_alloc(OVERRUN, bytes, sz, &buf_map); + + if (tests[i].byte_len == -1) + memset(buf, 0, sz); + + current_state = "decode"; + ret = (*decode) (buf, tests[i].byte_len, data, &sz); + if (ret == 0) { + printf ("sucessfully decoded %s\n", tests[i].name); + ++failures; + continue; + } + + current_state = "free"; + if (buf) + map_free(buf_map, tests[i].name, "encode"); + map_free(data_map, tests[i].name, "data"); + +#ifdef HAVE_SIGACTION + sigaction (SIGSEGV, &osa, NULL); +#endif + } + current_state = "done"; + return failures; +} diff --git a/third_party/heimdal/lib/asn1/check-common.h b/third_party/heimdal/lib/asn1/check-common.h new file mode 100644 index 0000000..6ea1f81 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-common.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define IF_OPT_COMPARE(ac,bc,e) \ + if (((ac)->e == NULL && (bc)->e != NULL) || (((ac)->e != NULL && (bc)->e == NULL))) return 1; \ + if ((ac)->e) +#define COMPARE_OPT_STRING(ac,bc,e) \ + do { if (strcmp(*(ac)->e, *(bc)->e) != 0) return 1; } while(0) +#define COMPARE_OPT_OCTET_STRING(ac,bc,e) \ + do { if ((ac)->e->length != (bc)->e->length || memcmp((ac)->e->data, (bc)->e->data, (ac)->e->length) != 0) return 1; } while(0) +#define COMPARE_STRING(ac,bc,e) \ + do { if (strcmp((ac)->e, (bc)->e) != 0) return 1; } while(0) +#define COMPARE_INTEGER(ac,bc,e) \ + do { if ((ac)->e != (bc)->e) return 1; } while(0) +#define COMPARE_OPT_INTEGER(ac,bc,e) \ + do { if (*(ac)->e != *(bc)->e) return 1; } while(0) +#define COMPARE_MEM(ac,bc,e,len) \ + do { if (memcmp((ac)->e, (bc)->e,len) != 0) return 1; } while(0) +#define COMPARE_OCTET_STRING(ac,bc,e) \ + do { if ((ac)->e.length != (bc)->e.length || memcmp((ac)->e.data, (bc)->e.data, (ac)->e.length) != 0) return 1; } while(0) + +struct test_case { + void *val; + ssize_t byte_len; + const char *bytes; + char *name; +}; + +typedef int (ASN1CALL *generic_encode)(unsigned char *, size_t, void *, size_t *); +typedef size_t (ASN1CALL *generic_length)(void *); +typedef int (ASN1CALL *generic_decode)(unsigned char *, size_t, void *, size_t *); +typedef void (ASN1CALL *generic_free)(void *); +typedef int (ASN1CALL *generic_copy)(const void *, void *); + +int +generic_test (const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *encode)(unsigned char *, size_t, void *, size_t *), + size_t (ASN1CALL *length)(void *), + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *), + void (ASN1CALL *free_data)(void *), + int (*cmp)(void *a, void *b), + int (ASN1CALL *copy)(const void *a, void *b)); + +int +generic_decode_fail(const struct test_case *tests, + unsigned ntests, + size_t data_size, + int (ASN1CALL *decode)(unsigned char *, size_t, void *, size_t *)); + + +struct map_page; + +enum map_type { OVERRUN, UNDERRUN }; + +struct map_page; + +void * map_alloc(enum map_type, const void *, size_t, struct map_page **); +void map_free(struct map_page *, const char *, const char *); diff --git a/third_party/heimdal/lib/asn1/check-der.c b/third_party/heimdal/lib/asn1/check-der.c new file mode 100644 index 0000000..58c1446 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-der.c @@ -0,0 +1,1215 @@ +/* + * Copyright (c) 1999 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <err.h> +#include <roken.h> + +#include <asn1-common.h> +#include <asn1_err.h> +#include <der.h> + +#include "check-common.h" + +RCSID("$Id$"); + +static int +cmp_integer (void *a, void *b) +{ + int *ia = (int *)a; + int *ib = (int *)b; + + return *ib - *ia; +} + +static int +test_integer (void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", NULL }, + {NULL, 1, "\x7f", NULL }, + {NULL, 2, "\x00\x80", NULL }, + {NULL, 2, "\x01\x00", NULL }, + {NULL, 1, "\x80", NULL }, + {NULL, 2, "\xff\x7f", NULL }, + {NULL, 1, "\xff", NULL }, + {NULL, 2, "\xff\x01", NULL }, + {NULL, 2, "\x00\xff", NULL }, + {NULL, 2, "\xfe\x01", NULL }, + {NULL, 4, "\x7f\xff\xff\xff", NULL } + }; + + int values[] = {0, 127, 128, 256, -128, -129, -1, -255, 255, + -511, 0x7fffffff}; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "integer %d", values[i]) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(int), + (generic_encode)der_put_integer, + (generic_length) der_length_integer, + (generic_decode)der_get_integer, + (generic_free)NULL, + cmp_integer, + NULL); + + for (i = 0; i < ntests; ++i) + free (tests[i].name); + return ret; +} + +static int +test_one_int(int val) +{ + int ret, dval; + unsigned char *buf; + size_t len_len, len; + + len = _heim_len_int(val); + + buf = emalloc(len + 2); + + buf[0] = '\xff'; + buf[len + 1] = '\xff'; + memset(buf + 1, 0, len); + + ret = der_put_integer(buf + 1 + len - 1, len, &val, &len_len); + if (ret) { + printf("integer %d encode failed %d\n", val, ret); + return 1; + } + if (len != len_len) { + printf("integer %d encode fail with %d len %lu, result len %lu\n", + val, ret, (unsigned long)len, (unsigned long)len_len); + return 1; + } + + ret = der_get_integer(buf + 1, len, &dval, &len_len); + if (ret) { + printf("integer %d decode failed %d\n", val, ret); + return 1; + } + if (len != len_len) { + printf("integer %d decoded diffrent len %lu != %lu", + val, (unsigned long)len, (unsigned long)len_len); + return 1; + } + if (val != dval) { + printf("decode decoded to diffrent value %d != %d", + val, dval); + return 1; + } + + if (buf[0] != (unsigned char)'\xff') { + printf("precanary dead %d\n", val); + return 1; + } + if (buf[len + 1] != (unsigned char)'\xff') { + printf("postecanary dead %d\n", val); + return 1; + } + free(buf); + return 0; +} + +static int +test_integer_more (void) +{ + int64_t i, n1, n2, n3, n4, n5, n6; + + n2 = 0; + for (i = 0; i < (sizeof(int) * 8); i++) { + n1 = 0x01 << i; + n2 = n2 | n1; + n3 = ~n1; + n4 = ~n2; + n5 = (-1) & ~(0x3f << i); + n6 = (-1) & ~(0x7f << i); + + test_one_int(n1); + test_one_int(n2); + test_one_int(n3); + test_one_int(n4); + test_one_int(n5); + test_one_int(n6); + } + return 0; +} + +static int +cmp_unsigned (void *a, void *b) +{ + return *(unsigned int*)b - *(unsigned int*)a; +} + +static int +test_unsigned (void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", NULL }, + {NULL, 1, "\x7f", NULL }, + {NULL, 2, "\x00\x80", NULL }, + {NULL, 2, "\x01\x00", NULL }, + {NULL, 2, "\x02\x00", NULL }, + {NULL, 3, "\x00\x80\x00", NULL }, + {NULL, 5, "\x00\x80\x00\x00\x00", NULL }, + {NULL, 4, "\x7f\xff\xff\xff", NULL } + }; + + unsigned int values[] = {0, 127, 128, 256, 512, 32768, + 0x80000000, 0x7fffffff}; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "unsigned %u", values[i]) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(int), + (generic_encode)der_put_unsigned, + (generic_length)der_length_unsigned, + (generic_decode)der_get_unsigned, + (generic_free)NULL, + cmp_unsigned, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + return ret; +} + +static int +cmp_octet_string (void *a, void *b) +{ + return der_heim_octet_string_cmp(a, b); +} + +static int +test_octet_string (void) +{ + heim_octet_string s1 = {8, "\x01\x23\x45\x67\x89\xab\xcd\xef"}; + + struct test_case tests[] = { + {NULL, 8, "\x01\x23\x45\x67\x89\xab\xcd\xef", NULL } + }; + int ntests = sizeof(tests) / sizeof(*tests); + int ret; + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "a octet string") < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(heim_octet_string), + (generic_encode)der_put_octet_string, + (generic_length)der_length_octet_string, + (generic_decode)der_get_octet_string, + (generic_free)der_free_octet_string, + cmp_octet_string, + NULL); + free(tests[0].name); + return ret; +} + +static int +cmp_bmp_string (void *a, void *b) +{ + heim_bmp_string *oa = (heim_bmp_string *)a; + heim_bmp_string *ob = (heim_bmp_string *)b; + + return der_heim_bmp_string_cmp(oa, ob); +} + +static uint16_t bmp_d1[] = { 32 }; +static uint16_t bmp_d2[] = { 32, 32 }; + +static int +test_bmp_string (void) +{ + heim_bmp_string s1 = { 1, bmp_d1 }; + heim_bmp_string s2 = { 2, bmp_d2 }; + + struct test_case tests[] = { + {NULL, 2, "\x00\x20", NULL }, + {NULL, 4, "\x00\x20\x00\x20", NULL } + }; + int ntests = sizeof(tests) / sizeof(*tests); + int ret; + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "a bmp string") < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + tests[1].val = &s2; + if (asprintf (&tests[1].name, "second bmp string") < 0) + errx(1, "malloc"); + if (tests[1].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(heim_bmp_string), + (generic_encode)der_put_bmp_string, + (generic_length)der_length_bmp_string, + (generic_decode)der_get_bmp_string, + (generic_free)der_free_bmp_string, + cmp_bmp_string, + NULL); + free(tests[0].name); + free(tests[1].name); + return ret; +} + +static int +cmp_universal_string (void *a, void *b) +{ + heim_universal_string *oa = (heim_universal_string *)a; + heim_universal_string *ob = (heim_universal_string *)b; + + return der_heim_universal_string_cmp(oa, ob); +} + +static uint32_t universal_d1[] = { 32 }; +static uint32_t universal_d2[] = { 32, 32 }; + +static int +test_universal_string (void) +{ + heim_universal_string s1 = { 1, universal_d1 }; + heim_universal_string s2 = { 2, universal_d2 }; + + struct test_case tests[] = { + {NULL, 4, "\x00\x00\x00\x20", NULL }, + {NULL, 8, "\x00\x00\x00\x20\x00\x00\x00\x20", NULL } + }; + int ntests = sizeof(tests) / sizeof(*tests); + int ret; + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "a universal string") < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + tests[1].val = &s2; + if (asprintf (&tests[1].name, "second universal string") < 0) + errx(1, "malloc"); + if (tests[1].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(heim_universal_string), + (generic_encode)der_put_universal_string, + (generic_length)der_length_universal_string, + (generic_decode)der_get_universal_string, + (generic_free)der_free_universal_string, + cmp_universal_string, + NULL); + free(tests[0].name); + free(tests[1].name); + return ret; +} + +static int +cmp_general_string (void *a, void *b) +{ + char **sa = (char **)a; + char **sb = (char **)b; + + return strcmp (*sa, *sb); +} + +static int +test_general_string (void) +{ + char *s1 = "Test User 1"; + + struct test_case tests[] = { + {NULL, 11, "\x54\x65\x73\x74\x20\x55\x73\x65\x72\x20\x31", NULL } + }; + int ret, ntests = sizeof(tests) / sizeof(*tests); + + tests[0].val = &s1; + if (asprintf (&tests[0].name, "the string \"%s\"", s1) < 0) + errx(1, "malloc"); + if (tests[0].name == NULL) + errx(1, "malloc"); + + ret = generic_test (tests, ntests, sizeof(unsigned char *), + (generic_encode)der_put_general_string, + (generic_length)der_length_general_string, + (generic_decode)der_get_general_string, + (generic_free)der_free_general_string, + cmp_general_string, + NULL); + free(tests[0].name); + return ret; +} + +static int +cmp_generalized_time (void *a, void *b) +{ + time_t *ta = (time_t *)a; + time_t *tb = (time_t *)b; + + return (int)(*tb - *ta); +} + +static int +test_generalized_time (void) +{ + struct test_case tests[] = { + {NULL, 15, "19700101000000Z", NULL }, + {NULL, 15, "19851106210627Z", NULL } + }; + time_t values[] = {0, 500159187}; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "time %d", (int)values[i]) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(time_t), + (generic_encode)der_put_generalized_time, + (generic_length)der_length_generalized_time, + (generic_decode)der_get_generalized_time, + (generic_free)NULL, + cmp_generalized_time, + NULL); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + return ret; +} + +static int +test_cmp_oid (void *a, void *b) +{ + return der_heim_oid_cmp((heim_oid *)a, (heim_oid *)b); +} + +static unsigned oid_comp1[] = { 1, 1, 1 }; +static unsigned oid_comp2[] = { 1, 1 }; +static unsigned oid_comp3[] = { 6, 15, 1 }; +static unsigned oid_comp4[] = { 6, 15 }; + +static int +test_oid (void) +{ + struct test_case tests[] = { + {NULL, 2, "\x29\x01", NULL }, + {NULL, 1, "\x29", NULL }, + {NULL, 2, "\xff\x01", NULL }, + {NULL, 1, "\xff", NULL } + }; + heim_oid values[] = { + { 3, oid_comp1 }, + { 2, oid_comp2 }, + { 3, oid_comp3 }, + { 2, oid_comp4 } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "oid %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(heim_oid), + (generic_encode)der_put_oid, + (generic_length)der_length_oid, + (generic_decode)der_get_oid, + (generic_free)der_free_oid, + test_cmp_oid, + NULL); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + return ret; +} + +static int +test_cmp_bit_string (void *a, void *b) +{ + return der_heim_bit_string_cmp((heim_bit_string *)a, (heim_bit_string *)b); +} + +static int +test_bit_string (void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", NULL } + }; + heim_bit_string values[] = { + { 0, "" } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "bit_string %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(heim_bit_string), + (generic_encode)der_put_bit_string, + (generic_length)der_length_bit_string, + (generic_decode)der_get_bit_string, + (generic_free)der_free_bit_string, + test_cmp_bit_string, + NULL); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + return ret; +} + +static int +test_cmp_heim_integer (void *a, void *b) +{ + return der_heim_integer_cmp((heim_integer *)a, (heim_integer *)b); +} + +static int +test_heim_integer (void) +{ + struct test_case tests[] = { + {NULL, 1, "\xff", NULL }, + {NULL, 2, "\xff\x01", NULL }, + {NULL, 2, "\xfe\x01", NULL }, + {NULL, 2, "\xef\x01", NULL }, + {NULL, 3, "\xff\x00\xff", NULL }, + {NULL, 3, "\xff\x01\x00", NULL }, + {NULL, 1, "\x00", NULL }, + {NULL, 1, "\x01", NULL }, + {NULL, 2, "\x00\x80", NULL }, + }; + + heim_integer values[] = { + { 1, "\x01", 1 }, + { 1, "\xff", 1 }, + { 2, "\x01\xff", 1 }, + { 2, "\x10\xff", 1 }, + { 2, "\xff\x01", 1 }, + { 2, "\xff\x00", 1 }, + { 0, "", 0 }, + { 1, "\x01", 0 }, + { 1, "\x80", 0 }, + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(tests[0]); + size_t size; + heim_integer i2; + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "heim_integer %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(heim_integer), + (generic_encode)der_put_heim_integer, + (generic_length)der_length_heim_integer, + (generic_decode)der_get_heim_integer, + (generic_free)der_free_heim_integer, + test_cmp_heim_integer, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + if (ret) + return ret; + + /* test zero length integer (BER format) */ + ret = der_get_heim_integer(NULL, 0, &i2, &size); + if (ret) + errx(1, "der_get_heim_integer"); + if (i2.length != 0) + errx(1, "der_get_heim_integer wrong length"); + der_free_heim_integer(&i2); + + return 0; +} + +static int +test_cmp_boolean (void *a, void *b) +{ + return !!*(int *)a != !!*(int *)b; +} + +static int +test_boolean (void) +{ + struct test_case tests[] = { + {NULL, 1, "\xff", NULL }, + {NULL, 1, "\x00", NULL } + }; + + int values[] = { 1, 0 }; + int i, ret; + int ntests = sizeof(tests) / sizeof(tests[0]); + size_t size; + heim_integer i2; + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "heim_boolean %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(int), + (generic_encode)der_put_boolean, + (generic_length)der_length_boolean, + (generic_decode)der_get_boolean, + (generic_free)NULL, + test_cmp_boolean, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + if (ret) + return ret; + + /* test zero length integer (BER format) */ + ret = der_get_heim_integer(NULL, 0, &i2, &size); + if (ret) + errx(1, "der_get_heim_integer"); + if (i2.length != 0) + errx(1, "der_get_heim_integer wrong length"); + der_free_heim_integer(&i2); + + return 0; +} + +static int +check_fail_unsigned(void) +{ + struct test_case tests[] = { + {NULL, sizeof(unsigned) + 1, + "\x01\x01\x01\x01\x01\x01\x01\x01\x01", "data overrun" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(unsigned), + (generic_decode)der_get_unsigned); +} + +static int +check_fail_integer(void) +{ + struct test_case tests[] = { + {NULL, sizeof(int) + 1, + "\x01\x01\x01\x01\x01\x01\x01\x01\x01", "data overrun" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(int), + (generic_decode)der_get_integer); +} + +static int +check_fail_length(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"}, + {NULL, 1, "\x82", "internal length overrun" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(size_t), + (generic_decode)der_get_length); +} + +static int +check_fail_boolean(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(int), + (generic_decode)der_get_boolean); +} + +static int +check_fail_general_string(void) +{ + struct test_case tests[] = { + { NULL, 3, "A\x00i", "NUL char in string"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_general_string), + (generic_decode)der_get_general_string); +} + +static int +check_fail_bmp_string(void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", "odd (1) length bmpstring"}, + {NULL, 3, "\x00\x00\x00", "odd (3) length bmpstring"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_bmp_string), + (generic_decode)der_get_bmp_string); +} + +static int +check_fail_universal_string(void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", "x & 3 == 1 universal string"}, + {NULL, 2, "\x00\x00", "x & 3 == 2 universal string"}, + {NULL, 3, "\x00\x00\x00", "x & 3 == 3 universal string"}, + {NULL, 5, "\x00\x00\x00\x00\x00", "x & 3 == 1 universal string"}, + {NULL, 6, "\x00\x00\x00\x00\x00\x00", "x & 3 == 2 universal string"}, + {NULL, 7, "\x00\x00\x00\x00\x00\x00\x00", "x & 3 == 3 universal string"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_universal_string), + (generic_decode)der_get_universal_string); +} + +static int +check_fail_heim_integer(void) +{ +#if 0 + struct test_case tests[] = { + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_integer), + (generic_decode)der_get_heim_integer); +#else + return 0; +#endif +} + +static int +check_fail_generalized_time(void) +{ + struct test_case tests[] = { + {NULL, 1, "\x00", "no time"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(time_t), + (generic_decode)der_get_generalized_time); +} + +static int +check_fail_oid(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"}, + {NULL, 2, "\x00\x80", "last byte continuation" }, + {NULL, 11, "\x00\x81\x80\x80\x80\x80\x80\x80\x80\x80\x00", + "oid element overflow" } + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_oid), + (generic_decode)der_get_oid); +} + +static int +check_fail_bitstring(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty input data"}, + {NULL, 1, "\x08", "larger then 8 bits trailer"}, + {NULL, 1, "\x01", "to few bytes for bits"}, + {NULL, -2, "\x00", "length overrun"}, + {NULL, -1, "", "length to short"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(heim_bit_string), + (generic_decode)der_get_bit_string); +} + +static int +check_heim_integer_same(const char *p, const char *norm_p, heim_integer *i) +{ + heim_integer i2; + char *str; + int ret; + + ret = der_print_hex_heim_integer(i, &str); + if (ret) + errx(1, "der_print_hex_heim_integer: %d", ret); + + if (strcmp(str, norm_p) != 0) + errx(1, "der_print_hex_heim_integer: %s != %s", str, p); + + ret = der_parse_hex_heim_integer(str, &i2); + if (ret) + errx(1, "der_parse_hex_heim_integer: %d", ret); + + if (der_heim_integer_cmp(i, &i2) != 0) + errx(1, "der_heim_integer_cmp: p %s", p); + + der_free_heim_integer(&i2); + free(str); + + ret = der_parse_hex_heim_integer(p, &i2); + if (ret) + errx(1, "der_parse_hex_heim_integer: %d", ret); + + if (der_heim_integer_cmp(i, &i2) != 0) + errx(1, "der_heim_integer_cmp: norm"); + + der_free_heim_integer(&i2); + + return 0; +} + +static int +test_heim_int_format(void) +{ + heim_integer i = { 1, "\x10", 0 }; + heim_integer i2 = { 1, "\x10", 1 }; + heim_integer i3 = { 1, "\01", 0 }; + char *p = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF"; + heim_integer bni = { + 128, + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2" + "\x21\x68\xC2\x34\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1" + "\x29\x02\x4E\x08\x8A\x67\xCC\x74\x02\x0B\xBE\xA6" + "\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD" + "\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D" + "\xF2\x5F\x14\x37\x4F\xE1\x35\x6D\x6D\x51\xC2\x45" + "\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\xF4\x4C\x42\xE9" + "\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED" + "\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11" + "\x7C\x4B\x1F\xE6\x49\x28\x66\x51\xEC\xE6\x53\x81" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", + 0 + }; + heim_integer f; + int ret = 0; + + ret += check_heim_integer_same(p, p, &bni); + ret += check_heim_integer_same("10", "10", &i); + ret += check_heim_integer_same("00000010", "10", &i); + ret += check_heim_integer_same("-10", "-10", &i2); + ret += check_heim_integer_same("-00000010", "-10", &i2); + ret += check_heim_integer_same("01", "01", &i3); + ret += check_heim_integer_same("1", "01", &i3); + + { + int r; + r = der_parse_hex_heim_integer("-", &f); + if (r == 0) { + der_free_heim_integer(&f); + ret++; + } + /* used to cause UMR */ + r = der_parse_hex_heim_integer("00", &f); + if (r == 0) + der_free_heim_integer(&f); + else + ret++; + } + + return ret; +} + +static int +test_heim_oid_format_same(const char *str, const heim_oid *oid) +{ + int ret; + char *p; + heim_oid o2; + + ret = der_print_heim_oid(oid, ' ', &p); + if (ret) { + printf("fail to print oid: %s\n", str); + return 1; + } + + if (strcmp(p, str) != 0) { + printf("oid %s != formated oid %s\n", str, p); + free(p); + return 1; + } + + ret = der_parse_heim_oid(p, " ", &o2); + if (ret) { + printf("failed to parse %s\n", p); + free(p); + return 1; + } + free(p); + ret = der_heim_oid_cmp(&o2, oid); + der_free_oid(&o2); + + if (ret != 0) + return 1; + return 0; +} + +static unsigned sha1_oid_tree[] = { 1, 3, 14, 3, 2, 26 }; + +static int +test_heim_oid_format(void) +{ + heim_oid sha1 = { 6, sha1_oid_tree }; + int ret = 0; + + ret += test_heim_oid_format_same("1 3 14 3 2 26", &sha1); + + return ret; +} + +static int +check_trailing_nul(void) +{ + int i, ret; + struct { + int fail; + const unsigned char *p; + size_t len; + const char *s; + size_t size; + } foo[] = { + { 1, (const unsigned char *)"foo\x00o", 5, NULL, 0 }, + { 1, (const unsigned char *)"\x00o", 2, NULL, 0 }, + { 0, (const unsigned char *)"\x00\x00\x00\x00\x00", 5, "", 5 }, + { 0, (const unsigned char *)"\x00", 1, "", 1 }, + { 0, (const unsigned char *)"", 0, "", 0 }, + { 0, (const unsigned char *)"foo\x00\x00", 5, "foo", 5 }, + { 0, (const unsigned char *)"foo\0", 4, "foo", 4 }, + { 0, (const unsigned char *)"foo", 3, "foo", 3 } + }; + + for (i = 0; i < sizeof(foo)/sizeof(foo[0]); i++) { + char *s; + size_t size; + ret = der_get_general_string(foo[i].p, foo[i].len, &s, &size); + if (foo[i].fail) { + if (ret == 0) + errx(1, "check %d NULL didn't fail", i); + continue; + } + if (ret) + errx(1, "NULL check %d der_get_general_string failed", i); + if (foo[i].size != size) + errx(1, "NUL check i = %d size failed", i); + if (strcmp(foo[i].s, s) != 0) + errx(1, "NUL check i = %d content failed", i); + free(s); + } + return 0; +} + +static int +test_misc_cmp(void) +{ + int ret; + + /* diffrent lengths are diffrent */ + { + const heim_octet_string os1 = { 1, "a" } , os2 = { 0, NULL }; + ret = der_heim_octet_string_cmp(&os1, &os2); + if (ret == 0) + return 1; + } + /* diffrent data are diffrent */ + { + const heim_octet_string os1 = { 1, "a" } , os2 = { 1, "b" }; + ret = der_heim_octet_string_cmp(&os1, &os2); + if (ret == 0) + return 1; + } + /* diffrent lengths are diffrent */ + { + const heim_bit_string bs1 = { 8, "a" } , bs2 = { 7, "a" }; + ret = der_heim_bit_string_cmp(&bs1, &bs2); + if (ret == 0) + return 1; + } + /* diffrent data are diffrent */ + { + const heim_bit_string bs1 = { 7, "\x0f" } , bs2 = { 7, "\x02" }; + ret = der_heim_bit_string_cmp(&bs1, &bs2); + if (ret == 0) + return 1; + } + /* diffrent lengths are diffrent */ + { + uint16_t data = 1; + heim_bmp_string bs1 = { 1, NULL } , bs2 = { 0, NULL }; + bs1.data = &data; + ret = der_heim_bmp_string_cmp(&bs1, &bs2); + if (ret == 0) + return 1; + } + /* diffrent lengths are diffrent */ + { + uint32_t data; + heim_universal_string us1 = { 1, NULL } , us2 = { 0, NULL }; + us1.data = &data; + ret = der_heim_universal_string_cmp(&us1, &us2); + if (ret == 0) + return 1; + } + /* same */ + { + uint32_t data = (uint32_t)'a'; + heim_universal_string us1 = { 1, NULL } , us2 = { 1, NULL }; + us1.data = &data; + us2.data = &data; + ret = der_heim_universal_string_cmp(&us1, &us2); + if (ret != 0) + return 1; + } + + return 0; +} + +static int +corner_generalized_time(void) +{ + const char *str = "760520140000Z"; + size_t size; + time_t t; + int ret; + + ret = der_get_generalized_time((const unsigned char*)str, strlen(str), + &t, &size); + if (ret) + return 1; + return 0; +} + +static int +corner_tag(void) +{ + struct { + int ok; + const char *ptr; + size_t len; + } tests[] = { + { 1, "\x00", 1 }, + { 0, "\xff", 1 }, + { 0, "\xff\xff\xff\xff\xff\xff\xff\xff", 8 } + }; + int i, ret; + Der_class cl; + Der_type ty; + unsigned int tag; + size_t size; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + ret = der_get_tag((const unsigned char*)tests[i].ptr, + tests[i].len, &cl, &ty, &tag, &size); + if (ret) { + if (tests[i].ok) + errx(1, "failed while shouldn't"); + } else { + if (!tests[i].ok) + errx(1, "passed while shouldn't"); + } + } + return 0; +} + +struct randomcheck { + asn1_type_decode decoder; + asn1_type_release release; + size_t typesize; + size_t inputsize; +} randomcheck[] = { +#define el(name, type, maxlen) { \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type), \ + maxlen \ + } + el(integer, int, 6), + el(heim_integer, heim_integer, 12), + el(integer, int, 6), + el(unsigned, unsigned, 6), + el(general_string, heim_general_string, 12), + el(octet_string, heim_octet_string, 12), + { (asn1_type_decode)der_get_octet_string_ber, + (asn1_type_release)der_free_octet_string, + sizeof(heim_octet_string), 20 }, + el(generalized_time, time_t, 20), + el(utctime, time_t, 20), + el(bit_string, heim_bit_string, 10), + el(oid, heim_oid, 10), + { NULL, NULL, 0, 0 } +#undef el +}; + +static void +asn1rand(uint8_t *randbytes, size_t len) +{ + while (len) { + *randbytes++ = rk_random(); + len--; + } +} + +static int +check_random(void) +{ + struct randomcheck *r = randomcheck; + uint8_t *input; + void *type; + size_t size, insize; + int ret; + + while (r->decoder) { + type = emalloc(r->typesize); + memset(type, 0, r->typesize); + + input = emalloc(r->inputsize); + + /* try all zero first */ + memset(input, 0, r->inputsize); + + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* try all one first */ + memset(input, 0xff, r->inputsize); + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* try 0x41 too */ + memset(input, 0x41, r->inputsize); + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* random */ + asn1rand(input, r->inputsize); + ret = r->decoder(input, r->inputsize, type, &size); + if (!ret) + r->release(type); + + /* let make buffer smaller */ + insize = r->inputsize; + do { + insize--; + asn1rand(input, insize); + + ret = r->decoder(input, insize, type, &size); + if (!ret) + r->release(type); + } while(insize > 0); + + free(type); + + r++; + } + return 0; +} + + + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_integer (); + ret += test_integer_more(); + ret += test_unsigned (); + ret += test_octet_string (); + ret += test_bmp_string (); + ret += test_universal_string (); + ret += test_general_string (); + ret += test_generalized_time (); + ret += test_oid (); + ret += test_bit_string(); + ret += test_heim_integer(); + ret += test_boolean(); + + ret += check_fail_unsigned(); + ret += check_fail_integer(); + ret += check_fail_length(); + ret += check_fail_boolean(); + ret += check_fail_general_string(); + ret += check_fail_bmp_string(); + ret += check_fail_universal_string(); + ret += check_fail_heim_integer(); + ret += check_fail_generalized_time(); + ret += check_fail_oid(); + ret += check_fail_bitstring(); + ret += test_heim_int_format(); + ret += test_heim_oid_format(); + ret += check_trailing_nul(); + ret += test_misc_cmp(); + ret += corner_generalized_time(); + ret += corner_tag(); + ret += check_random(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-gen.c b/third_party/heimdal/lib/asn1/check-gen.c new file mode 100644 index 0000000..4941c74 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-gen.c @@ -0,0 +1,2758 @@ +/* + * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <roken.h> + +#include <asn1-common.h> +#include <asn1_err.h> +#include <der.h> +#include <krb5_asn1.h> +#include <heim_asn1.h> +#include <rfc2459_asn1.h> +#include <x690sample_asn1.h> +#include <test_asn1.h> +#include <cms_asn1.h> + +#include "check-common.h" + +static int my_copy_vers_called; +static int my_free_vers_called; + +#include <limits.h> +#if UINT_MAX == 0xffffffff +// 32 bit +#define DISABLE_TEST_64 +#endif + +int +my_copy_vers(const my_vers *from, my_vers *to) +{ + my_copy_vers_called++; + *to = *from; + return 0; +} + +void +my_free_vers(my_vers *v) +{ + my_free_vers_called++; + v->v = -1; +} + +static char *lha_principal[] = { "lha" }; +static char *lharoot_princ[] = { "lha", "root" }; +static char *datan_princ[] = { "host", "nutcracker.e.kth.se" }; +static char *nada_tgt_principal[] = { "krbtgt", "NADA.KTH.SE" }; + +static int +cmp_principal (void *a, void *b) +{ + Principal *pa = a; + Principal *pb = b; + int i; + + COMPARE_STRING(pa,pb,realm); + COMPARE_INTEGER(pa,pb,name.name_type); + COMPARE_INTEGER(pa,pb,name.name_string.len); + + for (i = 0; i < pa->name.name_string.len; i++) + COMPARE_STRING(pa,pb,name.name_string.val[i]); + + return 0; +} + +static int +test_principal (void) +{ + + struct test_case tests[] = { + { NULL, 29, + "\x30\x1b\xa0\x10\x30\x0e\xa0\x03\x02\x01\x01\xa1\x07\x30\x05\x1b" + "\x03\x6c\x68\x61\xa1\x07\x1b\x05\x53\x55\x2e\x53\x45", + NULL + }, + { NULL, 35, + "\x30\x21\xa0\x16\x30\x14\xa0\x03\x02\x01\x01\xa1\x0d\x30\x0b\x1b" + "\x03\x6c\x68\x61\x1b\x04\x72\x6f\x6f\x74\xa1\x07\x1b\x05\x53\x55" + "\x2e\x53\x45", + NULL + }, + { NULL, 54, + "\x30\x34\xa0\x26\x30\x24\xa0\x03\x02\x01\x03\xa1\x1d\x30\x1b\x1b" + "\x04\x68\x6f\x73\x74\x1b\x13\x6e\x75\x74\x63\x72\x61\x63\x6b\x65" + "\x72\x2e\x65\x2e\x6b\x74\x68\x2e\x73\x65\xa1\x0a\x1b\x08\x45\x2e" + "\x4b\x54\x48\x2e\x53\x45", + NULL + } + }; + + + Principal values[] = { + { { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, "SU.SE", NULL }, + { { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, "SU.SE", NULL }, + { { KRB5_NT_SRV_HST, { 2, datan_princ } }, "E.KTH.SE", NULL } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "Principal %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(Principal), + (generic_encode)encode_Principal, + (generic_length)length_Principal, + (generic_decode)decode_Principal, + (generic_free)free_Principal, + cmp_principal, + NULL); + for (i = 0; i < ntests; ++i) + free (tests[i].name); + + return ret; +} + +static int +cmp_authenticator (void *a, void *b) +{ + Authenticator *aa = a; + Authenticator *ab = b; + int i; + + COMPARE_INTEGER(aa,ab,authenticator_vno); + COMPARE_STRING(aa,ab,crealm); + + COMPARE_INTEGER(aa,ab,cname.name_type); + COMPARE_INTEGER(aa,ab,cname.name_string.len); + + for (i = 0; i < aa->cname.name_string.len; i++) + COMPARE_STRING(aa,ab,cname.name_string.val[i]); + + return 0; +} + +static int +test_authenticator (void) +{ + struct test_case tests[] = { + { NULL, 63, + "\x62\x3d\x30\x3b\xa0\x03\x02\x01\x05\xa1\x0a\x1b\x08" + "\x45\x2e\x4b\x54\x48\x2e\x53\x45\xa2\x10\x30\x0e\xa0" + "\x03\x02\x01\x01\xa1\x07\x30\x05\x1b\x03\x6c\x68\x61" + "\xa4\x03\x02\x01\x0a\xa5\x11\x18\x0f\x31\x39\x37\x30" + "\x30\x31\x30\x31\x30\x30\x30\x31\x33\x39\x5a", + NULL + }, + { NULL, 67, + "\x62\x41\x30\x3f\xa0\x03\x02\x01\x05\xa1\x07\x1b\x05" + "\x53\x55\x2e\x53\x45\xa2\x16\x30\x14\xa0\x03\x02\x01" + "\x01\xa1\x0d\x30\x0b\x1b\x03\x6c\x68\x61\x1b\x04\x72" + "\x6f\x6f\x74\xa4\x04\x02\x02\x01\x24\xa5\x11\x18\x0f" + "\x31\x39\x37\x30\x30\x31\x30\x31\x30\x30\x31\x36\x33" + "\x39\x5a", + NULL + } + }; + + Authenticator values[] = { + { 5, "E.KTH.SE", { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, + NULL, 10, 99, NULL, NULL, NULL }, + { 5, "SU.SE", { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, + NULL, 292, 999, NULL, NULL, NULL } + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "Authenticator %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(Authenticator), + (generic_encode)encode_Authenticator, + (generic_length)length_Authenticator, + (generic_decode)decode_Authenticator, + (generic_free)free_Authenticator, + cmp_authenticator, + (generic_copy)copy_Authenticator); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + + return ret; +} + +static int +cmp_KRB_ERROR (void *a, void *b) +{ + KRB_ERROR *aa = a; + KRB_ERROR *ab = b; + int i; + + COMPARE_INTEGER(aa,ab,pvno); + COMPARE_INTEGER(aa,ab,msg_type); + + IF_OPT_COMPARE(aa,ab,ctime) { + COMPARE_INTEGER(aa,ab,ctime); + } + IF_OPT_COMPARE(aa,ab,cusec) { + COMPARE_INTEGER(aa,ab,cusec); + } + COMPARE_INTEGER(aa,ab,stime); + COMPARE_INTEGER(aa,ab,susec); + COMPARE_INTEGER(aa,ab,error_code); + + IF_OPT_COMPARE(aa,ab,crealm) { + COMPARE_OPT_STRING(aa,ab,crealm); + } +#if 0 + IF_OPT_COMPARE(aa,ab,cname) { + COMPARE_OPT_STRING(aa,ab,cname); + } +#endif + COMPARE_STRING(aa,ab,realm); + + COMPARE_INTEGER(aa,ab,sname.name_string.len); + for (i = 0; i < aa->sname.name_string.len; i++) + COMPARE_STRING(aa,ab,sname.name_string.val[i]); + + IF_OPT_COMPARE(aa,ab,e_text) { + COMPARE_OPT_STRING(aa,ab,e_text); + } + IF_OPT_COMPARE(aa,ab,e_data) { + /* COMPARE_OPT_OCTET_STRING(aa,ab,e_data); */ + } + + return 0; +} + +static int +test_krb_error (void) +{ + struct test_case tests[] = { + { NULL, 127, + "\x7e\x7d\x30\x7b\xa0\x03\x02\x01\x05\xa1\x03\x02\x01\x1e\xa4\x11" + "\x18\x0f\x32\x30\x30\x33\x31\x31\x32\x34\x30\x30\x31\x31\x31\x39" + "\x5a\xa5\x05\x02\x03\x04\xed\xa5\xa6\x03\x02\x01\x1f\xa7\x0d\x1b" + "\x0b\x4e\x41\x44\x41\x2e\x4b\x54\x48\x2e\x53\x45\xa8\x10\x30\x0e" + "\xa0\x03\x02\x01\x01\xa1\x07\x30\x05\x1b\x03\x6c\x68\x61\xa9\x0d" + "\x1b\x0b\x4e\x41\x44\x41\x2e\x4b\x54\x48\x2e\x53\x45\xaa\x20\x30" + "\x1e\xa0\x03\x02\x01\x01\xa1\x17\x30\x15\x1b\x06\x6b\x72\x62\x74" + "\x67\x74\x1b\x0b\x4e\x41\x44\x41\x2e\x4b\x54\x48\x2e\x53\x45", + "KRB-ERROR Test 1" + } + }; + int ntests = sizeof(tests) / sizeof(*tests); + KRB_ERROR e1; + PrincipalName lhaprincipalname = { 1, { 1, lha_principal } }; + PrincipalName tgtprincipalname = { 1, { 2, nada_tgt_principal } }; + char *realm = "NADA.KTH.SE"; + + e1.pvno = 5; + e1.msg_type = 30; + e1.ctime = NULL; + e1.cusec = NULL; + e1.stime = 1069632679; + e1.susec = 322981; + e1.error_code = 31; + e1.crealm = &realm; + e1.cname = &lhaprincipalname; + e1.realm = "NADA.KTH.SE"; + e1.sname = tgtprincipalname; + e1.e_text = NULL; + e1.e_data = NULL; + + tests[0].val = &e1; + + return generic_test (tests, ntests, sizeof(KRB_ERROR), + (generic_encode)encode_KRB_ERROR, + (generic_length)length_KRB_ERROR, + (generic_decode)decode_KRB_ERROR, + (generic_free)free_KRB_ERROR, + cmp_KRB_ERROR, + (generic_copy)copy_KRB_ERROR); +} + +static int +cmp_Name (void *a, void *b) +{ + Name *aa = a; + Name *ab = b; + + COMPARE_INTEGER(aa,ab,element); + + return 0; +} + +static int +test_Name (void) +{ + struct test_case tests[] = { + { NULL, 35, + "\x30\x21\x31\x1f\x30\x0b\x06\x03\x55\x04\x03\x13\x04\x4c\x6f\x76" + "\x65\x30\x10\x06\x03\x55\x04\x07\x13\x09\x53\x54\x4f\x43\x4b\x48" + "\x4f\x4c\x4d", + "Name CN=Love+L=STOCKHOLM" + }, + { NULL, 35, + "\x30\x21\x31\x1f\x30\x0b\x06\x03\x55\x04\x03\x13\x04\x4c\x6f\x76" + "\x65\x30\x10\x06\x03\x55\x04\x07\x13\x09\x53\x54\x4f\x43\x4b\x48" + "\x4f\x4c\x4d", + "Name L=STOCKHOLM+CN=Love" + } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + Name n1, n2; + RelativeDistinguishedName rdn1[1]; + RelativeDistinguishedName rdn2[1]; + AttributeTypeAndValue atv1[2]; + AttributeTypeAndValue atv2[2]; + unsigned cmp_CN[] = { 2, 5, 4, 3 }; + unsigned cmp_L[] = { 2, 5, 4, 7 }; + + /* n1 */ + n1.element = choice_Name_rdnSequence; + n1.u.rdnSequence.val = rdn1; + n1.u.rdnSequence.len = sizeof(rdn1)/sizeof(rdn1[0]); + rdn1[0].val = atv1; + rdn1[0].len = sizeof(atv1)/sizeof(atv1[0]); + + atv1[0].type.length = sizeof(cmp_CN)/sizeof(cmp_CN[0]); + atv1[0].type.components = cmp_CN; + atv1[0].value.element = choice_DirectoryString_printableString; + atv1[0].value.u.printableString.data = "Love"; + atv1[0].value.u.printableString.length = 4; + + atv1[1].type.length = sizeof(cmp_L)/sizeof(cmp_L[0]); + atv1[1].type.components = cmp_L; + atv1[1].value.element = choice_DirectoryString_printableString; + atv1[1].value.u.printableString.data = "STOCKHOLM"; + atv1[1].value.u.printableString.length = 9; + + /* n2 */ + n2.element = choice_Name_rdnSequence; + n2.u.rdnSequence.val = rdn2; + n2.u.rdnSequence.len = sizeof(rdn2)/sizeof(rdn2[0]); + rdn2[0].val = atv2; + rdn2[0].len = sizeof(atv2)/sizeof(atv2[0]); + + atv2[0].type.length = sizeof(cmp_L)/sizeof(cmp_L[0]); + atv2[0].type.components = cmp_L; + atv2[0].value.element = choice_DirectoryString_printableString; + atv2[0].value.u.printableString.data = "STOCKHOLM"; + atv2[0].value.u.printableString.length = 9; + + atv2[1].type.length = sizeof(cmp_CN)/sizeof(cmp_CN[0]); + atv2[1].type.components = cmp_CN; + atv2[1].value.element = choice_DirectoryString_printableString; + atv2[1].value.u.printableString.data = "Love"; + atv2[1].value.u.printableString.length = 4; + + /* */ + tests[0].val = &n1; + tests[1].val = &n2; + + return generic_test (tests, ntests, sizeof(Name), + (generic_encode)encode_Name, + (generic_length)length_Name, + (generic_decode)decode_Name, + (generic_free)free_Name, + cmp_Name, + (generic_copy)copy_Name); +} + +static int +cmp_KeyUsage (void *a, void *b) +{ + KeyUsage *aa = a; + KeyUsage *ab = b; + + return KeyUsage2int(*aa) != KeyUsage2int(*ab); +} + +static int +test_bit_string (void) +{ + struct test_case tests[] = { + { NULL, 4, + "\x03\x02\x07\x80", + "bitstring 1" + }, + { NULL, 4, + "\x03\x02\x05\xa0", + "bitstring 2" + }, + { NULL, 5, + "\x03\x03\x07\x00\x80", + "bitstring 3" + }, + { NULL, 3, + "\x03\x01\x00", + "bitstring 4" + } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + KeyUsage ku1, ku2, ku3, ku4; + + memset(&ku1, 0, sizeof(ku1)); + ku1.digitalSignature = 1; + tests[0].val = &ku1; + + memset(&ku2, 0, sizeof(ku2)); + ku2.digitalSignature = 1; + ku2.keyEncipherment = 1; + tests[1].val = &ku2; + + memset(&ku3, 0, sizeof(ku3)); + ku3.decipherOnly = 1; + tests[2].val = &ku3; + + memset(&ku4, 0, sizeof(ku4)); + tests[3].val = &ku4; + + + return generic_test (tests, ntests, sizeof(KeyUsage), + (generic_encode)encode_KeyUsage, + (generic_length)length_KeyUsage, + (generic_decode)decode_KeyUsage, + (generic_free)free_KeyUsage, + cmp_KeyUsage, + (generic_copy)copy_KeyUsage); +} + +static int +cmp_TicketFlags (void *a, void *b) +{ + TicketFlags *aa = a; + TicketFlags *ab = b; + + return TicketFlags2int(*aa) != TicketFlags2int(*ab); +} + +static int +test_bit_string_rfc1510 (void) +{ + struct test_case tests[] = { + { NULL, 7, + "\x03\x05\x00\x80\x00\x00\x00", + "TF bitstring 1" + }, + { NULL, 7, + "\x03\x05\x00\x40\x20\x00\x00", + "TF bitstring 2" + }, + { NULL, 7, + "\x03\x05\x00\x00\x20\x00\x00", + "TF bitstring 3" + }, + { NULL, 7, + "\x03\x05\x00\x00\x00\x00\x00", + "TF bitstring 4" + } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + TicketFlags tf1, tf2, tf3, tf4; + + memset(&tf1, 0, sizeof(tf1)); + tf1.reserved = 1; + tests[0].val = &tf1; + + memset(&tf2, 0, sizeof(tf2)); + tf2.forwardable = 1; + tf2.pre_authent = 1; + tests[1].val = &tf2; + + memset(&tf3, 0, sizeof(tf3)); + tf3.pre_authent = 1; + tests[2].val = &tf3; + + memset(&tf4, 0, sizeof(tf4)); + tests[3].val = &tf4; + + + return generic_test (tests, ntests, sizeof(TicketFlags), + (generic_encode)encode_TicketFlags, + (generic_length)length_TicketFlags, + (generic_decode)decode_TicketFlags, + (generic_free)free_TicketFlags, + cmp_TicketFlags, + (generic_copy)copy_TicketFlags); +} + +static int +cmp_KerberosTime (void *a, void *b) +{ + KerberosTime *aa = a; + KerberosTime *ab = b; + + return *aa != *ab; +} + +static int +test_time (void) +{ + struct test_case tests[] = { + { NULL, 17, + "\x18\x0f\x31\x39\x37\x30\x30\x31\x30\x31\x30\x31\x31\x38\x33\x31" + "\x5a", + "time 1" }, + { NULL, 17, + "\x18\x0f\x32\x30\x30\x39\x30\x35\x32\x34\x30\x32\x30\x32\x34\x30" + "\x5a", + "time 2" } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + KerberosTime times[] = { + 4711, + 1243130560 + }; + + tests[0].val = ×[0]; + tests[1].val = ×[1]; + + return generic_test (tests, ntests, sizeof(KerberosTime), + (generic_encode)encode_KerberosTime, + (generic_length)length_KerberosTime, + (generic_decode)decode_KerberosTime, + (generic_free)free_KerberosTime, + cmp_KerberosTime, + (generic_copy)copy_KerberosTime); +} + +struct { + const char *cert; + size_t len; +} certs[] = { + { + "\x30\x82\x02\x6c\x30\x82\x01\xd5\xa0\x03\x02\x01\x02\x02\x09\x00" + "\x99\x32\xde\x61\x0e\x40\x19\x8a\x30\x0d\x06\x09\x2a\x86\x48\x86" + "\xf7\x0d\x01\x01\x05\x05\x00\x30\x2a\x31\x1b\x30\x19\x06\x03\x55" + "\x04\x03\x0c\x12\x68\x78\x35\x30\x39\x20\x54\x65\x73\x74\x20\x52" + "\x6f\x6f\x74\x20\x43\x41\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13" + "\x02\x53\x45\x30\x1e\x17\x0d\x30\x39\x30\x34\x32\x36\x32\x30\x32" + "\x39\x34\x30\x5a\x17\x0d\x31\x39\x30\x34\x32\x34\x32\x30\x32\x39" + "\x34\x30\x5a\x30\x2a\x31\x1b\x30\x19\x06\x03\x55\x04\x03\x0c\x12" + "\x68\x78\x35\x30\x39\x20\x54\x65\x73\x74\x20\x52\x6f\x6f\x74\x20" + "\x43\x41\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x30" + "\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05" + "\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xb9\xd3\x1b\x67" + "\x1c\xf7\x5e\x26\x81\x3b\x82\xff\x03\xa4\x43\xb5\xb2\x63\x0b\x89" + "\x58\x43\xfe\x3d\xe0\x38\x7d\x93\x74\xbb\xad\x21\xa4\x29\xd9\x34" + "\x79\xf3\x1c\x8c\x5a\xd6\xb0\xd7\x19\xea\xcc\xaf\xe0\xa8\x40\x02" + "\x1d\x91\xf1\xac\x36\xb0\xfb\x08\xbd\xcc\x9a\xe1\xb7\x6e\xee\x0a" + "\x69\xbf\x6d\x2b\xee\x20\x82\x61\x06\xf2\x18\xcc\x89\x11\x64\x7e" + "\xb2\xff\x47\xd1\x3b\x52\x73\xeb\x5a\xc0\x03\xa6\x4b\xc7\x40\x7e" + "\xbc\xe1\x0e\x65\x44\x3f\x40\x8b\x02\x82\x54\x04\xd9\xcc\x2c\x67" + "\x01\xb6\x16\x82\xd8\x33\x53\x17\xd7\xde\x8d\x5d\x02\x03\x01\x00" + "\x01\xa3\x81\x99\x30\x81\x96\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16" + "\x04\x14\x6e\x48\x13\xdc\xbf\x8b\x95\x4c\x13\xf3\x1f\x97\x30\xdd" + "\x27\x96\x59\x9b\x0e\x68\x30\x5a\x06\x03\x55\x1d\x23\x04\x53\x30" + "\x51\x80\x14\x6e\x48\x13\xdc\xbf\x8b\x95\x4c\x13\xf3\x1f\x97\x30" + "\xdd\x27\x96\x59\x9b\x0e\x68\xa1\x2e\xa4\x2c\x30\x2a\x31\x1b\x30" + "\x19\x06\x03\x55\x04\x03\x0c\x12\x68\x78\x35\x30\x39\x20\x54\x65" + "\x73\x74\x20\x52\x6f\x6f\x74\x20\x43\x41\x31\x0b\x30\x09\x06\x03" + "\x55\x04\x06\x13\x02\x53\x45\x82\x09\x00\x99\x32\xde\x61\x0e\x40" + "\x19\x8a\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff" + "\x30\x0b\x06\x03\x55\x1d\x0f\x04\x04\x03\x02\x01\xe6\x30\x0d\x06" + "\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00" + "\x52\x9b\xe4\x0e\xee\xc2\x5d\xb7\xf1\xba\x47\xe3\xfe\xaf\x3d\x51" + "\x10\xfd\xe8\x0d\x14\x58\x05\x36\xa7\xeb\xd8\x05\xe5\x27\x6f\x51" + "\xb8\xec\x90\xd9\x03\xe1\xbc\x9c\x93\x38\x21\x5c\xaf\x4e\x6c\x7b" + "\x6c\x65\xa9\x92\xcd\x94\xef\xa8\xae\x90\x12\x14\x78\x2d\xa3\x15" + "\xaa\x42\xf1\xd9\x44\x64\x2c\x3c\xc0\xbd\x3a\x48\xd8\x80\x45\x8b" + "\xd1\x79\x82\xe0\x0f\xdf\x08\x3c\x60\x21\x6f\x31\x47\x98\xae\x2f" + "\xcb\xb1\xa1\xb9\xc1\xa3\x71\x5e\x4a\xc2\x67\xdf\x66\x0a\x51\xb5" + "\xad\x60\x05\xdb\x02\xd4\x1a\xd2\xb9\x4e\x01\x08\x2b\xc3\x57\xaf", + 624 }, + { + "\x30\x82\x02\x54\x30\x82\x01\xbd\xa0\x03\x02\x01\x02\x02\x01\x08" + "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30" + "\x2a\x31\x1b\x30\x19\x06\x03\x55\x04\x03\x0c\x12\x68\x78\x35\x30" + "\x39\x20\x54\x65\x73\x74\x20\x52\x6f\x6f\x74\x20\x43\x41\x31\x0b" + "\x30\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x30\x1e\x17\x0d\x30" + "\x39\x30\x34\x32\x36\x32\x30\x32\x39\x34\x30\x5a\x17\x0d\x31\x39" + "\x30\x34\x32\x34\x32\x30\x32\x39\x34\x30\x5a\x30\x1b\x31\x0b\x30" + "\x09\x06\x03\x55\x04\x06\x13\x02\x53\x45\x31\x0c\x30\x0a\x06\x03" + "\x55\x04\x03\x0c\x03\x6b\x64\x63\x30\x81\x9f\x30\x0d\x06\x09\x2a" + "\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81" + "\x89\x02\x81\x81\x00\xd2\x41\x7a\xf8\x4b\x55\xb2\xaf\x11\xf9\x43" + "\x9b\x43\x81\x09\x3b\x9a\x94\xcf\x00\xf4\x85\x75\x92\xd7\x2a\xa5" + "\x11\xf1\xa8\x50\x6e\xc6\x84\x74\x24\x17\xda\x84\xc8\x03\x37\xb2" + "\x20\xf3\xba\xb5\x59\x36\x21\x4d\xab\x70\xe2\xc3\x09\x93\x68\x14" + "\x12\x79\xc5\xbb\x9e\x1b\x4a\xf0\xc6\x24\x59\x25\xc3\x1c\xa8\x70" + "\x66\x5b\x3e\x41\x8e\xe3\x25\x71\x9a\x94\xa0\x5b\x46\x91\x6f\xdd" + "\x58\x14\xec\x89\xe5\x8c\x96\xc5\x38\x60\xe4\xab\xf2\x75\xee\x6e" + "\x62\xfc\xe1\xbd\x03\x47\xff\xc4\xbe\x0f\xca\x70\x73\xe3\x74\x58" + "\x3a\x2f\x04\x2d\x39\x02\x03\x01\x00\x01\xa3\x81\x98\x30\x81\x95" + "\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55" + "\x1d\x0f\x04\x04\x03\x02\x05\xe0\x30\x12\x06\x03\x55\x1d\x25\x04" + "\x0b\x30\x09\x06\x07\x2b\x06\x01\x05\x02\x03\x05\x30\x1d\x06\x03" + "\x55\x1d\x0e\x04\x16\x04\x14\x3a\xd3\x73\xff\xab\xdb\x7d\x8d\xc6" + "\x3a\xa2\x26\x3e\xae\x78\x95\x80\xc9\xe6\x31\x30\x48\x06\x03\x55" + "\x1d\x11\x04\x41\x30\x3f\xa0\x3d\x06\x06\x2b\x06\x01\x05\x02\x02" + "\xa0\x33\x30\x31\xa0\x0d\x1b\x0b\x54\x45\x53\x54\x2e\x48\x35\x4c" + "\x2e\x53\x45\xa1\x20\x30\x1e\xa0\x03\x02\x01\x01\xa1\x17\x30\x15" + "\x1b\x06\x6b\x72\x62\x74\x67\x74\x1b\x0b\x54\x45\x53\x54\x2e\x48" + "\x35\x4c\x2e\x53\x45\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01" + "\x01\x05\x05\x00\x03\x81\x81\x00\x83\xf4\x14\xa7\x6e\x59\xff\x80" + "\x64\xe7\xfa\xcf\x13\x80\x86\xe1\xed\x02\x38\xad\x96\x72\x25\xe5" + "\x06\x7a\x9a\xbc\x24\x74\xa9\x75\x55\xb2\x49\x80\x69\x45\x95\x4a" + "\x4c\x76\xa9\xe3\x4e\x49\xd3\xc2\x69\x5a\x95\x03\xeb\xba\x72\x23" + "\x9c\xfd\x3d\x8b\xc6\x07\x82\x3b\xf4\xf3\xef\x6c\x2e\x9e\x0b\xac" + "\x9e\x6c\xbb\x37\x4a\xa1\x9e\x73\xd1\xdc\x97\x61\xba\xfc\xd3\x49" + "\xa6\xc2\x4c\x55\x2e\x06\x37\x76\xb5\xef\x57\xe7\x57\x58\x8a\x71" + "\x63\xf3\xeb\xe7\x55\x68\x0d\xf6\x46\x4c\xfb\xf9\x43\xbb\x0c\x92" + "\x4f\x4e\x22\x7b\x63\xe8\x4f\x9c", + 600 + } +}; + +static int +test_cert(void) +{ + Certificate c, c2; + size_t size; + size_t i; + int ret; + + memset(&c, 0, sizeof(c)); + ret = copy_Certificate(&c, &c2); + if (ret) + return ret; + free_Certificate(&c2); + + for (i = 0; i < sizeof(certs)/sizeof(certs[0]); i++) { + + ret = decode_Certificate((unsigned char *)certs[i].cert, + certs[i].len, &c, &size); + if (ret) + return ret; + + ret = copy_Certificate(&c, &c2); + free_Certificate(&c); + if (ret) + return ret; + + free_Certificate(&c2); + } + + return 0; +} + +struct { + const char *sd; + size_t len; +} signeddata[] = { + { + "\x30\x80\x02\x01\x03\x31\x0b\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a" + "\x05\x00\x30\x80\x06\x07\x2b\x06\x01\x05\x02\x03\x03\xa0\x80\x24" + "\x80\x04\x50\x30\x4e\xa0\x2b\x30\x29\xa0\x03\x02\x01\x12\xa1\x22" + "\x04\x20\x78\xf4\x86\x31\xc6\xc2\xc9\xcb\xef\x0c\xd7\x3a\x2a\xcd" + "\x8c\x13\x34\x83\xb1\x5c\xa8\xbe\xbf\x2f\xea\xd2\xbb\xd8\x8c\x18" + "\x47\x01\xa1\x1f\x30\x1d\xa0\x03\x02\x01\x0c\xa1\x16\x04\x14\xa6" + "\x2c\x52\xb2\x80\x98\x30\x40\xbc\x5f\xb0\x77\x2d\x8a\xd7\xa1\xda" + "\x3c\xc5\x62\x00\x00\x00\x00\x00\x00\xa0\x82\x02\x09\x30\x82\x02" + "\x05\x30\x82\x01\x6e\xa0\x03\x02\x01\x02\x02\x04\x49\x75\x57\xbf" + "\x30\x0b\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x30\x3b\x31" + "\x1f\x30\x1d\x06\x03\x55\x04\x03\x0c\x16\x63\x6f\x6d\x2e\x61\x70" + "\x70\x6c\x65\x2e\x6b\x65\x72\x62\x65\x72\x6f\x73\x2e\x6b\x64\x63" + "\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x53\x79\x73\x74\x65" + "\x6d\x20\x49\x64\x65\x6e\x74\x69\x74\x79\x30\x1e\x17\x0d\x30\x39" + "\x31\x32\x30\x34\x30\x30\x32\x30\x32\x34\x5a\x17\x0d\x32\x39\x31" + "\x31\x32\x39\x30\x30\x32\x30\x32\x34\x5a\x30\x3b\x31\x1f\x30\x1d" + "\x06\x03\x55\x04\x03\x0c\x16\x63\x6f\x6d\x2e\x61\x70\x70\x6c\x65" + "\x2e\x6b\x65\x72\x62\x65\x72\x6f\x73\x2e\x6b\x64\x63\x31\x18\x30" + "\x16\x06\x03\x55\x04\x0a\x0c\x0f\x53\x79\x73\x74\x65\x6d\x20\x49" + "\x64\x65\x6e\x74\x69\x74\x79\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86" + "\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89" + "\x02\x81\x81\x00\xb2\xc5\x4b\x34\xe3\x93\x99\xbb\xaa\xd1\x70\x62" + "\x6c\x9c\xcc\xa6\xbc\x47\xc3\x23\xff\x15\xb9\x11\x27\x0a\xf8\x55" + "\x4c\xb2\x43\x34\x75\xad\x55\xbb\xb9\x8a\xd0\x25\x64\xa4\x8c\x82" + "\x74\x5d\x89\x52\xe2\x76\x75\x08\x67\xb5\x9c\x9c\x69\x86\x0c\x6d" + "\x79\xf7\xa0\xbe\x42\x8f\x90\x46\x0c\x18\xf4\x7a\x56\x17\xa4\x65" + "\x00\x3a\x5e\x3e\xbf\xbc\xf5\xe2\x2c\x26\x03\x52\xdd\xd4\x85\x3f" + "\x03\xd7\x0c\x45\x7f\xff\xdd\x1e\x70\x6c\x9f\xb0\x8c\xd0\x33\xad" + "\x92\x54\x17\x9d\x88\x89\x1a\xee\xef\xf7\x96\x3e\x68\xc3\xd1\x60" + "\x47\x86\x80\x5d\x02\x03\x01\x00\x01\xa3\x18\x30\x16\x30\x14\x06" + "\x03\x55\x1d\x25\x04\x0d\x30\x0b\x06\x09\x2a\x86\x48\x86\xf7\x63" + "\x64\x04\x04\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05" + "\x05\x00\x03\x81\x81\x00\x9b\xbb\xaa\x63\x66\xd8\x70\x84\x3e\xf6" + "\xa1\x3b\xf3\xe6\xd7\x3d\xfc\x4f\xc9\x45\xaa\x31\x43\x8d\xb5\x72" + "\xe4\x34\x95\x7b\x6e\x5f\xe5\xc8\x5e\xaf\x12\x08\x6d\xd7\x25\x76" + "\x40\xd5\xdc\x83\x7f\x2f\x74\xd1\x63\xc0\x7c\x26\x4d\x53\x10\xe7" + "\xfa\xcc\xf2\x60\x41\x63\xdf\x56\xd6\xd9\xc0\xb4\xd0\x73\x99\x54" + "\x40\xad\x90\x79\x2d\xd2\x5e\xcb\x13\x22\x2b\xd0\x76\xef\x8a\x48" + "\xfd\xb2\x6e\xca\x04\x4e\x91\x3f\xb4\x63\xad\x22\x3a\xf7\x20\x9c" + "\x4c\x0e\x47\x78\xe5\x2a\x85\x0e\x90\x7a\xce\x46\xe6\x15\x02\xb0" + "\x83\xe7\xac\xfa\x92\xf8\x31\x81\xe8\x30\x81\xe5\x02\x01\x01\x30" + "\x43\x30\x3b\x31\x1f\x30\x1d\x06\x03\x55\x04\x03\x0c\x16\x63\x6f" + "\x6d\x2e\x61\x70\x70\x6c\x65\x2e\x6b\x65\x72\x62\x65\x72\x6f\x73" + "\x2e\x6b\x64\x63\x31\x18\x30\x16\x06\x03\x55\x04\x0a\x0c\x0f\x53" + "\x79\x73\x74\x65\x6d\x20\x49\x64\x65\x6e\x74\x69\x74\x79\x02\x04" + "\x49\x75\x57\xbf\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x30" + "\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x04\x81" + "\x80\x50\x2c\x69\xe1\xd2\xc4\xd1\xcc\xdc\xe0\xe9\x8a\x6b\x6a\x97" + "\x1b\xb4\xe0\xa8\x20\xbe\x09\x6d\xe1\x55\x5f\x07\x70\x94\x2e\x14" + "\xed\x4e\xb1\x69\x75\x40\xbb\x99\x87\xed\x23\x50\x27\x5f\xaa\xc4" + "\x84\x60\x06\xfe\x45\xfd\x7e\x1b\x18\xe0\x0b\x77\x35\x2a\xb2\xf2" + "\xe0\x88\x31\xad\x82\x31\x4a\xbc\x6d\x71\x62\xe6\x4d\x33\xb4\x09" + "\x6e\x3f\x14\x12\xf2\x89\x29\x31\x84\x60\x2b\xa8\x2d\xe6\xca\x2f" + "\x03\x3d\xd4\x69\x89\xb3\x98\xfd\xac\x63\x14\xaf\x6a\x52\x2a\xac" + "\xe3\x8e\xfa\x21\x41\x8f\xcc\x04\x2d\x52\xee\x49\x54\x0d\x58\x51" + "\x77\x00\x00", + 883 + } +}; + +static int +test_SignedData(void) +{ + SignedData sd; + size_t size, i; + int ret; + + for (i = 0; i < sizeof(signeddata) / sizeof(signeddata[0]); i++) { + + ret = decode_SignedData((unsigned char *)signeddata[i].sd, + signeddata[i].len, &sd, &size); + if (ret) + return ret; + + free_SignedData(&sd); + } + + return 0; +} + + +static int +cmp_TESTLargeTag (void *a, void *b) +{ + TESTLargeTag *aa = a; + TESTLargeTag *ab = b; + + COMPARE_INTEGER(aa,ab,foo); + COMPARE_INTEGER(aa,ab,bar); + return 0; +} + +static int +test_large_tag (void) +{ + struct test_case tests[] = { + { NULL, 15, "\x30\x0d\xbf\x7f\x03\x02\x01\x01\xbf\x81\x00\x03\x02\x01\x02", "large tag 1" } + }; + + int ntests = sizeof(tests) / sizeof(*tests); + TESTLargeTag lt1; + + memset(<1, 0, sizeof(lt1)); + lt1.foo = 1; + lt1.bar = 2; + + tests[0].val = <1; + + return generic_test (tests, ntests, sizeof(TESTLargeTag), + (generic_encode)encode_TESTLargeTag, + (generic_length)length_TESTLargeTag, + (generic_decode)decode_TESTLargeTag, + (generic_free)free_TESTLargeTag, + cmp_TESTLargeTag, + (generic_copy)copy_TESTLargeTag); +} + +struct test_data { + int ok; + size_t len; + size_t expected_len; + void *data; +}; + +static int +check_tag_length(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 3, 3, "\x02\x01\x7f"}, + { 1, 4, 4, "\x02\x02\x00\x80"}, + { 1, 4, 4, "\x02\x02\x01\x00"}, + { 1, 4, 4, "\x02\x02\x02\x00"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTuint32 values[] = {0, 127, 128, 256, 512, + 0, 127, 128, 256, 512 }; + TESTuint32 u; + int i, ret, failed = 0; + void *buf; + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTuint32(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int +check_tag_length64(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 7, 7, "\x02\x05\x01\xff\xff\xff\xff"}, + { 1, 7, 7, "\x02\x05\x02\x00\x00\x00\x00"}, + { 1, 9, 9, "\x02\x07\x7f\xff\xff\xff\xff\xff\xff"}, + { 1, 10, 10, "\x02\x08\x00\x80\x00\x00\x00\x00\x00\x00"}, + { 1, 10, 10, "\x02\x08\x7f\xff\xff\xff\xff\xff\xff\xff"}, + { 1, 11, 11, "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTuint64 values[] = {0, 8589934591LL, 8589934592LL, + 36028797018963967LL, 36028797018963968LL, + 9223372036854775807LL, 18446744073709551615ULL, + 0, 127, 128, 256, 512 }; + TESTuint64 u; + int i, ret, failed = 0; + void *buf; + + if (sizeof(TESTuint64) != sizeof(uint64_t)) { + ret += 1; + printf("sizeof(TESTuint64) %d != sizeof(uint64_t) %d\n", + (int)sizeof(TESTuint64), (int)sizeof(uint64_t)); + } + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTuint64(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + printf("ret = %d\n", ret); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + printf("sz = %lu\n", (unsigned long)sz); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + printf("Expected value: %llu\nActual value: %llu\n", + (unsigned long long)values[i], (unsigned long long)u); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int +check_tag_length64s(void) +{ + struct test_data td[] = { + { 1, 3, 3, "\x02\x01\x00"}, + { 1, 7, 7, "\x02\x05\xfe\x00\x00\x00\x01"}, + { 1, 7, 7, "\x02\x05\xfe\x00\x00\x00\x00"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x01"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x00"}, + { 1, 10, 10, "\x02\x08\x80\x00\x00\x00\x00\x00\x00\x01"}, + { 1, 9, 9, "\x02\x07\x80\x00\x00\x00\x00\x00\x01"}, + { 0, 3, 0, "\x02\x02\x00"}, + { 0, 3, 0, "\x02\x7f\x7f"}, + { 0, 4, 0, "\x02\x03\x00\x80"}, + { 0, 4, 0, "\x02\x7f\x01\x00"}, + { 0, 5, 0, "\x02\xff\x7f\x02\x00"} + }; + size_t sz; + TESTint64 values[] = {0, -8589934591LL, -8589934592LL, + -36028797018963967LL, -36028797018963968LL, + -9223372036854775807LL, -36028797018963967LL, + 0, 127, 128, 256, 512 }; + TESTint64 u; + int i, ret, failed = 0; + void *buf; + + for (i = 0; i < sizeof(td)/sizeof(td[0]); i++) { + struct map_page *page; + + buf = map_alloc(OVERRUN, td[i].data, td[i].len, &page); + + ret = decode_TESTint64(buf, td[i].len, &u, &sz); + if (ret) { + if (td[i].ok) { + printf("failed with tag len test %d\n", i); + printf("ret = %d\n", ret); + failed = 1; + } + } else { + if (td[i].ok == 0) { + printf("failed with success for tag len test %d\n", i); + failed = 1; + } + if (td[i].expected_len != sz) { + printf("wrong expected size for tag test %d\n", i); + printf("sz = %lu\n", (unsigned long)sz); + failed = 1; + } + if (values[i] != u) { + printf("wrong value for tag test %d\n", i); + printf("Expected value: %lld\nActual value: %lld\n", + (long long)values[i], (long long)u); + failed = 1; + } + } + map_free(page, "test", "decode"); + } + return failed; +} + +static int +cmp_TESTChoice (void *a, void *b) +{ + return 0; +} + +static int +test_choice (void) +{ + struct test_case tests[] = { + { NULL, 5, "\xa1\x03\x02\x01\x01", "large choice 1" }, + { NULL, 5, "\xa2\x03\x02\x01\x02", "large choice 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTChoice1 c1; + TESTChoice1 c2_1; + TESTChoice2 c2_2; + + memset(&c1, 0, sizeof(c1)); + c1.element = choice_TESTChoice1_i1; + c1.u.i1 = 1; + tests[0].val = &c1; + + memset(&c2_1, 0, sizeof(c2_1)); + c2_1.element = choice_TESTChoice1_i2; + c2_1.u.i2 = 2; + tests[1].val = &c2_1; + + ret += generic_test (tests, ntests, sizeof(TESTChoice1), + (generic_encode)encode_TESTChoice1, + (generic_length)length_TESTChoice1, + (generic_decode)decode_TESTChoice1, + (generic_free)free_TESTChoice1, + cmp_TESTChoice, + (generic_copy)copy_TESTChoice1); + + memset(&c2_2, 0, sizeof(c2_2)); + c2_2.element = choice_TESTChoice2_asn1_ellipsis; + c2_2.u.asn1_ellipsis.data = "\xa2\x03\x02\x01\x02"; + c2_2.u.asn1_ellipsis.length = 5; + tests[1].val = &c2_2; + + ret += generic_test (tests, ntests, sizeof(TESTChoice2), + (generic_encode)encode_TESTChoice2, + (generic_length)length_TESTChoice2, + (generic_decode)decode_TESTChoice2, + (generic_free)free_TESTChoice2, + cmp_TESTChoice, + (generic_copy)copy_TESTChoice2); + + return ret; +} + +/* Test --decorate=TYPE:FIELD-TYPE:field-name[?] */ +static int +test_decorated(void) +{ + TESTNotDecorated tnd; + TESTDecorated td, td_copy; + size_t len, size; + void *ptr; + int ret; + + memset(&td, 0, sizeof(td)); + memset(&tnd, 0, sizeof(tnd)); + + my_copy_vers_called = 0; + my_free_vers_called = 0; + + td.version = 3; + td.version3.v = 5; + td.privthing = &td; + if ((td.version2 = malloc(sizeof(*td.version2))) == NULL) + errx(1, "out of memory"); + *td.version2 = 5; + ASN1_MALLOC_ENCODE(TESTDecorated, ptr, len, &td, &size, ret); + if (ret) { + warnx("could not encode a TESTDecorated struct"); + return 1; + } + ret = decode_TESTNotDecorated(ptr, len, &tnd, &size); + if (ret) { + warnx("could not decode a TESTDecorated struct as TESTNotDecorated"); + return 1; + } + free(ptr); + if (size != len) { + warnx("TESTDecorated encoded size mismatch"); + return 1; + } + if (td.version != tnd.version) { + warnx("TESTDecorated did not decode as a TESTNotDecorated correctly"); + return 1; + } + if (copy_TESTDecorated(&td, &td_copy)) { + warnx("copy_TESTDecorated() failed"); + return 1; + } + if (td.version != td_copy.version) { + warnx("copy_TESTDecorated() did not work correctly (1)"); + return 1; + } + if (td_copy.version2 == NULL || *td.version2 != *td_copy.version2) { + warnx("copy_TESTDecorated() did not work correctly (2)"); + return 1; + } + if (td.version3.v != td_copy.version3.v || + my_copy_vers_called != 1) { + warnx("copy_TESTDecorated() did not work correctly (3)"); + return 1; + } + if (td_copy.privthing != 0) { + warnx("copy_TESTDecorated() did not work correctly (4)"); + return 1; + } + + free_TESTDecorated(&td_copy); + free_TESTDecorated(&td); + if (td.version2) { + warnx("free_TESTDecorated() did not work correctly (1)"); + return 1; + } + if (td.version3.v != 0 || my_free_vers_called != 2) { + warnx("free_TESTDecorated() did not work correctly (2)"); + return 1; + } + if (td.privthing != 0) { + warnx("free_TESTDecorated() did not work correctly (3)"); + return 1; + } + return 0; +} + +static int +test_extensible_choice(void) +{ + PA_FX_FAST_REQUEST r, r2; + size_t len, size; + void *ptr; + int ret; + + memset(&r, 0, sizeof(r)); + + ret = copy_PA_FX_FAST_REQUEST(&r, &r2); + if (ret) + return ret; + free_PA_FX_FAST_REQUEST(&r2); + + r.element = 0; + r.u.asn1_ellipsis.data = "hello"; + r.u.asn1_ellipsis.length = sizeof("hello") - 1; + ret = copy_PA_FX_FAST_REQUEST(&r, &r2); + if (ret) + errx(1, "Out of memory"); + if (r2.element != 0) + errx(1, "Extensible CHOICE copy failure to set discriminant to 0"); + if (r2.u.asn1_ellipsis.length != r.u.asn1_ellipsis.length) + errx(1, "Extensible CHOICE copy failure to copy extension"); + if (memcmp(r.u.asn1_ellipsis.data, r2.u.asn1_ellipsis.data, + r.u.asn1_ellipsis.length) != 0) + errx(1, "Extensible CHOICE copy failure to copy extension (2)"); + free_PA_FX_FAST_REQUEST(&r2); + + ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST, ptr, len, &r, &size, ret); + if (ret || len != size) + errx(1, "Extensible CHOICE encoding failure"); + + ret = decode_PA_FX_FAST_REQUEST(ptr, len, &r2, &size); + if (ret || len != size) + errx(1, "Extensible CHOICE decoding failure"); + + if (r2.element != 0) + errx(1, "Extensible CHOICE decode failure to set discriminant to 0"); + if (r2.u.asn1_ellipsis.length != r.u.asn1_ellipsis.length) + errx(1, "Extensible CHOICE decode failure to copy extension"); + if (memcmp(r.u.asn1_ellipsis.data, r2.u.asn1_ellipsis.data, + r.u.asn1_ellipsis.length) != 0) + errx(1, "Extensible CHOICE decode failure to copy extension (2)"); + + free_PA_FX_FAST_REQUEST(&r2); + free(ptr); + return 0; +} + +static int +test_decorated_choice(void) +{ + TESTNotDecoratedChoice tndc; + TESTDecoratedChoice tdc, tdc_copy; + size_t len, size; + void *ptr; + int ret; + + memset(&tdc, 0, sizeof(tdc)); + memset(&tndc, 0, sizeof(tndc)); + + my_copy_vers_called = 0; + my_free_vers_called = 0; + + tdc.element = choice_TESTDecoratedChoice_version; + tdc.u.version = 3; + tdc.version3.v = 5; + tdc.privthing = &tdc; + if ((tdc.version2 = malloc(sizeof(*tdc.version2))) == NULL) + errx(1, "out of memory"); + *tdc.version2 = 5; + ASN1_MALLOC_ENCODE(TESTDecoratedChoice, ptr, len, &tdc, &size, ret); + if (ret) { + warnx("could not encode a TESTDecoratedChoice struct"); + return 1; + } + ret = decode_TESTNotDecoratedChoice(ptr, len, &tndc, &size); + if (ret) { + warnx("could not decode a TESTDecoratedChoice struct as TESTNotDecoratedChoice"); + return 1; + } + free(ptr); + if (size != len) { + warnx("TESTDecoratedChoice encoded size mismatch"); + return 1; + } + if ((int)tdc.element != (int)tndc.element || + tdc.u.version != tndc.u.version) { + warnx("TESTDecoratedChoice did not decode as a TESTNotDecoratedChoice correctly"); + return 1; + } + if (copy_TESTDecoratedChoice(&tdc, &tdc_copy)) { + warnx("copy_TESTDecoratedChoice() failed"); + return 1; + } + if ((int)tdc.element != (int)tdc_copy.element || + tdc.u.version != tdc_copy.u.version) { + warnx("copy_TESTDecoratedChoice() did not work correctly (1)"); + return 1; + } + if (tdc_copy.version2 == NULL || *tdc.version2 != *tdc_copy.version2) { + warnx("copy_TESTDecoratedChoice() did not work correctly (2)"); + return 1; + } + if (tdc.version3.v != tdc_copy.version3.v || + my_copy_vers_called != 1) { + warnx("copy_TESTDecoratedChoice() did not work correctly (3)"); + return 1; + } + if (tdc_copy.privthing != 0) { + warnx("copy_TESTDecoratedChoice() did not work correctly (4)"); + return 1; + } + + free_TESTDecoratedChoice(&tdc_copy); + free_TESTDecoratedChoice(&tdc); + if (tdc.version2) { + warnx("free_TESTDecoratedChoice() did not work correctly (1)"); + return 1; + } + if (tdc.version3.v != 0 || my_free_vers_called != 2) { + warnx("free_TESTDecoratedChoice() did not work correctly (2)"); + return 1; + } + if (tdc.privthing != 0) { + warnx("free_TESTDecoratedChoice() did not work correctly (3)"); + return 1; + } + return 0; +} + + +static int +cmp_TESTImplicit (void *a, void *b) +{ + TESTImplicit *aa = a; + TESTImplicit *ab = b; + + COMPARE_INTEGER(aa,ab,ti1); + COMPARE_INTEGER(aa,ab,ti2.foo); + COMPARE_INTEGER(aa,ab,ti3); + return 0; +} + +static int +cmp_TESTImplicit2 (void *a, void *b) +{ + TESTImplicit2 *aa = a; + TESTImplicit2 *ab = b; + + COMPARE_INTEGER(aa,ab,ti1); + COMPARE_INTEGER(aa,ab,ti3); + IF_OPT_COMPARE(aa,ab,ti4) { + COMPARE_INTEGER(aa,ab,ti4[0]); + } + return 0; +} + +static int +cmp_TESTImplicit3 (void *a, void *b) +{ + TESTImplicit3 *aa = a; + TESTImplicit3 *ab = b; + + COMPARE_INTEGER(aa,ab,element); + if (aa->element == choice_TESTImplicit3_ti1) { + COMPARE_INTEGER(aa,ab,u.ti1); + } else { + COMPARE_INTEGER(aa,ab,u.ti2.element); + COMPARE_INTEGER(aa,ab,u.ti2.u.i1); + } + return 0; +} + +static int +cmp_TESTImplicit4 (void *a, void *b) +{ + TESTImplicit4 *aa = a; + TESTImplicit4 *ab = b; + + COMPARE_INTEGER(aa,ab,element); + if (aa->element == choice_TESTImplicit4_ti1) { + COMPARE_INTEGER(aa,ab,u.ti1); + } else { + COMPARE_INTEGER(aa,ab,u.ti2.element); + COMPARE_INTEGER(aa,ab,u.ti2.u.i1); + } + return 0; +} + +static int +test_implicit (void) +{ + int ret = 0; + /* + * UNIV CONS Sequence = 14 bytes { + * CONTEXT PRIM tag 0 = 1 bytes [0] IMPLICIT content + * CONTEXT CONS tag 1 = 6 bytes [1] + * CONTEXT CONS tag 127 = 3 bytes [127] + * UNIV PRIM Integer = integer 2 + * CONTEXT PRIM tag 2 = 1 bytes [2] IMPLICIT content + * } + */ + struct test_case tests[] = { + { NULL, 16, + "\x30\x0e\x80\x01\x00\xa1\x06\xbf\x7f\x03\x02\x01\x02\x82\x01\x03", + "implicit 1" } + }; + /* + * UNIV CONS Sequence = 10 bytes { + * CONTEXT PRIM tag 0 = 1 bytes [0] IMPLICIT content + * CONTEXT PRIM tag 2 = 1 bytes [2] IMPLICIT content + * CONTEXT PRIM tag 51 = 1 bytes [51] IMPLICIT content + * } + */ + struct test_case tests2[] = { + { NULL, 12, + "\x30\x0a\x80\x01\x01\x82\x01\x03\x9f\x33\x01\x04", + "implicit 2" } + }; + /* + * CONTEXT CONS tag 5 = 5 bytes [5] + * CONTEXT CONS tag 1 = 3 bytes [1] + * UNIV PRIM Integer = integer 5 + */ + struct test_case tests3[] = { + { NULL, 7, + "\xa5\x05\xa1\x03\x02\x01\x05", + "implicit 3" } + }; + /* + * Notice: same as tests3[].bytes. + * + * CONTEXT CONS tag 5 = 5 bytes [5] + * CONTEXT CONS tag 1 = 3 bytes [1] + * UNIV PRIM Integer = integer 5 + */ + struct test_case tests4[] = { + { NULL, 7, + "\xa5\x05\xa1\x03\x02\x01\x05", + "implicit 4" } + }; + + TESTImplicit c0; + TESTImplicit2 c1; + TESTImplicit3 c2; + TESTImplicit4 c3; + int ti4 = 4; + + memset(&c0, 0, sizeof(c0)); + c0.ti1 = 0; + c0.ti2.foo = 2; + c0.ti3 = 3; + tests[0].val = &c0; + + memset(&c1, 0, sizeof(c1)); + c1.ti1 = 1; + c1.ti3 = 3; + c1.ti4 = &ti4; + tests2[0].val = &c1; + + memset(&c2, 0, sizeof(c2)); + c2.element = choice_TESTImplicit3_ti2; + c2.u.ti2.element = choice_TESTImplicit3_ti2_i1; + c2.u.ti2.u.i1 = 5; + tests3[0].val = &c2; + + memset(&c3, 0, sizeof(c3)); + c3.element = choice_TESTImplicit4_ti2; + c3.u.ti2.element = choice_TESTChoice2_i1; + c3.u.ti2.u.i1 = 5; + tests4[0].val = &c3; + + ret += generic_test(tests, + sizeof(tests) / sizeof(*tests), + sizeof(TESTImplicit), + (generic_encode)encode_TESTImplicit, + (generic_length)length_TESTImplicit, + (generic_decode)decode_TESTImplicit, + (generic_free)free_TESTImplicit, + cmp_TESTImplicit, + (generic_copy)copy_TESTImplicit); + + ret += generic_test(tests2, + sizeof(tests2) / sizeof(*tests2), + sizeof(TESTImplicit2), + (generic_encode)encode_TESTImplicit2, + (generic_length)length_TESTImplicit2, + (generic_decode)decode_TESTImplicit2, + (generic_free)free_TESTImplicit2, + cmp_TESTImplicit2, + NULL); + + ret += generic_test(tests3, + sizeof(tests3) / sizeof(*tests3), + sizeof(TESTImplicit3), + (generic_encode)encode_TESTImplicit3, + (generic_length)length_TESTImplicit3, + (generic_decode)decode_TESTImplicit3, + (generic_free)free_TESTImplicit3, + cmp_TESTImplicit3, + NULL); + + ret += generic_test(tests4, + sizeof(tests4) / sizeof(*tests4), + sizeof(TESTImplicit4), + (generic_encode)encode_TESTImplicit4, + (generic_length)length_TESTImplicit4, + (generic_decode)decode_TESTImplicit4, + (generic_free)free_TESTImplicit4, + cmp_TESTImplicit4, + NULL); + + return ret; +} + +static int +cmp_TESTAlloc (void *a, void *b) +{ + TESTAlloc *aa = a; + TESTAlloc *ab = b; + + IF_OPT_COMPARE(aa,ab,tagless) { + COMPARE_INTEGER(aa,ab,tagless->ai); + } + + COMPARE_INTEGER(aa,ab,three); + + IF_OPT_COMPARE(aa,ab,tagless2) { + COMPARE_OPT_OCTET_STRING(aa, ab, tagless2); + } + + return 0; +} + +/* +UNIV CONS Sequence 12 + UNIV CONS Sequence 5 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 01 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 03 + +UNIV CONS Sequence 5 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 03 + +UNIV CONS Sequence 8 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 04 + UNIV PRIM Integer 1 05 + +*/ + +static int +test_taglessalloc (void) +{ + struct test_case tests[] = { + { NULL, 14, + "\x30\x0c\x30\x05\xa0\x03\x02\x01\x01\xa1\x03\x02\x01\x03", + "alloc 1" }, + { NULL, 7, + "\x30\x05\xa1\x03\x02\x01\x03", + "alloc 2" }, + { NULL, 10, + "\x30\x08\xa1\x03\x02\x01\x04\x02\x01\x05", + "alloc 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTAlloc c1, c2, c3; + heim_any any3; + + memset(&c1, 0, sizeof(c1)); + c1.tagless = ecalloc(1, sizeof(*c1.tagless)); + c1.tagless->ai = 1; + c1.three = 3; + tests[0].val = &c1; + + memset(&c2, 0, sizeof(c2)); + c2.tagless = NULL; + c2.three = 3; + tests[1].val = &c2; + + memset(&c3, 0, sizeof(c3)); + c3.tagless = NULL; + c3.three = 4; + c3.tagless2 = &any3; + any3.data = "\x02\x01\x05"; + any3.length = 3; + tests[2].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTAlloc), + (generic_encode)encode_TESTAlloc, + (generic_length)length_TESTAlloc, + (generic_decode)decode_TESTAlloc, + (generic_free)free_TESTAlloc, + cmp_TESTAlloc, + (generic_copy)copy_TESTAlloc); + + free(c1.tagless); + + return ret; +} + +static int +cmp_TESTOptional (void *a, void *b) +{ + TESTOptional *aa = a; + TESTOptional *ab = b; + + IF_OPT_COMPARE(aa,ab,zero) { + COMPARE_OPT_INTEGER(aa,ab,zero); + } + IF_OPT_COMPARE(aa,ab,one) { + COMPARE_OPT_INTEGER(aa,ab,one); + } + return 0; +} + +/* +UNIV CONS Sequence 5 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 00 + +UNIV CONS Sequence 5 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 03 + +UNIV CONS Sequence 10 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 00 + CONTEXT CONS 1 3 + UNIV PRIM Integer 1 01 + +*/ + +static int +test_optional (void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "optional 0" }, + { NULL, 7, + "\x30\x05\xa0\x03\x02\x01\x00", + "optional 1" }, + { NULL, 7, + "\x30\x05\xa1\x03\x02\x01\x01", + "optional 2" }, + { NULL, 12, + "\x30\x0a\xa0\x03\x02\x01\x00\xa1\x03\x02\x01\x01", + "optional 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTOptional c0, c1, c2, c3; + int zero = 0; + int one = 1; + + c0.zero = NULL; + c0.one = NULL; + tests[0].val = &c0; + + c1.zero = &zero; + c1.one = NULL; + tests[1].val = &c1; + + c2.zero = NULL; + c2.one = &one; + tests[2].val = &c2; + + c3.zero = &zero; + c3.one = &one; + tests[3].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTOptional), + (generic_encode)encode_TESTOptional, + (generic_length)length_TESTOptional, + (generic_decode)decode_TESTOptional, + (generic_free)free_TESTOptional, + cmp_TESTOptional, + (generic_copy)copy_TESTOptional); + + return ret; +} + +static int +check_fail_largetag(void) +{ + struct test_case tests[] = { + {NULL, 14, "\x30\x0c\xbf\x87\xff\xff\xff\xff\xff\x7f\x03\x02\x01\x01", + "tag overflow"}, + {NULL, 0, "", "empty buffer"}, + {NULL, 7, "\x30\x05\xa1\x03\x02\x02\x01", + "one too short" }, + {NULL, 7, "\x30\x04\xa1\x03\x02\x02\x01", + "two too short" }, + {NULL, 7, "\x30\x03\xa1\x03\x02\x02\x01", + "three too short" }, + {NULL, 7, "\x30\x02\xa1\x03\x02\x02\x01", + "four too short" }, + {NULL, 7, "\x30\x01\xa1\x03\x02\x02\x01", + "five too short" }, + {NULL, 7, "\x30\x00\xa1\x03\x02\x02\x01", + "six too short" }, + {NULL, 7, "\x30\x05\xa1\x04\x02\x02\x01", + "inner one too long" }, + {NULL, 7, "\x30\x00\xa1\x02\x02\x02\x01", + "inner one too short" }, + {NULL, 8, "\x30\x05\xbf\x7f\x03\x02\x02\x01", + "inner one too short"}, + {NULL, 8, "\x30\x06\xbf\x64\x03\x02\x01\x01", + "wrong tag"}, + {NULL, 10, "\x30\x08\xbf\x9a\x9b\x38\x03\x02\x01\x01", + "still wrong tag"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(TESTLargeTag), + (generic_decode)decode_TESTLargeTag); +} + + +static int +check_fail_sequence(void) +{ + struct test_case tests[] = { + {NULL, 0, "", "empty buffer"}, + {NULL, 24, + "\x30\x16\xa0\x03\x02\x01\x01\xa1\x08\x30\x06\xbf\x7f\x03\x02\x01\x01" + "\x02\x01\x01\xa2\x03\x02\x01\x01", + "missing one byte from the end, internal length ok"}, + {NULL, 25, + "\x30\x18\xa0\x03\x02\x01\x01\xa1\x08\x30\x06\xbf\x7f\x03\x02\x01\x01" + "\x02\x01\x01\xa2\x03\x02\x01\x01", + "inner length one byte too long"}, + {NULL, 24, + "\x30\x17\xa0\x03\x02\x01\x01\xa1\x08\x30\x06\xbf\x7f\x03\x02\x01" + "\x01\x02\x01\x01\xa2\x03\x02\x01\x01", + "correct buffer but missing one too short"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(TESTSeq), + (generic_decode)decode_TESTSeq); +} + +static int +check_fail_choice(void) +{ + struct test_case tests[] = { + {NULL, 6, + "\xa1\x02\x02\x01\x01", + "choice one too short"}, + {NULL, 6, + "\xa1\x03\x02\x02\x01", + "choice one too short inner"} + }; + int ntests = sizeof(tests) / sizeof(*tests); + + return generic_decode_fail(tests, ntests, sizeof(TESTChoice1), + (generic_decode)decode_TESTChoice1); +} + +static int +check_fail_Ticket(void) +{ + char buf[100]; + size_t i; + int ret; + struct test_case test; + Ticket ticket; + + for (i = 0; i < sizeof(buf); i++) { + memset(buf, 0, sizeof(buf)); + memset(&ticket, 0, sizeof(ticket)); + test.val = &ticket; + test.byte_len = i; + test.bytes = buf; + test.name = "zero life"; + ret = generic_decode_fail(&test, 1, sizeof(Ticket), + (generic_decode)decode_Ticket); + if (ret) + return ret; + } + return 0; +} + +static int +check_seq(void) +{ + TESTSeqOf seq; + TESTInteger i = 0; + int ret; + + seq.val = NULL; + seq.len = 0; + + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + ret = add_TESTSeqOf(&seq, &i); + if (ret) { printf("failed adding\n"); goto out; } + + ret = remove_TESTSeqOf(&seq, seq.len - 1); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 2); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 0); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 0); + if (ret) { printf("failed removing\n"); goto out; } + ret = remove_TESTSeqOf(&seq, 0); + if (ret == 0) { + printf("can remove from empty list"); + return 1; + } + + if (seq.len != 0) { + printf("seq not empty!"); + return 1; + } + free_TESTSeqOf(&seq); + ret = 0; + +out: + + return ret; +} + +#define test_seq_of(type, ok, ptr) \ +{ \ + heim_octet_string os; \ + size_t size; \ + type decode; \ + ASN1_MALLOC_ENCODE(type, os.data, os.length, ptr, &size, ret); \ + if (ret) \ + return ret; \ + if (os.length != size) \ + abort(); \ + ret = decode_##type(os.data, os.length, &decode, &size); \ + free(os.data); \ + if (ret) { \ + if (ok) \ + return 1; \ + } else { \ + free_##type(&decode); \ + if (!ok) \ + return 1; \ + if (size != 0) \ + return 1; \ + } \ + return 0; \ +} + +static int +check_seq_of_size(void) +{ +#if 0 /* template */ + TESTInteger integers[4] = { 1, 2, 3, 4 }; + int ret; + + { + TESTSeqSizeOf1 ssof1f1 = { 1, integers }; + TESTSeqSizeOf1 ssof1ok1 = { 2, integers }; + TESTSeqSizeOf1 ssof1f2 = { 3, integers }; + + test_seq_of(TESTSeqSizeOf1, 0, &ssof1f1); + test_seq_of(TESTSeqSizeOf1, 1, &ssof1ok1); + test_seq_of(TESTSeqSizeOf1, 0, &ssof1f2); + } + { + TESTSeqSizeOf2 ssof2f1 = { 0, NULL }; + TESTSeqSizeOf2 ssof2ok1 = { 1, integers }; + TESTSeqSizeOf2 ssof2ok2 = { 2, integers }; + TESTSeqSizeOf2 ssof2f2 = { 3, integers }; + + test_seq_of(TESTSeqSizeOf2, 0, &ssof2f1); + test_seq_of(TESTSeqSizeOf2, 1, &ssof2ok1); + test_seq_of(TESTSeqSizeOf2, 1, &ssof2ok2); + test_seq_of(TESTSeqSizeOf2, 0, &ssof2f2); + } + { + TESTSeqSizeOf3 ssof3f1 = { 0, NULL }; + TESTSeqSizeOf3 ssof3ok1 = { 1, integers }; + TESTSeqSizeOf3 ssof3ok2 = { 2, integers }; + + test_seq_of(TESTSeqSizeOf3, 0, &ssof3f1); + test_seq_of(TESTSeqSizeOf3, 1, &ssof3ok1); + test_seq_of(TESTSeqSizeOf3, 1, &ssof3ok2); + } + { + TESTSeqSizeOf4 ssof4ok1 = { 0, NULL }; + TESTSeqSizeOf4 ssof4ok2 = { 1, integers }; + TESTSeqSizeOf4 ssof4ok3 = { 2, integers }; + TESTSeqSizeOf4 ssof4f1 = { 3, integers }; + + test_seq_of(TESTSeqSizeOf4, 1, &ssof4ok1); + test_seq_of(TESTSeqSizeOf4, 1, &ssof4ok2); + test_seq_of(TESTSeqSizeOf4, 1, &ssof4ok3); + test_seq_of(TESTSeqSizeOf4, 0, &ssof4f1); + } +#endif + return 0; +} + +static int +check_TESTMechTypeList(void) +{ + TESTMechTypeList tl; + unsigned oid1[] = { 1, 2, 840, 48018, 1, 2, 2}; + unsigned oid2[] = { 1, 2, 840, 113554, 1, 2, 2}; + unsigned oid3[] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 30}; + unsigned oid4[] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10}; + TESTMechType array[] = {{ 7, oid1 }, + { 7, oid2 }, + { 10, oid3 }, + { 10, oid4 }}; + size_t size, len; + void *ptr; + int ret; + + tl.len = 4; + tl.val = array; + + ASN1_MALLOC_ENCODE(TESTMechTypeList, ptr, len, &tl, &size, ret); + if (ret) + errx(1, "TESTMechTypeList: %d", ret); + if (len != size) + abort(); + free(ptr); + return 0; +} + +static int +cmp_TESTSeqOf4(void *a, void *b) +{ + TESTSeqOf4 *aa = a; + TESTSeqOf4 *ab = b; + int i; + + IF_OPT_COMPARE(aa, ab, b1) { + COMPARE_INTEGER(aa->b1, ab->b1, len); + for (i = 0; i < aa->b1->len; ++i) { + COMPARE_INTEGER(aa->b1->val+i, ab->b1->val+i, u1); + COMPARE_INTEGER(aa->b1->val+i, ab->b1->val+i, u2); + COMPARE_OCTET_STRING(aa->b1->val+i, ab->b1->val+i, s1); + COMPARE_OCTET_STRING(aa->b1->val+i, ab->b1->val+i, s2); + } + } + IF_OPT_COMPARE(aa, ab, b2) { + COMPARE_INTEGER(aa->b2, ab->b2, len); + for (i = 0; i < aa->b2->len; ++i) { + COMPARE_INTEGER(aa->b2->val+i, ab->b2->val+i, u1); + COMPARE_INTEGER(aa->b2->val+i, ab->b2->val+i, u2); + COMPARE_INTEGER(aa->b2->val+i, ab->b2->val+i, u3); + COMPARE_OCTET_STRING(aa->b2->val+i, ab->b2->val+i, s1); + COMPARE_OCTET_STRING(aa->b2->val+i, ab->b2->val+i, s2); + COMPARE_OCTET_STRING(aa->b2->val+i, ab->b2->val+i, s3); + } + } + IF_OPT_COMPARE(aa, ab, b3) { + COMPARE_INTEGER(aa->b3, ab->b3, len); + for (i = 0; i < aa->b3->len; ++i) { + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u1); + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u2); + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u3); + COMPARE_INTEGER(aa->b3->val+i, ab->b3->val+i, u4); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s1); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s2); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s3); + COMPARE_OCTET_STRING(aa->b3->val+i, ab->b3->val+i, s4); + } + } + return 0; +} + +static int +test_seq4 (void) +{ + int ret = 0; + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seq4 0" }, + { NULL, 4, + "\x30\x02" "\xa1\x00", + "seq4 1" }, + { NULL, 8, + "\x30\x06" "\xa0\x02\x30\x00" "\xa1\x00", + "seq4 2" }, + { NULL, 2 + (2 + 0x18) + (2 + 0x27) + (2 + 0x31), + "\x30\x76" /* 2 SEQ */ + "\xa0\x18\x30\x16" /* 4 [0] SEQ */ + "\x30\x14" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\xa1\x27" /* 2 [1] IMPL SEQ */ + "\x30\x25" /* 2 SEQ */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\xa2\x31" /* 2 [2] IMPL SEQ */ + "\x30\x2f" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x01\x00" /* 3 OCTET-STRING */ + "\x02\x05\x01\x00\x00\x00\x00", /* 7 INT */ + "seq4 3" }, + }; + + int ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf4 c[4]; + struct TESTSeqOf4_b1 b1[4]; + struct TESTSeqOf4_b2 b2[4]; + struct TESTSeqOf4_b3 b3[4]; + struct TESTSeqOf4_b1_val b1val[4]; + struct TESTSeqOf4_b2_val b2val[4]; + struct TESTSeqOf4_b3_val b3val[4]; + + c[0].b1 = NULL; + c[0].b2 = NULL; + c[0].b3 = NULL; + tests[0].val = &c[0]; + + b2[1].len = 0; + b2[1].val = NULL; + c[1].b1 = NULL; + c[1].b2 = &b2[1]; + c[1].b3 = NULL; + tests[1].val = &c[1]; + + b1[2].len = 0; + b1[2].val = NULL; + b2[2].len = 0; + b2[2].val = NULL; + c[2].b1 = &b1[2]; + c[2].b2 = &b2[2]; + c[2].b3 = NULL; + tests[2].val = &c[2]; + + b1val[3].s1.data = ""; + b1val[3].s1.length = 0; + b1val[3].u1 = 1LL; + b1val[3].s2.data = "\x01\x02"; + b1val[3].s2.length = 2; + b1val[3].u2 = -1LL; + + b2val[3].s1.data = ""; + b2val[3].s1.length = 0; + b2val[3].u1 = 1LL; + b2val[3].s2.data = "\x01\x02"; + b2val[3].s2.length = 2; + b2val[3].u2 = -1LL; + b2val[3].s3.data = "\x00\x01\x02\x03"; + b2val[3].s3.length = 4; + b2val[3].u3 = 1LL<<63; + + b3val[3].s1.data = ""; + b3val[3].s1.length = 0; + b3val[3].u1 = 1LL; + b3val[3].s2.data = "\x01\x02"; + b3val[3].s2.length = 2; + b3val[3].u2 = -1LL; + b3val[3].s3.data = "\x00\x01\x02\x03"; + b3val[3].s3.length = 4; + b3val[3].u3 = 1LL<<63; + b3val[3].s4.data = "\x00"; + b3val[3].s4.length = 1; + b3val[3].u4 = 1LL<<32; + + b1[3].len = 1; + b1[3].val = &b1val[3]; + b2[3].len = 1; + b2[3].val = &b2val[3]; + b3[3].len = 1; + b3[3].val = &b3val[3]; + c[3].b1 = &b1[3]; + c[3].b2 = &b2[3]; + c[3].b3 = &b3[3]; + tests[3].val = &c[3]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf4), + (generic_encode)encode_TESTSeqOf4, + (generic_length)length_TESTSeqOf4, + (generic_decode)decode_TESTSeqOf4, + (generic_free)free_TESTSeqOf4, + cmp_TESTSeqOf4, + (generic_copy)copy_TESTSeqOf4); + return ret; +} + +static int +cmp_test_seqof5 (void *a, void *b) +{ + TESTSeqOf5 *aval = a; + TESTSeqOf5 *bval = b; + + IF_OPT_COMPARE(aval, bval, outer) { + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u0); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s0); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u1); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s1); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u2); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s2); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u3); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s3); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u4); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s4); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u5); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s5); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u6); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s6); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u7); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s7); + } + return 0; +} + +static int +test_seqof5(void) +{ + struct test_case tests[] = { + { NULL, 2, "\x30\x00", "seq5 0" }, + { NULL, 126, + "\x30\x7c" /* SEQ */ + "\x30\x7a" /* SEQ */ + "\x30\x78" /* SEQ */ + "\x02\x01\x01" /* INT 1 */ + "\x04\x06\x01\x01\x01\x01\x01\x01" /* "\0x1"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfe" /* INT ~1 */ + "\x04\x06\x02\x02\x02\x02\x02\x02" /* "\x02"x6 */ + "\x02\x01\x02" /* INT 2 */ + "\x04\x06\x03\x03\x03\x03\x03\x03" /* "\x03"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfd" /* INT ~2 */ + "\x04\x06\x04\x04\x04\x04\x04\x04" /* ... */ + "\x02\x01\x03" + "\x04\x06\x05\x05\x05\x05\x05\x05" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfc" + "\x04\x06\x06\x06\x06\x06\x06\x06" + "\x02\x01\x04" + "\x04\x06\x07\x07\x07\x07\x07\x07" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfb" + "\x04\x06\x08\x08\x08\x08\x08\x08", + "seq5 1" }, + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf5 c[2]; + struct TESTSeqOf5_outer outer; + struct TESTSeqOf5_outer_inner inner; + TESTuint64 u[8]; + heim_octet_string s[8]; + int i; + + c[0].outer = NULL; + tests[0].val = &c[0]; + + for (i = 0; i < 8; ++i) { + u[i] = (i&1) == 0 ? i/2+1 : ~(i/2+1); + s[i].data = memset(malloc(s[i].length = 6), i+1, 6); + } + + inner.u0 = u[0]; inner.u1 = u[1]; inner.u2 = u[2]; inner.u3 = u[3]; + inner.u4 = u[4]; inner.u5 = u[5]; inner.u6 = u[6]; inner.u7 = u[7]; + inner.s0 = s[0]; inner.s1 = s[1]; inner.s2 = s[2]; inner.s3 = s[3]; + inner.s4 = s[4]; inner.s5 = s[5]; inner.s6 = s[6]; inner.s7 = s[7]; + + outer.inner = inner; + c[1].outer = &outer; + tests[1].val = &c[1]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf5), + (generic_encode)encode_TESTSeqOf5, + (generic_length)length_TESTSeqOf5, + (generic_decode)decode_TESTSeqOf5, + (generic_free)free_TESTSeqOf5, + cmp_test_seqof5, + NULL); + + for (i = 0; i < 8; ++i) + free(s[i].data); + + return ret; +} + +static int +cmp_default(void *a, void *b) +{ + TESTDefault *aa = a; + TESTDefault *ab = b; + + COMPARE_STRING(aa,ab,name); + COMPARE_INTEGER(aa,ab,version); + COMPARE_INTEGER(aa,ab,maxint); + COMPARE_INTEGER(aa,ab,works); + return 0; +} + +static int +test_default(void) +{ + struct test_case tests[] = { +#ifndef DISABLE_TEST_64 + { NULL, 2, "\x30\x00", NULL }, +#endif + { NULL, 25, + "\x30\x17\x0c\x07\x68\x65\x69\x6d\x64\x61" + "\x6c\xa0\x03\x02\x01\x07\x02\x04\x7f\xff" + "\xff\xff\x01\x01\x00", + NULL + }, +#ifndef DISABLE_TEST_64 + { NULL, 10, + "\x30\x08\xa0\x03\x02\x01\x07\x01\x01\x00", + NULL + }, +#endif + { NULL, 17, + "\x30\x0f\x0c\x07\x68\x65\x69\x6d\x64\x61\x6c\x02\x04" + "\x7f\xff\xff\xff", + NULL + } + }; + + TESTDefault values[] = { +#ifndef DISABLE_TEST_64 + { "Heimdal", 8, 9223372036854775807LL, 1 }, +#endif + { "heimdal", 7, 2147483647, 0 }, +#ifndef DISABLE_TEST_64 + { "Heimdal", 7, 9223372036854775807LL, 0 }, +#endif + { "heimdal", 8, 2147483647, 1 }, + }; + int i, ret; + int ntests = sizeof(tests) / sizeof(*tests); + + for (i = 0; i < ntests; ++i) { + tests[i].val = &values[i]; + if (asprintf (&tests[i].name, "TESTDefault %d", i) < 0) + errx(1, "malloc"); + if (tests[i].name == NULL) + errx(1, "malloc"); + } + + ret = generic_test (tests, ntests, sizeof(TESTDefault), + (generic_encode)encode_TESTDefault, + (generic_length)length_TESTDefault, + (generic_decode)decode_TESTDefault, + (generic_free)free_TESTDefault, + cmp_default, + (generic_copy)copy_TESTDefault); + for (i = 0; i < ntests; ++i) + free(tests[i].name); + + return ret; +} + +static int +test_x690sample(void) +{ + /* + * Taken from X.690, Appendix A, though sadly it's not specified whether + * it's in BER, DER, or CER, but it is clearly BER and neither DER nor CER + * because the tags of the members of the X690SamplePersonnelRecord type + * are not canonically sorted in the given sample. + * + * Our compiler does NOT canonically sort the members of SET { ... } types + * so it produces the same encoding after decoding this test vector. That + * is clearly a bug given that we aim to output DER. + * + * The template compiler doesn't even decode SET { ... } values properly + * when their members are not in the same order as defined (but the regular + * compiler does). + */ + X690SamplePersonnelRecord r; + heim_octet_string os; + unsigned char encoded_sample[] = { + 0x60, 0x81, 0x85, 0x61, 0x10, 0x1a, 0x04, 0x4a, 0x6f, 0x68, 0x6e, 0x1a, + 0x01, 0x50, 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x1a, + 0x08, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x42, 0x01, 0x33, + 0xa1, 0x0a, 0x43, 0x08, 0x31, 0x39, 0x37, 0x31, 0x30, 0x39, 0x31, 0x37, + 0xa2, 0x12, 0x61, 0x10, 0x1a, 0x04, 0x4d, 0x61, 0x72, 0x79, 0x1a, 0x01, + 0x54, 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa3, 0x42, 0x31, 0x1f, + 0x61, 0x11, 0x1a, 0x05, 0x52, 0x61, 0x6c, 0x70, 0x68, 0x1a, 0x01, 0x54, + 0x1a, 0x05, 0x53, 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x43, 0x08, 0x31, + 0x39, 0x35, 0x37, 0x31, 0x31, 0x31, 0x31, 0x31, 0x1f, 0x61, 0x11, 0x1a, + 0x05, 0x53, 0x75, 0x73, 0x61, 0x6e, 0x1a, 0x01, 0x42, 0x1a, 0x05, 0x53, + 0x6d, 0x69, 0x74, 0x68, 0xa0, 0x0a, 0x43, 0x08, 0x31, 0x39, 0x35, 0x39, + 0x30, 0x37, 0x31, 0x37 + }; + size_t sz = 0; + int ret; + + memset(&r, 0, sizeof(r)); + if (decode_X690SamplePersonnelRecord(encoded_sample, sizeof(encoded_sample), &r, &sz)) + return 1; + if (sz != sizeof(encoded_sample)) + return 1; + free_X690SamplePersonnelRecord(&r); + memset(&r, 0, sizeof(r)); + + /* We re-construct the record manually to double-check the spec */ + r.name.givenName = strdup("John"); + r.name.initial = strdup("P"); + r.name.familyName = strdup("Smith"); + r.title = strdup("Director"); + r.dateOfHire = strdup("19710917"); + r.number = 51; + r.nameOfSpouse.givenName = strdup("Mary"); + r.nameOfSpouse.initial = strdup("T"); + r.nameOfSpouse.familyName = strdup("Smith"); + r.children.val = calloc(2, sizeof(r.children.val[0])); + r.children.len = 2; + r.children.val[0].name.givenName = strdup("Ralph"); + r.children.val[0].name.initial = strdup("T"); + r.children.val[0].name.familyName = strdup("Smith"); + r.children.val[0].dateOfBirth = strdup("19571111"); + r.children.val[1].name.givenName = strdup("Susan"); + r.children.val[1].name.initial = strdup("B"); + r.children.val[1].name.familyName = strdup("Smith"); + r.children.val[1].dateOfBirth = strdup("19590717"); + os.length = 0; + os.data = 0; + ASN1_MALLOC_ENCODE(X690SamplePersonnelRecord, os.data, os.length, &r, &sz, + ret); + if (ret || sz != sizeof(encoded_sample) || sz != os.length || + memcmp(encoded_sample, os.data, sz) != 0) + return 1; + free_X690SamplePersonnelRecord(&r); + free(os.data); + return 0; +} + +#if ASN1_IOS_SUPPORTED +static int +test_ios(void) +{ + unsigned char encoded_sample[] = { + 0x30, 0x82, 0x04, 0x8e, 0x30, 0x82, 0x03, 0x76, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x6a, + 0x05, 0x97, 0xba, 0x71, 0xd7, 0xe6, 0xd3, 0xac, + 0x0e, 0xdc, 0x9e, 0xdc, 0x95, 0xa1, 0x5b, 0x99, + 0x8d, 0xe4, 0x0a, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x30, 0x55, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, + 0x48, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x15, 0x53, 0x54, 0x4d, 0x69, + 0x63, 0x72, 0x6f, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x73, 0x20, 0x4e, + 0x56, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x1d, 0x53, 0x54, 0x4d, 0x20, + 0x54, 0x50, 0x4d, 0x20, 0x45, 0x4b, 0x20, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, + 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x20, 0x30, + 0x35, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, + 0x32, 0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x31, 0x32, + 0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x5a, 0x30, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xcc, 0x14, 0xeb, 0x27, + 0xa7, 0x8c, 0xeb, 0x0e, 0xa4, 0x86, 0xfa, 0x2d, + 0xf7, 0x83, 0x5f, 0x5f, 0xa8, 0xe9, 0x05, 0xb0, + 0x97, 0x01, 0x2b, 0x5b, 0xde, 0x50, 0x38, 0x0c, + 0x35, 0x5b, 0x1a, 0x2a, 0x72, 0x1b, 0xbc, 0x3d, + 0x08, 0xdd, 0x21, 0x79, 0x6c, 0xdb, 0x23, 0x9f, + 0xa9, 0x53, 0x10, 0x65, 0x1b, 0x1b, 0x56, 0xfd, + 0x2c, 0xfe, 0x53, 0xc8, 0x73, 0x52, 0xeb, 0xd9, + 0x96, 0xe3, 0x32, 0x56, 0x16, 0x04, 0x04, 0xce, + 0x93, 0x02, 0xa0, 0x80, 0x66, 0x80, 0x1e, 0x78, + 0x6a, 0x2f, 0x86, 0xe1, 0x81, 0xf9, 0x49, 0x96, + 0x6f, 0x49, 0x2a, 0x85, 0xb5, 0x8e, 0xaa, 0x4a, + 0x6a, 0x8c, 0xb3, 0x69, 0x75, 0x51, 0xbb, 0x23, + 0x6e, 0x87, 0xcc, 0x7b, 0xf8, 0xec, 0x13, 0x47, + 0x87, 0x1c, 0x91, 0xe1, 0x54, 0x37, 0xe8, 0xf2, + 0x66, 0xbf, 0x1e, 0xa5, 0xeb, 0x27, 0x1f, 0xdc, + 0xf3, 0x74, 0xd8, 0xb4, 0x7d, 0xf8, 0xbc, 0xe8, + 0x9e, 0x1f, 0xad, 0x61, 0xc2, 0xa0, 0x88, 0xcb, + 0x40, 0x36, 0xb3, 0x59, 0xcb, 0x72, 0xa2, 0x94, + 0x97, 0x3f, 0xed, 0xcc, 0xf0, 0xc3, 0x40, 0xaf, + 0xfd, 0x14, 0xb6, 0x4f, 0x04, 0x11, 0x65, 0x58, + 0x1a, 0xca, 0x34, 0x14, 0x7c, 0x1c, 0x75, 0x61, + 0x70, 0x47, 0x05, 0x8f, 0x7e, 0xd7, 0xd6, 0x03, + 0xe0, 0x32, 0x50, 0x80, 0x94, 0xfa, 0x73, 0xe8, + 0xb9, 0x15, 0x3d, 0xa3, 0xbf, 0x25, 0x5d, 0x2c, + 0xbb, 0xc5, 0xdf, 0x30, 0x1b, 0xa8, 0xf7, 0x4d, + 0x19, 0x8b, 0xeb, 0xce, 0x86, 0x04, 0x0f, 0xc1, + 0xd2, 0x92, 0x7c, 0x76, 0x57, 0x41, 0x44, 0x90, + 0xd8, 0x02, 0xf4, 0x82, 0xf3, 0xeb, 0xf2, 0xde, + 0x35, 0xee, 0x14, 0x9a, 0x1a, 0x6d, 0xe8, 0xd1, + 0x68, 0x91, 0xfb, 0xfb, 0xa0, 0x2a, 0x18, 0xaf, + 0xe5, 0x9f, 0x9d, 0x6f, 0x14, 0x97, 0x44, 0xe5, + 0xf0, 0xd5, 0x59, 0xb1, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0xa9, 0x30, 0x82, 0x01, + 0xa5, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x1a, 0xdb, + 0x99, 0x4a, 0xb5, 0x8b, 0xe5, 0x7a, 0x0c, 0xc9, + 0xb9, 0x00, 0xe7, 0x85, 0x1e, 0x1a, 0x43, 0xc0, + 0x86, 0x60, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, + 0x20, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0x06, + 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30, 0x2f, 0x30, + 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x02, 0x01, 0x16, 0x21, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, + 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, + 0x50, 0x4d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x30, 0x59, + 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01, 0xff, + 0x04, 0x4f, 0x30, 0x4d, 0xa4, 0x4b, 0x30, 0x49, + 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67, 0x81, + 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64, 0x3a, + 0x35, 0x33, 0x35, 0x34, 0x34, 0x44, 0x32, 0x30, + 0x31, 0x17, 0x30, 0x15, 0x06, 0x05, 0x67, 0x81, + 0x05, 0x02, 0x02, 0x0c, 0x0c, 0x53, 0x54, 0x33, + 0x33, 0x48, 0x54, 0x50, 0x48, 0x41, 0x48, 0x43, + 0x30, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67, + 0x81, 0x05, 0x02, 0x03, 0x0c, 0x0b, 0x69, 0x64, + 0x3a, 0x30, 0x30, 0x34, 0x39, 0x30, 0x30, 0x30, + 0x38, 0x30, 0x67, 0x06, 0x03, 0x55, 0x1d, 0x09, + 0x04, 0x60, 0x30, 0x5e, 0x30, 0x17, 0x06, 0x05, + 0x67, 0x81, 0x05, 0x02, 0x10, 0x31, 0x0e, 0x30, + 0x0c, 0x0c, 0x03, 0x32, 0x2e, 0x30, 0x02, 0x01, + 0x00, 0x02, 0x02, 0x00, 0x8a, 0x30, 0x43, 0x06, + 0x05, 0x67, 0x81, 0x05, 0x02, 0x12, 0x31, 0x3a, + 0x30, 0x38, 0x02, 0x01, 0x00, 0x01, 0x01, 0xff, + 0xa0, 0x03, 0x0a, 0x01, 0x01, 0xa1, 0x03, 0x0a, + 0x01, 0x00, 0xa2, 0x03, 0x0a, 0x01, 0x00, 0xa3, + 0x10, 0x30, 0x0e, 0x16, 0x03, 0x33, 0x2e, 0x31, + 0x0a, 0x01, 0x04, 0x0a, 0x01, 0x02, 0x01, 0x01, + 0xff, 0xa4, 0x0f, 0x30, 0x0d, 0x16, 0x05, 0x31, + 0x34, 0x30, 0x2d, 0x32, 0x0a, 0x01, 0x02, 0x01, + 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x05, 0x20, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, + 0x09, 0x30, 0x07, 0x06, 0x05, 0x67, 0x81, 0x05, + 0x08, 0x01, 0x30, 0x4a, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x3e, + 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2e, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x67, 0x6c, + 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69, 0x67, 0x6e, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x74, 0x6d, + 0x74, 0x70, 0x6d, 0x65, 0x6b, 0x69, 0x6e, 0x74, + 0x30, 0x35, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x3d, 0x4c, 0x38, 0x1e, 0x5b, 0x4f, + 0x1b, 0xcb, 0xe0, 0x9c, 0x63, 0xd5, 0x2f, 0x1f, + 0x04, 0x57, 0x0c, 0xae, 0xa1, 0x42, 0xfd, 0x9c, + 0xd9, 0x42, 0x04, 0x3b, 0x11, 0xf8, 0xe3, 0xbd, + 0xcf, 0x50, 0x00, 0x7a, 0xe1, 0x6c, 0xf8, 0x86, + 0x90, 0x13, 0x04, 0x1e, 0x92, 0xcd, 0xd3, 0x28, + 0x0b, 0xa4, 0xb5, 0x1f, 0xbb, 0xd4, 0x05, 0x82, + 0xed, 0x75, 0x02, 0x19, 0xe2, 0x61, 0xa6, 0x95, + 0x09, 0x56, 0x74, 0x85, 0x5a, 0xac, 0xeb, 0x52, + 0x0a, 0xda, 0xff, 0x9e, 0x7e, 0x90, 0x84, 0x80, + 0xa3, 0x9c, 0xdc, 0xf9, 0x00, 0x46, 0x2d, 0x91, + 0x71, 0x96, 0x0f, 0xfe, 0x55, 0xd3, 0xac, 0x49, + 0xe8, 0xc9, 0x81, 0x34, 0x1b, 0xbd, 0x2e, 0xfb, + 0xcc, 0x25, 0x2a, 0x4c, 0x18, 0xa4, 0xf3, 0xb7, + 0xc8, 0x4c, 0xce, 0x42, 0xce, 0x70, 0xa2, 0x08, + 0xc8, 0x4d, 0x26, 0x30, 0xa7, 0xab, 0xfb, 0xe7, + 0x2d, 0x62, 0x71, 0xe7, 0x5b, 0x9f, 0xf1, 0xc9, + 0x71, 0xd2, 0x0e, 0xb3, 0xdb, 0xd7, 0x63, 0xf1, + 0xe0, 0x4d, 0x83, 0x4e, 0xaa, 0x69, 0x2d, 0x2e, + 0x40, 0x01, 0xbb, 0xf4, 0x73, 0x0a, 0x3e, 0x3f, + 0xda, 0x97, 0x11, 0xae, 0x38, 0x65, 0x24, 0xd9, + 0x1c, 0x63, 0xbe, 0x0e, 0x51, 0x6d, 0x00, 0xd5, + 0xc6, 0x14, 0x1f, 0xcc, 0xf6, 0xc5, 0x39, 0xf3, + 0x51, 0x8e, 0x18, 0x00, 0x49, 0x86, 0x5b, 0xe1, + 0x6b, 0x69, 0xca, 0xe1, 0xf8, 0xcb, 0x7f, 0xdc, + 0x47, 0x4b, 0x38, 0xf7, 0xee, 0x56, 0xcb, 0xe7, + 0xd8, 0xa8, 0x9d, 0x9b, 0xa9, 0x9b, 0x65, 0xd5, + 0x26, 0x5a, 0xef, 0x32, 0xaa, 0x62, 0x42, 0x6b, + 0x10, 0xe6, 0xd7, 0x5b, 0xb8, 0x67, 0x7e, 0xc4, + 0x4f, 0x75, 0x5b, 0xbc, 0x28, 0x06, 0xfd, 0x2b, + 0x4e, 0x04, 0xbd, 0xf5, 0xd4, 0x42, 0x59, 0xdb, + 0xea, 0xa4, 0x2b, 0x6f, 0x56, 0x3d, 0xf7, 0xaa, + 0x75, 0x06, + }; + char cert_json[] = { + "{\"_type\":\"Certificate\",\"tbsCertificate\":{\"_type\":\"TBSCertificate" + "\",\"_save\":\"30820376A00302010202146A0597BA71D7E6D3AC0EDC9EDC95A15" + "B998DE40A300D06092A864886F70D01010B05003055310B30090603550406130" + "24348311E301C060355040A131553544D6963726F656C656374726F6E6963732" + "04E56312630240603550403131D53544D2054504D20454B20496E7465726D656" + "469617465204341203035301E170D3138313231343030303030305A170D32383" + "13231343030303030305A300030820122300D06092A864886F70D01010105000" + "382010F003082010A0282010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E90" + "5B097012B5BDE50380C355B1A2A721BBC3D08DD21796CDB239FA95310651B1B5" + "6FD2CFE53C87352EBD996E33256160404CE9302A08066801E786A2F86E181F94" + "9966F492A85B58EAA4A6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E" + "8F266BF1EA5EB271FDCF374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A" + "294973FEDCCF0C340AFFD14B64F041165581ACA34147C1C75617047058F7ED7D" + "603E032508094FA73E8B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040" + "FC1D2927C7657414490D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A1" + "8AFE59F9D6F149744E5F0D559B10203010001A38201A9308201A5301F0603551" + "D230418301680141ADB994AB58BE57A0CC9B900E7851E1A43C08660304206035" + "51D20043B303930370604551D2000302F302D06082B060105050702011621687" + "474703A2F2F7777772E73742E636F6D2F54504D2F7265706F7369746F72792F3" + "0590603551D110101FF044F304DA44B304931163014060567810502010C0B696" + "43A353335343444323031173015060567810502020C0C5354333348545048414" + "8433031163014060567810502030C0B69643A303034393030303830670603551" + "D090460305E301706056781050210310E300C0C03322E300201000202008A304" + "306056781050212313A30380201000101FFA0030A0101A1030A0100A2030A010" + "0A310300E1603332E310A01040A01020101FFA40F300D16053134302D320A010" + "2010100300E0603551D0F0101FF040403020520300C0603551D130101FF04023" + "00030100603551D250409300706056781050801304A06082B060105050701010" + "43E303C303A06082B06010505073002862E687474703A2F2F7365637572652E6" + "76C6F62616C7369676E2E636F6D2F73746D74706D656B696E7430352E637274\"" + ",\"version\":\"rfc3280_version_3\",\"serialNumber\":\"6A0597BA71D7E6D3A" + "C0EDC9EDC95A15B998DE40A\",\"signature\":{\"_type\":\"AlgorithmIdentifi" + "er\",\"algorithm\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"1.2.840.1135" + "49.1.1.11\",\"components\":[1,2,840,113549,1,1,11],\"name\":\"id-pkcs1" + "-sha256WithRSAEncryption\"},\"parameters\":\"0500\"},\"issuer\":{\"_choi" + "ce\":\"rdnSequence\",\"value\":[[{\"_type\":\"AttributeTypeAndValue\",\"ty" + "pe\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.4.6\",\"components\":[2" + ",5,4,6],\"name\":\"id-at-countryName\"},\"value\":{\"_choice\":\"printabl" + "eString\",\"value\":\"CH\"}}],[{\"_type\":\"AttributeTypeAndValue\",\"type" + "\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.4.10\",\"components\":[2," + "5,4,10],\"name\":\"id-at-organizationName\"},\"value\":{\"_choice\":\"pri" + "ntableString\",\"value\":\"STMicroelectronics NV\"}}],[{\"_type\":\"Attr" + "ibuteTypeAndValue\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2." + "5.4.3\",\"components\":[2,5,4,3],\"name\":\"id-at-commonName\"},\"value\"" + ":{\"_choice\":\"printableString\",\"value\":\"STM TPM EK Intermediate C" + "A 05\"}}]]},\"validity\":{\"_type\":\"Validity\",\"notBefore\":{\"_choice\"" + ":\"utcTime\",\"value\":\"2018-12-14T00:00:00Z\"},\"notAfter\":{\"_choice\"" + ":\"utcTime\",\"value\":\"2028-12-14T00:00:00Z\"}},\"subject\":{\"_choice\"" + ":\"rdnSequence\",\"value\":[]},\"subjectPublicKeyInfo\":{\"_type\":\"Subj" + "ectPublicKeyInfo\",\"algorithm\":{\"_type\":\"AlgorithmIdentifier\",\"al" + "gorithm\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"1.2.840.113549.1.1." + "1\",\"components\":[1,2,840,113549,1,1,1],\"name\":\"id-pkcs1-rsaEncry" + "ption\"},\"parameters\":\"0500\"},\"subjectPublicKey\":\"2160:3082010A02" + "82010100CC14EB27A78CEB0EA486FA2DF7835F5FA8E905B097012B5BDE50380C" + "355B1A2A721BBC3D08DD21796CDB239FA95310651B1B56FD2CFE53C87352EBD9" + "96E33256160404CE9302A08066801E786A2F86E181F949966F492A85B58EAA4A" + "6A8CB3697551BB236E87CC7BF8EC1347871C91E15437E8F266BF1EA5EB271FDC" + "F374D8B47DF8BCE89E1FAD61C2A088CB4036B359CB72A294973FEDCCF0C340AF" + "FD14B64F041165581ACA34147C1C75617047058F7ED7D603E032508094FA73E8" + "B9153DA3BF255D2CBBC5DF301BA8F74D198BEBCE86040FC1D2927C7657414490" + "D802F482F3EBF2DE35EE149A1A6DE8D16891FBFBA02A18AFE59F9D6F149744E5" + "F0D559B10203010001\"},\"issuerUniqueID\":null,\"subjectUniqueID\":nul" + "l,\"extensions\":[{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT I" + "DENTIFIER\",\"oid\":\"2.5.29.35\",\"components\":[2,5,29,35],\"name\":\"id" + "-x509-ce-authorityKeyIdentifier\"},\"critical\":false,\"extnValue\":\"" + "301680141ADB994AB58BE57A0CC9B900E7851E1A43C08660\",\"_extnValue_ch" + "oice\":\"ext-AuthorityKeyIdentifier\",\"_extnValue\":{\"_type\":\"Author" + "ityKeyIdentifier\",\"keyIdentifier\":\"1ADB994AB58BE57A0CC9B900E7851" + "E1A43C08660\",\"authorityCertIssuer\":null,\"authorityCertSerialNumb" + "er\":null}},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTI" + "FIER\",\"oid\":\"2.5.29.32\",\"components\":[2,5,29,32],\"name\":\"id-x509" + "-ce-certificatePolicies\"},\"critical\":false,\"extnValue\":\"30393037" + "0604551D2000302F302D06082B060105050702011621687474703A2F2F777777" + "2E73742E636F6D2F54504D2F7265706F7369746F72792F\",\"_extnValue_choi" + "ce\":\"ext-CertificatePolicies\",\"_extnValue\":[{\"_type\":\"PolicyInfo" + "rmation\",\"policyIdentifier\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"" + "2.5.29.32.0\",\"components\":[2,5,29,32,0],\"name\":\"id-x509-ce-certi" + "ficatePolicies-anyPolicy\"},\"policyQualifiers\":[{\"_type\":\"PolicyQ" + "ualifierInfo\",\"policyQualifierId\":{\"_type\":\"OBJECT IDENTIFIER\",\"" + "oid\":\"1.3.6.1.5.5.7.2.1\",\"components\":[1,3,6,1,5,5,7,2,1],\"name\"" + ":\"id-pkix-qt-cps\"},\"qualifier\":\"1621687474703A2F2F7777772E73742E" + "636F6D2F54504D2F7265706F7369746F72792F\",\"_qualifier_choice\":\"pq-" + "CPS\"}]}]},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIF" + "IER\",\"oid\":\"2.5.29.17\",\"components\":[2,5,29,17],\"name\":\"id-x509-" + "ce-subjectAltName\"},\"critical\":true,\"extnValue\":\"304DA44B3049311" + "63014060567810502010C0B69643A35333534344432303117301506056781050" + "2020C0C53543333485450484148433031163014060567810502030C0B69643A3" + "030343930303038\",\"_extnValue_choice\":\"ext-SubjectAltName\",\"_extn" + "Value\":[{\"_choice\":\"directoryName\",\"value\":{\"_choice\":\"rdnSequen" + "ce\",\"value\":[[{\"_type\":\"AttributeTypeAndValue\",\"type\":{\"_type\":\"" + "OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.1\",\"components\":[2,23,133,2" + ",1],\"name\":\"tcg-at-tpmManufacturer\"},\"value\":{\"_choice\":\"utf8Str" + "ing\",\"value\":\"id:53544D20\"}}],[{\"_type\":\"AttributeTypeAndValue\"," + "\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.2\",\"compon" + "ents\":[2,23,133,2,2],\"name\":\"tcg-at-tpmModel\"},\"value\":{\"_choice" + "\":\"utf8String\",\"value\":\"ST33HTPHAHC0\"}}],[{\"_type\":\"AttributeTyp" + "eAndValue\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2" + ".3\",\"components\":[2,23,133,2,3],\"name\":\"tcg-at-tpmVersion\"},\"val" + "ue\":{\"_choice\":\"utf8String\",\"value\":\"id:00490008\"}}]]}}]},{\"_typ" + "e\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5." + "29.9\",\"components\":[2,5,29,9],\"name\":\"id-x509-ce-subjectDirector" + "yAttributes\"},\"critical\":false,\"extnValue\":\"305E3017060567810502" + "10310E300C0C03322E300201000202008A304306056781050212313A30380201" + "000101FFA0030A0101A1030A0100A2030A0100A310300E1603332E310A01040A" + "01020101FFA40F300D16053134302D320A0102010100\",\"_extnValue_choice" + "\":\"ext-SubjectDirectoryAttributes\",\"_extnValue\":[{\"_type\":\"Attri" + "buteSet\",\"type\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.1" + "6\",\"components\":[2,23,133,2,16],\"name\":\"tcg-at-tpmSpecification\"" + "},\"values\":[\"300C0C03322E300201000202008A\"],\"_values_choice\":\"at" + "-TPMSpecification\",\"_values\":[{\"_type\":\"TPMSpecification\",\"famil" + "y\":\"2.0\",\"level\":0,\"revision\":138}]},{\"_type\":\"AttributeSet\",\"ty" + "pe\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.23.133.2.18\",\"componen" + "ts\":[2,23,133,2,18],\"name\":\"tcg-at-tpmSecurityAssertions\"},\"valu" + "es\":[\"30380201000101FFA0030A0101A1030A0100A2030A0100A310300E1603" + "332E310A01040A01020101FFA40F300D16053134302D320A0102010100\"],\"_v" + "alues_choice\":\"at-TPMSecurityAssertions\",\"_values\":[{\"_type\":\"TP" + "MSecurityAssertions\",\"version\":0,\"fieldUpgradable\":true,\"ekGener" + "ationType\":\"ekgt-injected\",\"ekGenerationLocation\":\"tpmManufactur" + "er\",\"ekCertificateGenerationLocation\":\"tpmManufacturer\",\"ccInfo\"" + ":{\"_type\":\"CommonCriteriaMeasures\",\"version\":\"3.1\",\"assurancelev" + "el\":\"ealevel4\",\"evaluationStatus\":\"evaluationCompleted\",\"plus\":t" + "rue,\"strengthOfFunction\":null,\"profileOid\":null,\"profileUri\":nul" + "l,\"targetOid\":null,\"targetUri\":null},\"fipsLevel\":{\"_type\":\"FIPSL" + "evel\",\"version\":\"140-2\",\"level\":\"sllevel2\",\"plus\":false},\"iso900" + "0Certified\":false,\"iso9000Uri\":null}]}]},{\"_type\":\"Extension\",\"e" + "xtnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"2.5.29.15\",\"component" + "s\":[2,5,29,15],\"name\":\"id-x509-ce-keyUsage\"},\"critical\":true,\"ex" + "tnValue\":\"03020520\",\"_extnValue_choice\":\"ext-KeyUsage\",\"_extnVal" + "ue\":[\"keyEncipherment\"]},{\"_type\":\"Extension\",\"extnID\":{\"_type\":" + "\"OBJECT IDENTIFIER\",\"oid\":\"2.5.29.19\",\"components\":[2,5,29,19],\"" + "name\":\"id-x509-ce-basicConstraints\"},\"critical\":true,\"extnValue\"" + ":\"3000\",\"_extnValue_choice\":\"ext-BasicConstraints\",\"_extnValue\":" + "{\"_type\":\"BasicConstraints\",\"cA\":false,\"pathLenConstraint\":null}" + "},{\"_type\":\"Extension\",\"extnID\":{\"_type\":\"OBJECT IDENTIFIER\",\"oi" + "d\":\"2.5.29.37\",\"components\":[2,5,29,37],\"name\":\"id-x509-ce-extKe" + "yUsage\"},\"critical\":false,\"extnValue\":\"300706056781050801\",\"_ext" + "nValue_choice\":\"ext-ExtKeyUsage\",\"_extnValue\":[{\"_type\":\"OBJECT " + "IDENTIFIER\",\"oid\":\"2.23.133.8.1\",\"components\":[2,23,133,8,1],\"na" + "me\":\"tcg-kp-EKCertificate\"}]},{\"_type\":\"Extension\",\"extnID\":{\"_t" + "ype\":\"OBJECT IDENTIFIER\",\"oid\":\"1.3.6.1.5.5.7.1.1\",\"components\":" + "[1,3,6,1,5,5,7,1,1],\"name\":\"id-pkix-pe-authorityInfoAccess\"},\"cr" + "itical\":false,\"extnValue\":\"303C303A06082B06010505073002862E68747" + "4703A2F2F7365637572652E676C6F62616C7369676E2E636F6D2F73746D74706" + "D656B696E7430352E637274\",\"_extnValue_choice\":\"ext-AuthorityInfoA" + "ccess\",\"_extnValue\":[{\"_type\":\"AccessDescription\",\"accessMethod\"" + ":{\"_type\":\"OBJECT IDENTIFIER\",\"oid\":\"1.3.6.1.5.5.7.48.2\",\"compon" + "ents\":[1,3,6,1,5,5,7,48,2],\"name\":\"id-pkix-ad-caIssuers\"},\"acces" + "sLocation\":{\"_choice\":\"uniformResourceIdentifier\",\"value\":\"http:" + "//secure.globalsign.com/stmtpmekint05.crt\"}}]}]},\"signatureAlgor" + "ithm\":{\"_type\":\"AlgorithmIdentifier\",\"algorithm\":{\"_type\":\"OBJEC" + "T IDENTIFIER\",\"oid\":\"1.2.840.113549.1.1.11\",\"components\":[1,2,84" + "0,113549,1,1,11],\"name\":\"id-pkcs1-sha256WithRSAEncryption\"},\"par" + "ameters\":\"0500\"},\"signatureValue\":\"2048:3D4C381E5B4F1BCBE09C63D5" + "2F1F04570CAEA142FD9CD942043B11F8E3BDCF50007AE16CF8869013041E92CD" + "D3280BA4B51FBBD40582ED750219E261A695095674855AACEB520ADAFF9E7E90" + "8480A39CDCF900462D9171960FFE55D3AC49E8C981341BBD2EFBCC252A4C18A4" + "F3B7C84CCE42CE70A208C84D2630A7ABFBE72D6271E75B9FF1C971D20EB3DBD7" + "63F1E04D834EAA692D2E4001BBF4730A3E3FDA9711AE386524D91C63BE0E516D" + "00D5C6141FCCF6C539F3518E180049865BE16B69CAE1F8CB7FDC474B38F7EE56" + "CBE7D8A89D9BA99B65D5265AEF32AA62426B10E6D75BB8677EC44F755BBC2806" + "FD2B4E04BDF5D44259DBEAA42B6F563DF7AA7506\"" + "}" + }; + heim_octet_string os; + Certificate c0, c1; + size_t i, nknown, size; + char *s; + int ret; + + /* + * Test automatic decoding of open types. + * + * Decode a value that has plenty of open types with values of known + * alternatives in them, then check that we got what we wanted. + */ + ret = decode_Certificate(encoded_sample, sizeof(encoded_sample), + &c0, &size); + if (ret) + return 1; + if (size != sizeof(encoded_sample)) + return 1; + + s = print_Certificate(&c0, 0); + if (!s) + return 1; + if (strcmp(s, cert_json) != 0) + return 1; + free(s); + + ret = copy_Certificate(&c0, &c1); + if (ret) + return 1; + + if (!c0.tbsCertificate.extensions || !c1.tbsCertificate.extensions) + return 1; + if (!c0.tbsCertificate.extensions->len || + c0.tbsCertificate.extensions->len != c1.tbsCertificate.extensions->len) + return 1; + for (i = nknown = 0; i < c0.tbsCertificate.extensions->len; i++) { + if (c0.tbsCertificate.extensions->val[i]._ioschoice_extnValue.element != + c1.tbsCertificate.extensions->val[i]._ioschoice_extnValue.element) + return 1; + if (c0.tbsCertificate.extensions->val[i]._ioschoice_extnValue.element) { +#if 0 + fprintf(stderr, "extension %llu known %u\n", + (unsigned long long)i, + c0.tbsCertificate.extensions->val[i]._ioschoice_extnValue._element); +#endif + nknown++; + } + } + if (!nknown) + return 1; + + + /* + * Check that this round trips. But note that this attempt to encode will + * ignore the automatically decoded open type values from above because + * their encodings are still present. + */ + ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, &c1, &size, ret); + if (ret) + return 1; + if (os.length != size || size != sizeof(encoded_sample)) + return 1; + if (memcmp(os.data, encoded_sample, os.length) != 0) + return 1; + der_free_octet_string(&os); + + /* + * Test automatic encoding of open types by clearing the encoding of one + * such open type value, forcing the encoder to encode the value from + * before. + */ + der_free_octet_string(&c0.tbsCertificate.extensions->val[0].extnValue); + der_free_oid(&c0.tbsCertificate.extensions->val[0].extnID); + + ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, &c0, &size, ret); + if (ret) + return 1; + if (os.length != size || size != sizeof(encoded_sample)) + return 1; + if (memcmp(os.data, encoded_sample, os.length) != 0) + return 1; + der_free_octet_string(&os); + + /* + * Repeat, but with the copy, as this will test that copying data + * structures with decoded open types in them also copies those. + */ + der_free_octet_string(&c1.tbsCertificate.extensions->val[0].extnValue); + der_free_oid(&c1.tbsCertificate.extensions->val[0].extnID); + + ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, &c1, &size, ret); + if (ret) + return 1; + if (os.length != size || size != sizeof(encoded_sample)) + return 1; + if (memcmp(os.data, encoded_sample, os.length) != 0) + return 1; + der_free_octet_string(&os); + + free_Certificate(&c0); + free_Certificate(&c1); + return 0; +} +#endif + +int +main(int argc, char **argv) +{ + int ret = 0; + +#define DO_ONE(t) if (t()) { fprintf(stderr, "%s() failed!\n", #t); ret++; } + DO_ONE(test_principal); + DO_ONE(test_authenticator); + DO_ONE(test_krb_error); + DO_ONE(test_Name); + DO_ONE(test_bit_string); + DO_ONE(test_bit_string_rfc1510); + DO_ONE(test_time); + DO_ONE(test_cert); + + DO_ONE(check_tag_length); + DO_ONE(check_tag_length64); + DO_ONE(check_tag_length64s); + DO_ONE(test_large_tag); + DO_ONE(test_choice); + + DO_ONE(test_implicit); + + DO_ONE(test_taglessalloc); + DO_ONE(test_optional); + + DO_ONE(check_fail_largetag); + DO_ONE(check_fail_sequence); + DO_ONE(check_fail_choice); + DO_ONE(check_fail_Ticket); + + DO_ONE(check_seq); + DO_ONE(check_seq_of_size); + DO_ONE(test_SignedData); + + DO_ONE(check_TESTMechTypeList); + DO_ONE(test_seq4); + DO_ONE(test_seqof5); + + DO_ONE(test_x690sample); + + DO_ONE(test_default); + + DO_ONE(test_extensible_choice); + + DO_ONE(test_decorated_choice); + DO_ONE(test_decorated); + +#if ASN1_IOS_SUPPORTED + DO_ONE(test_ios); +#endif + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-gen.h b/third_party/heimdal/lib/asn1/check-gen.h new file mode 100644 index 0000000..df8c474 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-gen.h @@ -0,0 +1,9 @@ +#ifndef _CHECK_GEN_H +#define _CHECK_GEN_H +typedef struct my_vers_s { + int v; +} my_vers; + +int my_copy_vers(const my_vers *, my_vers *); +void my_free_vers(my_vers *); +#endif /* _CHECK_GEN_H */ diff --git a/third_party/heimdal/lib/asn1/check-template.c b/third_party/heimdal/lib/asn1/check-template.c new file mode 100644 index 0000000..ef5bd69 --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-template.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 1999 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <config.h> + +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <roken.h> + +#include <asn1-common.h> +#include <asn1_err.h> +#include <der.h> +#include <test_asn1.h> + +#include "check-common.h" +#include "der_locl.h" + +int +my_copy_vers(const my_vers *from, my_vers *to) +{ + *to = *from; + return 0; +} + +void +my_free_vers(my_vers *v) +{ + v->v = -1; +} + +static int +cmp_dummy (void *a, void *b) +{ + return 0; +} + +static int +test_uint64(void) +{ + struct test_case tests[] = { + { NULL, 3, "\x02\x01\x00", "uint64 0" }, + { NULL, 7, "\x02\x05\x01\xff\xff\xff\xff", "uint64 1" }, + { NULL, 7, "\x02\x05\x02\x00\x00\x00\x00", "uint64 2" }, + { NULL, 9, "\x02\x07\x7f\xff\xff\xff\xff\xff\xff", "uint64 3" }, + { NULL, 10, "\x02\x08\x00\x80\x00\x00\x00\x00\x00\x00", "uint64 4" }, + { NULL, 10, "\x02\x08\x7f\xff\xff\xff\xff\xff\xff\xff", "uint64 5" }, + { NULL, 11, "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", "uint64 6" } + }; + + size_t i; + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTuint64 values[] = { 0, 8589934591LL, 8589934592LL, + 36028797018963967LL, 36028797018963968LL, + 9223372036854775807LL, 18446744073709551615ULL }; + + for (i = 0; i < ntests; i++) + tests[i].val = &values[i]; + + if (sizeof(TESTuint64) != sizeof(uint64_t)) { + ret += 1; + printf("sizeof(TESTuint64) %d != sizeof(uint64_t) %d\n", + (int)sizeof(TESTuint64), (int)sizeof(uint64_t)); + } + + ret += generic_test (tests, ntests, sizeof(TESTuint64), + (generic_encode)encode_TESTuint64, + (generic_length)length_TESTuint64, + (generic_decode)decode_TESTuint64, + (generic_free)free_TESTuint64, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqofseq(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqofseq 0" }, + { NULL, 9, + "\x30\x07\x30\x05\xa0\x03\x02\x01\x00", + "seqofseq 1" }, + { NULL, 16, + "\x30\x0e\x30\x05\xa0\x03\x02\x01\x00\x30\x05\xa0\x03\x02\x01\x01", + "seqofseq 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOfSeq c0, c1, c2; + struct TESTSeqOfSeq_val i[2]; + + i[0].zero = 0; + i[1].zero = 1; + + c0.len = 0; + c0.val = NULL; + tests[0].val = &c0; + + c1.len = 1; + c1.val = i; + tests[1].val = &c1; + + c2.len = 2; + c2.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOfSeq), + (generic_encode)encode_TESTSeqOfSeq, + (generic_length)length_TESTSeqOfSeq, + (generic_decode)decode_TESTSeqOfSeq, + (generic_free)free_TESTSeqOfSeq, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqofseq2(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqofseq2 0" }, + { NULL, 11, + "\x30\x09\x30\x07\xa0\x05\x1b\x03\x65\x74\x74", + "seqofseq2 1" }, + { NULL, 21, + "\x30\x13\x30\x07\xa0\x05\x1b\x03\x65\x74\x74\x30\x08\xa0" + "\x06\x1b\x04\x74\x76\x61\x61", + "seqofseq2 2" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOfSeq2 c0, c1, c2; + struct TESTSeqOfSeq2_val i[2]; + + i[0].string = "ett"; + i[1].string = "tvaa"; + + c0.len = 0; + c0.val = NULL; + tests[0].val = &c0; + + c1.len = 1; + c1.val = i; + tests[1].val = &c1; + + c2.len = 2; + c2.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOfSeq2), + (generic_encode)encode_TESTSeqOfSeq2, + (generic_length)length_TESTSeqOfSeq2, + (generic_decode)decode_TESTSeqOfSeq2, + (generic_free)free_TESTSeqOfSeq2, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqof2(void) +{ + struct test_case tests[] = { + { NULL, 4, + "\x30\x02\x30\x00", + "seqof2 1" }, + { NULL, 9, + "\x30\x07\x30\x05\x1b\x03\x66\x6f\x6f", + "seqof2 2" }, + { NULL, 14, + "\x30\x0c\x30\x0a\x1b\x03\x66\x6f\x6f\x1b\x03\x62\x61\x72", + "seqof2 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf2 c0, c1, c2; + heim_general_string i[2]; + + i[0] = "foo"; + i[1] = "bar"; + + c0.strings.val = NULL; + c0.strings.len = 0; + tests[0].val = &c0; + + c1.strings.len = 1; + c1.strings.val = i; + tests[1].val = &c1; + + c2.strings.len = 2; + c2.strings.val = i; + tests[2].val = &c2; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf2), + (generic_encode)encode_TESTSeqOf2, + (generic_length)length_TESTSeqOf2, + (generic_decode)decode_TESTSeqOf2, + (generic_free)free_TESTSeqOf2, + cmp_dummy, + NULL); + return ret; +} + +static int +test_seqof3(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seqof3 0" }, + { NULL, 4, + "\x30\x02\x30\x00", + "seqof3 1" }, + { NULL, 9, + "\x30\x07\x30\x05\x1b\x03\x66\x6f\x6f", + "seqof3 2" }, + { NULL, 14, + "\x30\x0c\x30\x0a\x1b\x03\x66\x6f\x6f\x1b\x03\x62\x61\x72", + "seqof3 3" } + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf3 c0, c1, c2, c3; + struct TESTSeqOf3_strings s1, s2, s3; + heim_general_string i[2]; + + i[0] = "foo"; + i[1] = "bar"; + + c0.strings = NULL; + tests[0].val = &c0; + + s1.val = NULL; + s1.len = 0; + c1.strings = &s1; + tests[1].val = &c1; + + s2.len = 1; + s2.val = i; + c2.strings = &s2; + tests[2].val = &c2; + + s3.len = 2; + s3.val = i; + c3.strings = &s3; + tests[3].val = &c3; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf3), + (generic_encode)encode_TESTSeqOf3, + (generic_length)length_TESTSeqOf3, + (generic_decode)decode_TESTSeqOf3, + (generic_free)free_TESTSeqOf3, + cmp_dummy, + NULL); + return ret; +} + + +static int +test_seqof4(void) +{ + struct test_case tests[] = { + { NULL, 2, + "\x30\x00", + "seq4 0" }, + { NULL, 4, + "\x30\x02" "\xa1\x00", + "seq4 1" }, + { NULL, 8, + "\x30\x06" "\xa0\x02\x30\x00" "\xa1\x00", + "seq4 2" }, + { NULL, 2 + (2 + 0x18) + (2 + 0x27) + (2 + 0x31), + "\x30\x76" /* 2 SEQ */ + "\xa0\x18\x30\x16" /* 4 [0] SEQ */ + "\x30\x14" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\xa1\x27" /* 2 [1] IMPL SEQ */ + "\x30\x25" /* 2 SEQ */ + "\x02\x01\x01" /* 3 INT */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\xa2\x31" /* 2 [2] IMPL SEQ */ + "\x30\x2f" /* 2 SEQ */ + "\x04\x00" /* 2 OCTET-STRING */ + "\x02\x01\x01" /* 3 INT */ + "\x04\x02\x01\x02" /* 4 OCTET-STRING */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff" + /* 11 INT */ + "\x04\x04\x00\x01\x02\x03" /* 6 OCTET-STRING */ + "\x02\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00" + /* 11 INT */ + "\x04\x01\x00" /* 3 OCTET-STRING */ + "\x02\x05\x01\x00\x00\x00\x00", /* 7 INT */ + "seq4 3" }, + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf4 c[4]; + struct TESTSeqOf4_b1 b1[4]; + struct TESTSeqOf4_b2 b2[4]; + struct TESTSeqOf4_b3 b3[4]; + struct TESTSeqOf4_b1_val b1val[4]; + struct TESTSeqOf4_b2_val b2val[4]; + struct TESTSeqOf4_b3_val b3val[4]; + + c[0].b1 = NULL; + c[0].b2 = NULL; + c[0].b3 = NULL; + tests[0].val = &c[0]; + + b2[1].len = 0; + b2[1].val = NULL; + c[1].b1 = NULL; + c[1].b2 = &b2[1]; + c[1].b3 = NULL; + tests[1].val = &c[1]; + + b1[2].len = 0; + b1[2].val = NULL; + b2[2].len = 0; + b2[2].val = NULL; + c[2].b1 = &b1[2]; + c[2].b2 = &b2[2]; + c[2].b3 = NULL; + tests[2].val = &c[2]; + + b1val[3].s1.data = ""; + b1val[3].s1.length = 0; + b1val[3].u1 = 1LL; + b1val[3].s2.data = "\x01\x02"; + b1val[3].s2.length = 2; + b1val[3].u2 = (TESTuint64)-1LL; + + b2val[3].s1.data = ""; + b2val[3].s1.length = 0; + b2val[3].u1 = 1LL; + b2val[3].s2.data = "\x01\x02"; + b2val[3].s2.length = 2; + b2val[3].u2 = (TESTuint64)-1LL; + b2val[3].s3.data = "\x00\x01\x02\x03"; + b2val[3].s3.length = 4; + b2val[3].u3 = 1ULL<<63; + + b3val[3].s1.data = ""; + b3val[3].s1.length = 0; + b3val[3].u1 = 1LL; + b3val[3].s2.data = "\x01\x02"; + b3val[3].s2.length = 2; + b3val[3].u2 = (TESTuint64)-1LL; + b3val[3].s3.data = "\x00\x01\x02\x03"; + b3val[3].s3.length = 4; + b3val[3].u3 = 1ULL<<63; + b3val[3].s4.data = "\x00"; + b3val[3].s4.length = 1; + b3val[3].u4 = 1LL<<32; + + b1[3].len = 1; + b1[3].val = &b1val[3]; + b2[3].len = 1; + b2[3].val = &b2val[3]; + b3[3].len = 1; + b3[3].val = &b3val[3]; + c[3].b1 = &b1[3]; + c[3].b2 = &b2[3]; + c[3].b3 = &b3[3]; + tests[3].val = &c[3]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf4), + (generic_encode)encode_TESTSeqOf4, + (generic_length)length_TESTSeqOf4, + (generic_decode)decode_TESTSeqOf4, + (generic_free)free_TESTSeqOf4, + cmp_dummy, + NULL); + return ret; +} + +static int +cmp_test_seqof5 (void *a, void *b) +{ + TESTSeqOf5 *aval = a; + TESTSeqOf5 *bval = b; + + IF_OPT_COMPARE(aval, bval, outer) { + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u0); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s0); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u1); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s1); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u2); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s2); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u3); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s3); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u4); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s4); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u5); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s5); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u6); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s6); + COMPARE_INTEGER(&aval->outer->inner, &bval->outer->inner, u7); + COMPARE_OCTET_STRING(&aval->outer->inner, &bval->outer->inner, s7); + } + return 0; +} + +static int +test_seqof5(void) +{ + struct test_case tests[] = { + { NULL, 2, "\x30\x00", "seq5 0" }, + { NULL, 126, + "\x30\x7c" /* SEQ */ + "\x30\x7a" /* SEQ */ + "\x30\x78" /* SEQ */ + "\x02\x01\x01" /* INT 1 */ + "\x04\x06\x01\x01\x01\x01\x01\x01" /* "\0x1"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfe" /* INT ~1 */ + "\x04\x06\x02\x02\x02\x02\x02\x02" /* "\x02"x6 */ + "\x02\x01\x02" /* INT 2 */ + "\x04\x06\x03\x03\x03\x03\x03\x03" /* "\x03"x6 */ + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfd" /* INT ~2 */ + "\x04\x06\x04\x04\x04\x04\x04\x04" /* ... */ + "\x02\x01\x03" + "\x04\x06\x05\x05\x05\x05\x05\x05" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfc" + "\x04\x06\x06\x06\x06\x06\x06\x06" + "\x02\x01\x04" + "\x04\x06\x07\x07\x07\x07\x07\x07" + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xfb" + "\x04\x06\x08\x08\x08\x08\x08\x08", + "seq5 1" }, + }; + + int ret = 0, ntests = sizeof(tests) / sizeof(*tests); + TESTSeqOf5 c[2]; + struct TESTSeqOf5_outer outer; + struct TESTSeqOf5_outer_inner inner; + TESTuint64 u[8]; + heim_octet_string s[8]; + int i; + + c[0].outer = NULL; + tests[0].val = &c[0]; + + for (i = 0; i < 8; ++i) { + u[i] = (i&1) == 0 ? i/2+1 : ~(i/2+1); + s[i].data = memset(malloc(s[i].length = 6), i+1, 6); + } + + inner.u0 = u[0]; inner.u1 = u[1]; inner.u2 = u[2]; inner.u3 = u[3]; + inner.u4 = u[4]; inner.u5 = u[5]; inner.u6 = u[6]; inner.u7 = u[7]; + inner.s0 = s[0]; inner.s1 = s[1]; inner.s2 = s[2]; inner.s3 = s[3]; + inner.s4 = s[4]; inner.s5 = s[5]; inner.s6 = s[6]; inner.s7 = s[7]; + + outer.inner = inner; + c[1].outer = &outer; + tests[1].val = &c[1]; + + ret += generic_test (tests, ntests, sizeof(TESTSeqOf5), + (generic_encode)encode_TESTSeqOf5, + (generic_length)length_TESTSeqOf5, + (generic_decode)decode_TESTSeqOf5, + (generic_free)free_TESTSeqOf5, + cmp_test_seqof5, + NULL); + + for (i = 0; i < 8; ++i) + free(s[i].data); + + return ret; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_uint64(); + ret += test_seqofseq(); + ret += test_seqofseq2(); + ret += test_seqof2(); + ret += test_seqof3(); + ret += test_seqof4(); + ret += test_seqof5(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/check-timegm.c b/third_party/heimdal/lib/asn1/check-timegm.c new file mode 100644 index 0000000..13d3abc --- /dev/null +++ b/third_party/heimdal/lib/asn1/check-timegm.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <der_locl.h> + +RCSID("$Id$"); + +static int +test_timegm(void) +{ + int ret = 0; + struct tm tm; + time_t t; + + memset(&tm, 0, sizeof(tm)); + tm.tm_year = 106; + tm.tm_mon = 9; + tm.tm_mday = 1; + tm.tm_hour = 10; + tm.tm_min = 3; + + t = _der_timegm(&tm); + if (t != 1159696980) + ret += 1; + + tm.tm_mday = 0; + t = _der_timegm(&tm); + if (t != -1) + ret += 1; + + _der_gmtime(1159696980, &tm); + if (tm.tm_year != 106 || + tm.tm_mon != 9 || + tm.tm_mday != 1 || + tm.tm_hour != 10 || + tm.tm_min != 3 || + tm.tm_sec != 0) + errx(1, "tmtime failes"); + + return ret; +} + +int +main(int argc, char **argv) +{ + int ret = 0; + + ret += test_timegm(); + + return ret; +} diff --git a/third_party/heimdal/lib/asn1/cms.asn1 b/third_party/heimdal/lib/asn1/cms.asn1 new file mode 100644 index 0000000..ae547e5 --- /dev/null +++ b/third_party/heimdal/lib/asn1/cms.asn1 @@ -0,0 +1,149 @@ +-- From RFC 3369 -- +-- $Id$ -- + +CMS DEFINITIONS ::= BEGIN + +IMPORTS CertificateSerialNumber, AlgorithmIdentifier, Name, + Attribute, Certificate, SubjectKeyIdentifier FROM rfc2459 + HEIM_ANY FROM heim; + +id-pkcs7 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs7(7) } + +id-pkcs7-data OBJECT IDENTIFIER ::= { id-pkcs7 1 } +id-pkcs7-signedData OBJECT IDENTIFIER ::= { id-pkcs7 2 } +id-pkcs7-envelopedData OBJECT IDENTIFIER ::= { id-pkcs7 3 } +id-pkcs7-signedAndEnvelopedData OBJECT IDENTIFIER ::= { id-pkcs7 4 } +id-pkcs7-digestedData OBJECT IDENTIFIER ::= { id-pkcs7 5 } +id-pkcs7-encryptedData OBJECT IDENTIFIER ::= { id-pkcs7 6 } + +CMSVersion ::= INTEGER { + cMSVersion-v0(0), + cMSVersion-v1(1), + cMSVersion-v2(2), + cMSVersion-v3(3), + cMSVersion-v4(4) +} + +DigestAlgorithmIdentifier ::= AlgorithmIdentifier +DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier +SignatureAlgorithmIdentifier ::= AlgorithmIdentifier + +ContentType ::= OBJECT IDENTIFIER +MessageDigest ::= OCTET STRING + +ContentInfo ::= SEQUENCE { + contentType ContentType, + content [0] EXPLICIT HEIM_ANY OPTIONAL -- DEFINED BY contentType +} + +EncapsulatedContentInfo ::= SEQUENCE { + eContentType ContentType, + eContent [0] EXPLICIT OCTET STRING OPTIONAL +} + +CertificateSet ::= SET OF HEIM_ANY + +CertificateList ::= Certificate + +CertificateRevocationLists ::= SET OF CertificateList + +IssuerAndSerialNumber ::= SEQUENCE { + issuer Name, + serialNumber CertificateSerialNumber +} + +-- RecipientIdentifier is same as SignerIdentifier, +-- lets glue them togheter and save some bytes and share code for them + +CMSIdentifier ::= CHOICE { + issuerAndSerialNumber IssuerAndSerialNumber, + subjectKeyIdentifier [0] SubjectKeyIdentifier +} + +SignerIdentifier ::= CMSIdentifier +RecipientIdentifier ::= CMSIdentifier + +--- CMSAttributes are the combined UnsignedAttributes and SignedAttributes +--- to store space and share code + +CMSAttributes ::= SET OF Attribute -- SIZE (1..MAX) + +SignatureValue ::= OCTET STRING + +SignerInfo ::= SEQUENCE { + version CMSVersion, + sid SignerIdentifier, + digestAlgorithm DigestAlgorithmIdentifier, + signedAttrs [0] IMPLICIT CMSAttributes OPTIONAL, + signatureAlgorithm SignatureAlgorithmIdentifier, + signature SignatureValue, + unsignedAttrs [1] IMPLICIT CMSAttributes OPTIONAL +} + +SignerInfos ::= SET OF SignerInfo + +SignedData ::= SEQUENCE { + version CMSVersion, + digestAlgorithms DigestAlgorithmIdentifiers, + encapContentInfo EncapsulatedContentInfo, + certificates [0] IMPLICIT CertificateSet OPTIONAL, + crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + signerInfos SignerInfos +} + +OriginatorInfo ::= SEQUENCE { + certs [0] IMPLICIT CertificateSet OPTIONAL, + crls [1] IMPLICIT CertificateRevocationLists OPTIONAL +} + +KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier +ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + +EncryptedKey ::= OCTET STRING + +KeyTransRecipientInfo ::= SEQUENCE { + version CMSVersion, -- always set to 0 or 2 + rid RecipientIdentifier, + keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + encryptedKey EncryptedKey +} + +RecipientInfo ::= KeyTransRecipientInfo + +RecipientInfos ::= SET OF RecipientInfo + +EncryptedContent ::= OCTET STRING + +EncryptedContentInfo ::= SEQUENCE { + contentType ContentType, + contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + encryptedContent [0] IMPLICIT OCTET STRING OPTIONAL +} + +UnprotectedAttributes ::= SET OF Attribute -- SIZE (1..MAX) + +CMSEncryptedData ::= SEQUENCE { + version CMSVersion, + encryptedContentInfo EncryptedContentInfo, + unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL +} + +EnvelopedData ::= SEQUENCE { + version CMSVersion, + originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + recipientInfos RecipientInfos, + encryptedContentInfo EncryptedContentInfo, + unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL +} + +-- Data ::= OCTET STRING + +CMSRC2CBCParameter ::= SEQUENCE { + rc2ParameterVersion INTEGER (0..4294967295), + iv OCTET STRING -- exactly 8 octets +} + +CMSCBCParameter ::= OCTET STRING + +END diff --git a/third_party/heimdal/lib/asn1/cms.opt b/third_party/heimdal/lib/asn1/cms.opt new file mode 100644 index 0000000..49333e5 --- /dev/null +++ b/third_party/heimdal/lib/asn1/cms.opt @@ -0,0 +1,2 @@ +--decode-dce-ber +--sequence=DigestAlgorithmIdentifiers diff --git a/third_party/heimdal/lib/asn1/crmf.asn1 b/third_party/heimdal/lib/asn1/crmf.asn1 new file mode 100644 index 0000000..696a89b --- /dev/null +++ b/third_party/heimdal/lib/asn1/crmf.asn1 @@ -0,0 +1,110 @@ +-- $Id$ +PKCS10 DEFINITIONS ::= + +BEGIN + +IMPORTS + Time, + GeneralName, + SubjectPublicKeyInfo, + RelativeDistinguishedName, + AttributeTypeAndValue, + Extension, + AlgorithmIdentifier + FROM rfc2459 + HEIM_ANY + FROM heim; + +CRMFRDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +Controls ::= SEQUENCE -- SIZE(1..MAX) -- OF AttributeTypeAndValue + +PKMACValue ::= SEQUENCE { + algId AlgorithmIdentifier, + value BIT STRING +} + +-- XXX IMPLICIT brokenness +POPOSigningKeyInput ::= SEQUENCE { + authInfo CHOICE { + sender [0] IMPLICIT GeneralName, + publicKeyMAC PKMACValue + }, + publicKey SubjectPublicKeyInfo +} -- from CertTemplate + +-- XXX IMPLICIT brokenness +POPOSigningKey ::= SEQUENCE { + poposkInput [0] IMPLICIT POPOSigningKeyInput OPTIONAL, + algorithmIdentifier AlgorithmIdentifier, + signature BIT STRING } + +PBMParameter ::= SEQUENCE { + salt OCTET STRING, + owf AlgorithmIdentifier, + iterationCount INTEGER, + mac AlgorithmIdentifier +} + +SubsequentMessage ::= INTEGER { + encrCert (0), + challengeResp (1) +} + +POPOPrivKey ::= CHOICE { + thisMessage [0] BIT STRING, -- Deprecated + subsequentMessage [1] IMPLICIT SubsequentMessage, + dhMAC [2] BIT STRING, -- Deprecated + agreeMAC [3] IMPLICIT PKMACValue, + encryptedKey [4] HEIM_ANY +} + +ProofOfPossession ::= CHOICE { + raVerified [0] NULL, + signature [1] POPOSigningKey, + keyEncipherment [2] POPOPrivKey, + keyAgreement [3] POPOPrivKey +} + +CertTemplate ::= SEQUENCE { + version [0] INTEGER OPTIONAL, + serialNumber [1] INTEGER OPTIONAL, + signingAlg [2] SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters HEIM_ANY OPTIONAL + } -- AlgorithmIdentifier -- OPTIONAL, + issuer [3] IMPLICIT CHOICE { + rdnSequence CRMFRDNSequence + } -- Name -- OPTIONAL, + validity [4] SEQUENCE { + notBefore [0] Time OPTIONAL, + notAfter [1] Time OPTIONAL + } -- OptionalValidity -- OPTIONAL, + subject [5] IMPLICIT CHOICE { + rdnSequence CRMFRDNSequence + } -- Name -- OPTIONAL, + publicKey [6] IMPLICIT SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING OPTIONAL + } -- SubjectPublicKeyInfo -- OPTIONAL, + issuerUID [7] IMPLICIT BIT STRING OPTIONAL, + subjectUID [8] IMPLICIT BIT STRING OPTIONAL, + extensions [9] IMPLICIT SEQUENCE OF Extension OPTIONAL +} + +CertRequest ::= SEQUENCE { + certReqId INTEGER, + certTemplate CertTemplate, + controls Controls OPTIONAL +} + +CertReqMsg ::= SEQUENCE { + certReq CertRequest, + popo ProofOfPossession OPTIONAL, + regInfo SEQUENCE OF AttributeTypeAndValue OPTIONAL } + +CertReqMessages ::= SEQUENCE OF CertReqMsg + + +END + diff --git a/third_party/heimdal/lib/asn1/crmf.opt b/third_party/heimdal/lib/asn1/crmf.opt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/heimdal/lib/asn1/crmf.opt diff --git a/third_party/heimdal/lib/asn1/der.c b/third_party/heimdal/lib/asn1/der.c new file mode 100644 index 0000000..bea4ae5 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <com_err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <getarg.h> +#include <err.h> + +RCSID("$Id$"); + + +static const char *class_names[] = { + "UNIV", /* 0 */ + "APPL", /* 1 */ + "CONTEXT", /* 2 */ + "PRIVATE" /* 3 */ +}; + +static const char *type_names[] = { + "PRIM", /* 0 */ + "CONS" /* 1 */ +}; + +static const char *tag_names[] = { + "EndOfContent", /* 0 */ + "Boolean", /* 1 */ + "Integer", /* 2 */ + "BitString", /* 3 */ + "OctetString", /* 4 */ + "Null", /* 5 */ + "ObjectID", /* 6 */ + NULL, /* 7 */ + NULL, /* 8 */ + NULL, /* 9 */ + "Enumerated", /* 10 */ + NULL, /* 11 */ + "UTF8String", /* 12 */ + NULL, /* 13 */ + NULL, /* 14 */ + NULL, /* 15 */ + "Sequence", /* 16 */ + "Set", /* 17 */ + NULL, /* 18 */ + "PrintableString", /* 19 */ + NULL, /* 20 */ + NULL, /* 21 */ + "IA5String", /* 22 */ + "UTCTime", /* 23 */ + "GeneralizedTime", /* 24 */ + NULL, /* 25 */ + "VisibleString", /* 26 */ + "GeneralString", /* 27 */ + NULL, /* 28 */ + NULL, /* 29 */ + "BMPString" /* 30 */ +}; + +static int +get_type(const char *name, const char *list[], unsigned len) +{ + unsigned i; + for (i = 0; i < len; i++) + if (list[i] && strcasecmp(list[i], name) == 0) + return i; + return -1; +} + +#define SIZEOF_ARRAY(a) (sizeof((a))/sizeof((a)[0])) + +const char * ASN1CALL +der_get_class_name(unsigned num) +{ + if (num >= SIZEOF_ARRAY(class_names)) + return NULL; + return class_names[num]; +} + +int ASN1CALL +der_get_class_num(const char *name) +{ + return get_type(name, class_names, SIZEOF_ARRAY(class_names)); +} + +const char * ASN1CALL +der_get_type_name(unsigned num) +{ + if (num >= SIZEOF_ARRAY(type_names)) + return NULL; + return type_names[num]; +} + +int ASN1CALL +der_get_type_num(const char *name) +{ + return get_type(name, type_names, SIZEOF_ARRAY(type_names)); +} + +const char * ASN1CALL +der_get_tag_name(unsigned num) +{ + if (num >= SIZEOF_ARRAY(tag_names)) + return NULL; + return tag_names[num]; +} + +int ASN1CALL +der_get_tag_num(const char *name) +{ + return get_type(name, tag_names, SIZEOF_ARRAY(tag_names)); +} diff --git a/third_party/heimdal/lib/asn1/der.h b/third_party/heimdal/lib/asn1/der.h new file mode 100644 index 0000000..ec5603e --- /dev/null +++ b/third_party/heimdal/lib/asn1/der.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __DER_H__ +#define __DER_H__ + +#include <stdint.h> + +typedef enum { + ASN1_C_UNIV = 0, + ASN1_C_APPL = 1, + ASN1_C_CONTEXT = 2, + ASN1_C_PRIVATE = 3 +} Der_class; + +typedef enum {PRIM = 0, CONS = 1} Der_type; + +#define MAKE_TAG(CLASS, TYPE, TAG) (((CLASS) << 6) | ((TYPE) << 5) | (TAG)) + +/* Universal tags */ + +enum { + UT_EndOfContent = 0, + UT_Boolean = 1, + UT_Integer = 2, + UT_BitString = 3, + UT_OctetString = 4, + UT_Null = 5, + UT_OID = 6, + UT_Enumerated = 10, + UT_UTF8String = 12, + UT_Sequence = 16, + UT_Set = 17, + UT_PrintableString = 19, + UT_IA5String = 22, + UT_UTCTime = 23, + UT_GeneralizedTime = 24, + UT_VisibleString = 26, + UT_GeneralString = 27, + UT_UniversalString = 28, + UT_BMPString = 30, + /* unsupported types */ + UT_ObjectDescriptor = 7, + UT_External = 8, + UT_Real = 9, + UT_EmbeddedPDV = 11, + UT_RelativeOID = 13, + UT_NumericString = 18, + UT_TeletexString = 20, + UT_VideotexString = 21, + UT_GraphicString = 25 +}; + +#define ASN1_INDEFINITE 0xdce0deed + +typedef struct heim_der_time_t { + time_t dt_sec; + unsigned long dt_nsec; +} heim_der_time_t; + +typedef struct heim_ber_time_t { + time_t bt_sec; + unsigned bt_nsec; + int bt_zone; +} heim_ber_time_t; + +struct asn1_template; + +#include <der-protos.h> + +int _heim_fix_dce(size_t reallen, size_t *len); +int _heim_der_set_sort(const void *, const void *); +int _heim_time2generalizedtime (time_t, heim_octet_string *, int); + +#endif /* __DER_H__ */ diff --git a/third_party/heimdal/lib/asn1/der_cmp.c b/third_party/heimdal/lib/asn1/der_cmp.c new file mode 100644 index 0000000..f745270 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_cmp.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2003-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +int ASN1CALL +der_heim_oid_cmp(const heim_oid *p, const heim_oid *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->components, + q->components, + p->length * sizeof(*p->components)); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->components, + q->components, + p->length * sizeof(*p->components))) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->components, + q->components, + q->length * sizeof(*p->components))) == 0) + return 1; + return c; +} + +int ASN1CALL +der_heim_octet_string_cmp(const heim_octet_string *p, + const heim_octet_string *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->data, q->data, p->length); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->data, q->data, p->length)) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->data, q->data, q->length)) == 0) + return 1; + return c; +} + +int ASN1CALL +der_printable_string_cmp(const heim_printable_string *p, + const heim_printable_string *q) +{ + return der_heim_octet_string_cmp(p, q); +} + +int ASN1CALL +der_ia5_string_cmp(const heim_ia5_string *p, + const heim_ia5_string *q) +{ + return der_heim_octet_string_cmp(p, q); +} + +int ASN1CALL +der_heim_bit_string_cmp(const heim_bit_string *p, + const heim_bit_string *q) +{ + unsigned char pc, qc; + size_t bits; + int c = 0; + + /* Compare prefix */ + if (p->length == 0 && q->length == 0) + return 0; + if (p->length > 7 && q->length > 7) { + if (p->length < q->length) + c = memcmp(p->data, q->data, p->length / 8); + else + c = memcmp(p->data, q->data, q->length / 8); + } + if (c) + return c; + + /* Prefixes are equal, c == 0 */ + + if (p->length == q->length && p->length % 8 == 0) + return 0; + if (p->length == 0 && q->length) + return -1; /* No trailing bits of p to compare to corresponding bits of q */ + if (q->length == 0 && p->length) + return 1; /* No trailing bits of q to compare to corresponding bits of p */ + + /* c == 0, lengths are not equal, both are at least 1 bit */ + pc = ((unsigned char *)p->data)[p->length / 8]; + qc = ((unsigned char *)q->data)[q->length / 8]; + if (p->length < q->length) + bits = p->length % 8; + else + bits = q->length % 8; + + if (bits > 0) { + if ((pc & 0x80) == 0 && (qc & 0x80) != 0) + return -1; + if ((pc & 0x80) != 0 && (qc & 0x80) == 0) + return 1; + } + if (bits > 1) { + if ((pc & 0x40) == 0 && (qc & 0x40) != 0) + return -1; + if ((pc & 0x40) != 0 && (qc & 0x40) == 0) + return 1; + } + if (bits > 2) { + if ((pc & 0x20) == 0 && (qc & 0x20) != 0) + return -1; + if ((pc & 0x20) != 0 && (qc & 0x20) == 0) + return 1; + } + if (bits > 3) { + if ((pc & 0x10) == 0 && (qc & 0x10) != 0) + return -1; + if ((pc & 0x10) != 0 && (qc & 0x10) == 0) + return 1; + } + if (bits > 4) { + if ((pc & 0x08) == 0 && (qc & 0x08) != 0) + return -1; + if ((pc & 0x08) != 0 && (qc & 0x08) == 0) + return 1; + } + if (bits > 5) { + if ((pc & 0x04) == 0 && (qc & 0x04) != 0) + return -1; + if ((pc & 0x04) != 0 && (qc & 0x04) == 0) + return 1; + } + if (bits > 6) { + if ((pc & 0x02) == 0 && (qc & 0x02) != 0) + return -1; + if ((pc & 0x02) != 0 && (qc & 0x02) == 0) + return 1; + } + /* + * `bits' can't be 8. + * + * All leading `bits' bits of the tail of the shorter of `p' or `q' are + * equal. + */ + if (p->length < q->length) + return -1; + if (q->length < p->length) + return 1; + return 0; +} + +int ASN1CALL +der_heim_integer_cmp(const heim_integer *p, + const heim_integer *q) +{ + if (p->negative != q->negative) + return q->negative - p->negative; + if (p->length != q->length) + return (int)(p->length - q->length); + return memcmp(p->data, q->data, p->length); +} + +int ASN1CALL +der_heim_bmp_string_cmp(const heim_bmp_string *p, const heim_bmp_string *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->data, q->data, p->length * sizeof(q->data[0])); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->data, q->data, p->length * sizeof(q->data[0]))) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->data, q->data, q->length * sizeof(q->data[0]))) == 0) + return 1; + return c; +} + +int ASN1CALL +der_heim_universal_string_cmp(const heim_universal_string *p, + const heim_universal_string *q) +{ + int c; + + if (p->length == q->length) { + if (p->length == 0) + return 0; + return memcmp(p->data, q->data, p->length * sizeof(q->data[0])); + } + if (p->length < q->length) { + if (p->length == 0 || + (c = memcmp(p->data, q->data, p->length * sizeof(q->data[0]))) == 0) + return -1; + return c; + } + if (q->length == 0 || + (c = memcmp(p->data, q->data, q->length * sizeof(q->data[0]))) == 0) + return 1; + return c; +} diff --git a/third_party/heimdal/lib/asn1/der_copy.c b/third_party/heimdal/lib/asn1/der_copy.c new file mode 100644 index 0000000..f67fff6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_copy.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +int ASN1CALL +der_copy_general_string (const heim_general_string *from, + heim_general_string *to) +{ + *to = strdup(*from); + if(*to == NULL) + return ENOMEM; + return 0; +} + +int ASN1CALL +der_copy_integer (const int *from, int *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_integer64 (const int64_t *from, int64_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_unsigned (const unsigned *from, unsigned *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_unsigned64 (const uint64_t *from, uint64_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_generalized_time (const time_t *from, time_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_utctime (const time_t *from, time_t *to) +{ + *to = *from; + return 0; +} + +int ASN1CALL +der_copy_utf8string (const heim_utf8_string *from, heim_utf8_string *to) +{ + return der_copy_general_string(from, to); +} + +int ASN1CALL +der_copy_printable_string (const heim_printable_string *from, + heim_printable_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + to->data = malloc(from->length + 1); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length); + ((char *)to->data)[to->length] = '\0'; + return 0; +} + +int ASN1CALL +der_copy_ia5_string (const heim_ia5_string *from, + heim_ia5_string *to) +{ + return der_copy_printable_string(from, to); +} + +int ASN1CALL +der_copy_bmp_string (const heim_bmp_string *from, heim_bmp_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, sizeof(from->data[0])); + else + to->data = malloc(from->length * sizeof(from->data[0])); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length * sizeof(to->data[0])); + return 0; +} + +int ASN1CALL +der_copy_universal_string (const heim_universal_string *from, + heim_universal_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, sizeof(from->data[0])); + else + to->data = malloc(from->length * sizeof(from->data[0])); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length * sizeof(to->data[0])); + return 0; +} + +int ASN1CALL +der_copy_visible_string (const heim_visible_string *from, + heim_visible_string *to) +{ + return der_copy_general_string(from, to); +} + +int ASN1CALL +der_copy_octet_string (const heim_octet_string *from, heim_octet_string *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) { + if (from->data == NULL) { + *to = *from; + return 0; + } + to->data = calloc(1, 1); + } else + to->data = malloc(from->length); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length); + return 0; +} + +int ASN1CALL +der_copy_heim_integer (const heim_integer *from, heim_integer *to) +{ + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + if (from->length == 0) + to->data = calloc(1, 1); + else + to->data = malloc(from->length); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (to->length > 0) + memcpy(to->data, from->data, to->length); + to->negative = from->negative; + return 0; +} + +int ASN1CALL +der_copy_oid (const heim_oid *from, heim_oid *to) +{ + if (from->length == 0) { + to->length = 0; + to->components = calloc(1, sizeof(*from->components)); + if (to->components == NULL) + return ENOMEM; + return 0; + } + assert(from->components != NULL); + to->components = malloc(from->length * sizeof(*from->components)); + if (to->components == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + memcpy(to->components, from->components, + to->length * sizeof(*to->components)); + return 0; +} + +int ASN1CALL +der_copy_bit_string (const heim_bit_string *from, heim_bit_string *to) +{ + size_t len; + + assert(from->length == 0 || (from->length > 0 && from->data != NULL)); + + len = (from->length + 7) / 8; + if (len == 0) + to->data = calloc(1, 1); + else + to->data = malloc(len); + if (to->data == NULL) { + to->length = 0; + return ENOMEM; + } + to->length = from->length; + if (len > 0) + memcpy(to->data, from->data, len); + return 0; +} diff --git a/third_party/heimdal/lib/asn1/der_format.c b/third_party/heimdal/lib/asn1/der_format.c new file mode 100644 index 0000000..bb4a7ce --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_format.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <hex.h> + +RCSID("$Id$"); + +int ASN1CALL +der_parse_hex_heim_integer (const char *p, heim_integer *data) +{ + ssize_t len; + + data->length = 0; + data->negative = 0; + data->data = NULL; + + if (*p == '-') { + p++; + data->negative = 1; + } + + len = strlen(p); + if (len <= 0) { + data->data = NULL; + data->length = 0; + return EINVAL; + } + + data->length = (len / 2) + 1; + data->data = malloc(data->length); + if (data->data == NULL) { + data->length = 0; + return ENOMEM; + } + + len = hex_decode(p, data->data, data->length); + if (len < 0) { + free(data->data); + data->data = NULL; + data->length = 0; + return EINVAL; + } + + { + unsigned char *q = data->data; + while(len > 0 && *q == 0) { + q++; + len--; + } + data->length = len; + memmove(data->data, q, len); + } + return 0; +} + +int ASN1CALL +der_print_hex_heim_integer (const heim_integer *data, char **p) +{ + ssize_t len; + char *q; + + len = hex_encode(data->data, data->length, p); + if (len < 0) + return ENOMEM; + + if (data->negative) { + len = asprintf(&q, "-%s", *p); + free(*p); + if (len < 0) + return ENOMEM; + *p = q; + } + return 0; +} + +int ASN1CALL +der_print_heim_oid (const heim_oid *oid, char delim, char **str) +{ + struct rk_strpool *p = NULL; + size_t i; + + if (oid->length == 0) + return EINVAL; + + for (i = 0; i < oid->length ; i++) { + p = rk_strpoolprintf(p, "%d", oid->components[i]); + if (p && i < oid->length - 1) + p = rk_strpoolprintf(p, "%c", delim); + if (p == NULL) { + *str = NULL; + return ENOMEM; + } + } + + *str = rk_strpoolcollect(p); + if (*str == NULL) + return ENOMEM; + return 0; +} + +int ASN1CALL +der_parse_heim_oid (const char *str, const char *sep, heim_oid *data) +{ + char *s, *w, *brkt, *endptr; + unsigned int *c; + long l; + + data->length = 0; + data->components = NULL; + + if (sep == NULL) + sep = "."; + + s = strdup(str); + + for (w = strtok_r(s, sep, &brkt); + w != NULL; + w = strtok_r(NULL, sep, &brkt)) { + + c = realloc(data->components, + (data->length + 1) * sizeof(data->components[0])); + if (c == NULL) { + der_free_oid(data); + free(s); + return ENOMEM; + } + data->components = c; + + l = strtol(w, &endptr, 10); + if (*endptr != '\0' || l < 0 || l > INT_MAX) { + der_free_oid(data); + free(s); + return EINVAL; + } + data->components[data->length++] = (unsigned int)l; + } + free(s); + return 0; +} diff --git a/third_party/heimdal/lib/asn1/der_free.c b/third_party/heimdal/lib/asn1/der_free.c new file mode 100644 index 0000000..d80406f --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_free.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +void ASN1CALL +der_free_general_string (heim_general_string *str) +{ + free(*str); + *str = NULL; +} + +void ASN1CALL +der_free_integer (int *i) +{ + *i = 0; +} + +void ASN1CALL +der_free_integer64 (int64_t *i) +{ + *i = 0; +} + +void ASN1CALL +der_free_unsigned (unsigned *u) +{ + *u = 0; +} + +void ASN1CALL +der_free_unsigned64 (uint64_t *u) +{ + *u = 0; +} + +void ASN1CALL +der_free_generalized_time(time_t *t) +{ + *t = 0; +} + +void ASN1CALL +der_free_utctime(time_t *t) +{ + *t = 0; +} + + +void ASN1CALL +der_free_utf8string (heim_utf8_string *str) +{ + free(*str); + *str = NULL; +} + +void ASN1CALL +der_free_printable_string (heim_printable_string *str) +{ + der_free_octet_string(str); +} + +void ASN1CALL +der_free_ia5_string (heim_ia5_string *str) +{ + der_free_octet_string(str); +} + +void ASN1CALL +der_free_bmp_string (heim_bmp_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_universal_string (heim_universal_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_visible_string (heim_visible_string *str) +{ + free(*str); + *str = NULL; +} + +void ASN1CALL +der_free_octet_string (heim_octet_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_heim_integer (heim_integer *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_oid (heim_oid *k) +{ + free(k->components); + k->components = NULL; + k->length = 0; +} + +void ASN1CALL +der_free_bit_string (heim_bit_string *k) +{ + free(k->data); + k->data = NULL; + k->length = 0; +} diff --git a/third_party/heimdal/lib/asn1/der_get.c b/third_party/heimdal/lib/asn1/der_get.c new file mode 100644 index 0000000..06564b7 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_get.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +/* + * All decoding functions take a pointer `p' to first position in + * which to read, from the left, `len' which means the maximum number + * of characters we are able to read, `ret' were the value will be + * returned and `size' where the number of used bytes is stored. + * Either 0 or an error code is returned. + */ + +int ASN1CALL +der_get_unsigned (const unsigned char *p, size_t len, + unsigned *ret, size_t *size) +{ + unsigned val = 0; + size_t oldlen = len; + + if (len == sizeof(val) + 1 && p[0] == 0) + ; + else if (len > sizeof(val)) + return ASN1_OVERRUN; + + while (len--) + val = val * 256 + *p++; + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_unsigned64 (const unsigned char *p, size_t len, + uint64_t *ret, size_t *size) +{ + uint64_t val = 0; + size_t oldlen = len; + + if (len == sizeof(val) + 1 && p[0] == 0) + ; + else if (len > sizeof(val)) + return ASN1_OVERRUN; + + while (len--) + val = val * 256 + *p++; + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_integer (const unsigned char *p, size_t len, + int *ret, size_t *size) +{ + int val = 0; + size_t oldlen = len; + + if (len == sizeof(val) + 1 && (p[0] == 0 || p[0] == 0xff)) + ; + else if (len > sizeof(val)) + return ASN1_OVERRUN; + + /* We assume we're on a twos-complement platform */ + if (len > 0) { + val = (signed char)*p++; + while (--len) + val = val * 256 + *p++; + } + *ret = val; + if(size) *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_integer64 (const unsigned char *p, size_t len, + int64_t *ret, size_t *size) +{ + int64_t val = 0; + size_t oldlen = len; + + if (len > sizeof(val)) + return ASN1_OVERRUN; + + /* We assume we're on a twos-complement platform */ + if (len > 0) { + val = (signed char)*p++; + while (--len) + val = val * 256 + *p++; + } + *ret = val; + if(size) *size = oldlen; + return 0; +} + + +int ASN1CALL +der_get_length (const unsigned char *p, size_t len, + size_t *val, size_t *size) +{ + size_t v; + + if (len <= 0) + return ASN1_OVERRUN; + --len; + v = *p++; + if (v < 128) { + *val = v; + if(size) *size = 1; + } else { + int e; + size_t l; + unsigned tmp; + + if(v == 0x80){ + *val = ASN1_INDEFINITE; + if(size) *size = 1; + return 0; + } + v &= 0x7F; + if (len < v) + return ASN1_OVERRUN; + e = der_get_unsigned (p, v, &tmp, &l); + if(e) return e; + *val = tmp; + if(size) *size = l + 1; + } + return 0; +} + +int ASN1CALL +der_get_boolean(const unsigned char *p, size_t len, int *data, size_t *size) +{ + if(len < 1) + return ASN1_OVERRUN; + if(*p != 0) + *data = 1; + else + *data = 0; + *size = 1; + return 0; +} + +int ASN1CALL +der_get_general_string (const unsigned char *p, size_t len, + heim_general_string *str, size_t *size) +{ + const unsigned char *p1; + char *s; + + assert(p != NULL); + + if (size) + *size = 0; + + p1 = memchr(p, 0, len); + if (p1 != NULL) { + /* + * Allow trailing NULs. We allow this since MIT Kerberos sends + * an strings in the NEED_PREAUTH case that includes a + * trailing NUL. + */ + while ((size_t)(p1 - p) < len && *p1 == '\0') + p1++; + if ((size_t)(p1 - p) != len) { + *str = NULL; + return ASN1_BAD_CHARACTER; + } + } + if (len == SIZE_MAX) { + *str = NULL; + return ASN1_BAD_LENGTH; + } + + *str = s = malloc (len + 1); + if (s == NULL) + return ENOMEM; + memcpy (s, p, len); + s[len] = '\0'; + + if(size) *size = len; + return 0; +} + +int ASN1CALL +der_get_utf8string (const unsigned char *p, size_t len, + heim_utf8_string *str, size_t *size) +{ + return der_get_general_string(p, len, str, size); +} + +#define gen_data_zero(_data) \ + do { (_data)->length = 0; (_data)->data = NULL; } while(0) + +int ASN1CALL +der_get_printable_string(const unsigned char *p, size_t len, + heim_printable_string *str, size_t *size) +{ + assert(p != NULL); + + if (size) + *size = 0; + + if (len == SIZE_MAX) { + gen_data_zero(str); + return ASN1_BAD_LENGTH; + } + str->length = len; + str->data = malloc(len + 1); + if (str->data == NULL) { + gen_data_zero(str); + return ENOMEM; + } + + memcpy(str->data, p, len); + ((char *)str->data)[len] = '\0'; + if(size) *size = len; + return 0; +} + +int ASN1CALL +der_get_ia5_string(const unsigned char *p, size_t len, + heim_ia5_string *str, size_t *size) +{ + return der_get_printable_string(p, len, str, size); +} + +int ASN1CALL +der_get_bmp_string (const unsigned char *p, size_t len, + heim_bmp_string *data, size_t *size) +{ + size_t i; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len & 1) { + gen_data_zero(data); + return ASN1_BAD_FORMAT; + } + data->length = len / 2; + if (data->length > UINT_MAX/sizeof(data->data[0])) { + gen_data_zero(data); + return ERANGE; + } + data->data = malloc(data->length * sizeof(data->data[0])); + if (data->data == NULL && data->length != 0) { + gen_data_zero(data); + return ENOMEM; + } + + for (i = 0; i < data->length; i++) { + data->data[i] = (p[0] << 8) | p[1]; + p += 2; + /* check for NUL in the middle of the string */ + if (data->data[i] == 0 && i != (data->length - 1)) { + free(data->data); + gen_data_zero(data); + return ASN1_BAD_CHARACTER; + } + } + if (size) *size = len; + + return 0; +} + +int ASN1CALL +der_get_universal_string (const unsigned char *p, size_t len, + heim_universal_string *data, size_t *size) +{ + size_t i; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len & 3) { + gen_data_zero(data); + return ASN1_BAD_FORMAT; + } + data->length = len / 4; + if (data->length > UINT_MAX/sizeof(data->data[0])) { + gen_data_zero(data); + return ERANGE; + } + data->data = malloc(data->length * sizeof(data->data[0])); + if (data->data == NULL && data->length != 0) { + gen_data_zero(data); + return ENOMEM; + } + + for (i = 0; i < data->length; i++) { + data->data[i] = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + p += 4; + /* check for NUL in the middle of the string */ + if (data->data[i] == 0 && i != (data->length - 1)) { + free(data->data); + gen_data_zero(data); + return ASN1_BAD_CHARACTER; + } + } + if (size) *size = len; + return 0; +} + +int ASN1CALL +der_get_visible_string (const unsigned char *p, size_t len, + heim_visible_string *str, size_t *size) +{ + return der_get_general_string(p, len, str, size); +} + +int ASN1CALL +der_get_octet_string (const unsigned char *p, size_t len, + heim_octet_string *data, size_t *size) +{ + assert(p != NULL); + + if (size) + *size = 0; + + if (len == 0) + data->data = malloc(1); + else + data->data = malloc(len); + if (data->data == NULL) { + data->length = 0; + return ENOMEM; + } + data->length = len; + memcpy (data->data, p, len); + if (size) + *size = len; + return 0; +} + +int ASN1CALL +der_get_octet_string_ber (const unsigned char *p, size_t len, + heim_octet_string *data, size_t *size) +{ + int e; + Der_type type; + Der_class cls; + unsigned int tag, depth = 0; + size_t l, datalen, oldlen = len; + + assert(p != NULL); + + if (size) + *size = 0; + + data->length = 0; + data->data = NULL; + + while (len) { + e = der_get_tag (p, len, &cls, &type, &tag, &l); + if (e) goto out; + if (cls != ASN1_C_UNIV) { + e = ASN1_BAD_ID; + goto out; + } + if (type == PRIM && tag == UT_EndOfContent) { + if (depth == 0) + break; + depth--; + } + if (tag != UT_OctetString) { + e = ASN1_BAD_ID; + goto out; + } + + p += l; + len -= l; + e = der_get_length (p, len, &datalen, &l); + if (e) goto out; + p += l; + len -= l; + + if (datalen > len) + return ASN1_OVERRUN; + + if (type == PRIM && datalen) { + void *ptr; + + ptr = realloc(data->data, data->length + datalen); + if (ptr == NULL) { + e = ENOMEM; + goto out; + } + data->data = ptr; + memcpy(((unsigned char *)data->data) + data->length, p, datalen); + data->length += datalen; + } else if (type != PRIM) + depth++; + + p += datalen; + len -= datalen; + } + if (depth != 0) + return ASN1_INDEF_OVERRUN; + if(size) *size = oldlen - len; + return 0; + out: + free(data->data); + data->data = NULL; + data->length = 0; + return e; +} + + +int ASN1CALL +der_get_heim_integer (const unsigned char *p, size_t len, + heim_integer *data, size_t *size) +{ + data->length = 0; + data->negative = 0; + data->data = NULL; + + if (size) + *size = 0; + + if (len == 0) + return 0; + + assert(p != NULL); + + if (p[0] & 0x80) { + unsigned char *q; + int carry = 1; + + + /* + * A negative number. It's going to be a twos complement byte array. + * We're going to leave the positive value in `data->data', but set the + * `data->negative' flag. That means we need to negate the + * twos-complement integer received. + */ + data->negative = 1; + data->length = len; + + if (p[0] == 0xff) { + if (data->length == 1) { + /* One byte of all ones == -1 */ + q = data->data = malloc(1); + *q = 1; + data->length = 1; + if (size) + *size = 1; + return 0; + } + + p++; + data->length--; + + /* + * We could check if the next byte's high bit is set, which would + * be an error ("illegal padding" in OpenSSL). However, this would + * mean failing to accept certificates made by certain CAs that + * would read 8 bytes of RNG into a buffer, slap on length 8, then + * slap on the tag [UNIVERSAL INTEGER], and make that the + * serialNumber field's encoding, which then fails to parse in + * around 1 in 256 certificates. + * + * So let's not. + * + * if (p[0] & 0x80) + * return ASN1_PARSE_ERROR; // or a new error code + */ + } + data->data = malloc(data->length); + if (data->data == NULL) { + data->length = 0; + if (size) + *size = 0; + return ENOMEM; + } + + /* + * Note that if `data->length' were zero, this would be UB because we + * underflow if data->length is zero even though we wouldn't actually + * dereference the byte before data->data. Thus we check above for + * that. + */ + q = &((unsigned char*)data->data)[data->length - 1]; + p += data->length - 1; + while (q >= (unsigned char*)data->data) { + /* *p XOR 0xff -> ~*p; we're dealing with twos complement */ + *q = *p ^ 0xff; + if (carry) + carry = !++*q; + p--; + q--; + } + } else { + data->negative = 0; + data->length = len; + + if (p[0] == 0) { + p++; + data->length--; + } + data->data = malloc(data->length); + if (data->data == NULL && data->length != 0) { + data->length = 0; + if (size) + *size = 0; + return ENOMEM; + } + memcpy(data->data, p, data->length); + } + if (size) + *size = len; + return 0; +} + +static int +generalizedtime2time (const char *s, time_t *t) +{ + struct tm tm; + + memset(&tm, 0, sizeof(tm)); + if (sscanf (s, "%04d%02d%02d%02d%02d%02dZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec) != 6) { + if (sscanf (s, "%02d%02d%02d%02d%02d%02dZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec) != 6) + return ASN1_BAD_TIMEFORMAT; + if (tm.tm_year < 50) + tm.tm_year += 2000; + else + tm.tm_year += 1900; + } + tm.tm_year -= 1900; + tm.tm_mon -= 1; + *t = _der_timegm (&tm); + return 0; +} + +static int ASN1CALL +der_get_time (const unsigned char *p, size_t len, + time_t *data, size_t *size) +{ + char *times; + int e; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len == SIZE_MAX || len == 0) + return ASN1_BAD_LENGTH; + + times = malloc(len + 1); + if (times == NULL) + return ENOMEM; + memcpy(times, p, len); + times[len] = '\0'; + e = generalizedtime2time(times, data); + free (times); + if(size) *size = len; + return e; +} + +int ASN1CALL +der_get_generalized_time (const unsigned char *p, size_t len, + time_t *data, size_t *size) +{ + return der_get_time(p, len, data, size); +} + +int ASN1CALL +der_get_utctime (const unsigned char *p, size_t len, + time_t *data, size_t *size) +{ + return der_get_time(p, len, data, size); +} + +int ASN1CALL +der_get_oid (const unsigned char *p, size_t len, + heim_oid *data, size_t *size) +{ + size_t n; + size_t oldlen = len; + + assert(p != NULL); + + if (size) + *size = 0; + + if (len < 1) + return ASN1_OVERRUN; + + if (len == SIZE_MAX) + return ASN1_BAD_LENGTH; + + if (len + 1 > UINT_MAX/sizeof(data->components[0])) + return ERANGE; + + data->components = malloc((len + 1) * sizeof(data->components[0])); + if (data->components == NULL) { + data->length = 0; + return ENOMEM; + } + data->components[0] = (*p) / 40; + data->components[1] = (*p) % 40; + --len; + ++p; + for (n = 2; len > 0; ++n) { + unsigned u = 0, u1; + + do { + --len; + u1 = u * 128 + (*p++ % 128); + /* check that we don't overflow the element */ + if (u1 < u) { + der_free_oid(data); + return ASN1_OVERRUN; + } + u = u1; + } while (len > 0 && p[-1] & 0x80); + data->components[n] = u; + } + if (n > 2 && p[-1] & 0x80) { + der_free_oid (data); + return ASN1_OVERRUN; + } + data->length = n; + if (size) + *size = oldlen; + return 0; +} + +int ASN1CALL +der_get_tag (const unsigned char *p, size_t len, + Der_class *cls, Der_type *type, + unsigned int *tag, size_t *size) +{ + size_t ret = 0; + + if (size) + *size = 0; + + if (len < 1) + return ASN1_MISSING_FIELD; + + assert(p != NULL); + + *cls = (Der_class)(((*p) >> 6) & 0x03); + *type = (Der_type)(((*p) >> 5) & 0x01); + *tag = (*p) & 0x1f; + p++; len--; ret++; + if(*tag == 0x1f) { + unsigned int continuation; + unsigned int tag1; + *tag = 0; + do { + if(len < 1) + return ASN1_OVERRUN; + continuation = *p & 128; + tag1 = *tag * 128 + (*p % 128); + /* check that we don't overflow the tag */ + if (tag1 < *tag) + return ASN1_OVERFLOW; + *tag = tag1; + p++; len--; ret++; + } while(continuation); + } + if(size) *size = ret; + return 0; +} + +int ASN1CALL +der_match_tag (const unsigned char *p, size_t len, + Der_class cls, Der_type type, + unsigned int tag, size_t *size) +{ + Der_type thistype; + int e; + + e = der_match_tag2(p, len, cls, &thistype, tag, size); + if (e) return e; + if (thistype != type) return ASN1_BAD_ID; + return 0; +} + +int ASN1CALL +der_match_tag2 (const unsigned char *p, size_t len, + Der_class cls, Der_type *type, + unsigned int tag, size_t *size) +{ + size_t l; + Der_class thisclass; + unsigned int thistag; + int e; + + if (size) + *size = 0; + + e = der_get_tag(p, len, &thisclass, type, &thistag, &l); + if (e) return e; + /* + * We do depend on ASN1_BAD_ID being returned in places where we're + * essentially implementing an application-level CHOICE where we try to + * decode one way then the other. In Heimdal this happens only in lib/hdb/ + * where we try to decode a blob as an hdb_entry, then as an + * hdb_entry_alias. Applications should really not depend on this. + */ + if (cls != thisclass && (cls == ASN1_C_APPL || thisclass == ASN1_C_APPL)) + return ASN1_BAD_ID; + if (cls != thisclass || tag != thistag) + return ASN1_MISSING_FIELD; + if (size) *size = l; + return 0; +} + +/* + * Returns 0 if the encoded data at `p' of length `len' starts with the tag of + * class `cls`, type `type', and tag value `tag', and puts the length of the + * payload (i.e., the length of V in TLV, not the length of TLV) in + * `*length_ret', and the size of the whole thing (the TLV) in `*size' if + * `size' is not NULL. + * + * Else returns an error. + */ +int ASN1CALL +der_match_tag_and_length (const unsigned char *p, size_t len, + Der_class cls, Der_type *type, unsigned int tag, + size_t *length_ret, size_t *size) +{ + size_t l, ret = 0; + int e; + + e = der_match_tag2 (p, len, cls, type, tag, &l); + if (e) return e; + p += l; + len -= l; + ret += l; + e = der_get_length (p, len, length_ret, &l); + if (e) return e; + if(size) *size = ret + l; + return 0; +} + + + +/* + * Old versions of DCE was based on a very early beta of the MIT code, + * which used MAVROS for ASN.1 encoding. MAVROS had the interesting + * feature that it encoded data in the forward direction, which has + * it's problems, since you have no idea how long the data will be + * until after you're done. MAVROS solved this by reserving one byte + * for length, and later, if the actual length was longer, it reverted + * to indefinite, BER style, lengths. The version of MAVROS used by + * the DCE people could apparently generate correct X.509 DER encodings, and + * did this by making space for the length after encoding, but + * unfortunately this feature wasn't used with Kerberos. + */ + +int +_heim_fix_dce(size_t reallen, size_t *len) +{ + if(reallen == ASN1_INDEFINITE) + return 1; + if(*len < reallen) + return -1; + *len = reallen; + return 0; +} + +int ASN1CALL +der_get_bit_string (const unsigned char *p, size_t len, + heim_bit_string *data, size_t *size) +{ + assert(p != NULL); + + if (size) + *size = 0; + + if (len < 1) + return ASN1_OVERRUN; + if (p[0] > 7) + return ASN1_BAD_FORMAT; + if (len - 1 == 0 && p[0] != 0) + return ASN1_BAD_FORMAT; + /* check if any of the three upper bits are set + * any of them will cause a interger overrun */ + if ((len - 1) >> (sizeof(len) * 8 - 3)) + return ASN1_OVERRUN; + /* + * If there is data to copy, do that now. + */ + if (len - 1 > 0) { + data->length = (len - 1) * 8; + data->data = malloc(len - 1); + if (data->data == NULL) { + data->length = 0; + return ENOMEM; + } + memcpy (data->data, p + 1, len - 1); + data->length -= p[0]; + } else { + data->data = NULL; + data->length = 0; + } + if(size) *size = len; + return 0; +} diff --git a/third_party/heimdal/lib/asn1/der_length.c b/third_party/heimdal/lib/asn1/der_length.c new file mode 100644 index 0000000..cd50df8 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_length.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +size_t +_heim_len_unsigned (unsigned val) +{ + size_t ret = 0; + int last_val_gt_128; + + do { + ++ret; + last_val_gt_128 = (val >= 128); + val /= 256; + } while (val); + + if(last_val_gt_128) + ret++; + + return ret; +} + +size_t +_heim_len_unsigned64 (uint64_t val) +{ + size_t ret = 0; + int last_val_gt_128; + + do { + ++ret; + last_val_gt_128 = (val >= 128); + val /= 256; + } while (val); + + if(last_val_gt_128) + ret++; + + return ret; +} + +size_t +_heim_len_int (int val) +{ + unsigned char q; + size_t ret = 0; + + if (val >= 0) { + do { + q = val % 256; + ret++; + val /= 256; + } while(val); + if(q >= 128) + ret++; + } else { + val = ~val; + do { + q = ~(val % 256); + ret++; + val /= 256; + } while(val); + if(q < 128) + ret++; + } + return ret; +} + +size_t +_heim_len_int64 (int64_t val) +{ + unsigned char q; + size_t ret = 0; + + if (val >= 0) { + do { + q = val % 256; + ret++; + val /= 256; + } while(val); + if(q >= 128) + ret++; + } else { + val = ~val; + do { + q = ~(val % 256); + ret++; + val /= 256; + } while(val); + if(q < 128) + ret++; + } + return ret; +} + +static size_t +len_oid (const heim_oid *oid) +{ + size_t ret = 1; + size_t n; + + for (n = 2; n < oid->length; ++n) { + unsigned u = oid->components[n]; + + do { + ++ret; + u /= 128; + } while(u > 0); + } + return ret; +} + +size_t ASN1CALL +der_length_len (size_t len) +{ + if (len < 128) + return 1; + else { + int ret = 0; + do { + ++ret; + len /= 256; + } while (len); + return ret + 1; + } +} + +size_t ASN1CALL +der_length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + +size_t ASN1CALL +der_length_integer (const int *data) +{ + return _heim_len_int (*data); +} + +size_t ASN1CALL +der_length_integer64 (const int64_t *data) +{ + return _heim_len_int64 (*data); +} + +size_t ASN1CALL +der_length_unsigned (const unsigned *data) +{ + return _heim_len_unsigned(*data); +} + +size_t ASN1CALL +der_length_unsigned64 (const uint64_t *data) +{ + return _heim_len_unsigned64(*data); +} + +size_t ASN1CALL +der_length_enumerated (const unsigned *data) +{ + return _heim_len_int (*data); +} + +size_t ASN1CALL +der_length_general_string (const heim_general_string *data) +{ + return strlen(*data); +} + +size_t ASN1CALL +der_length_utf8string (const heim_utf8_string *data) +{ + return strlen(*data); +} + +size_t ASN1CALL +der_length_printable_string (const heim_printable_string *data) +{ + return data->length; +} + +size_t ASN1CALL +der_length_ia5_string (const heim_ia5_string *data) +{ + return data->length; +} + +size_t ASN1CALL +der_length_bmp_string (const heim_bmp_string *data) +{ + return data->length * 2; +} + +size_t ASN1CALL +der_length_universal_string (const heim_universal_string *data) +{ + return data->length * 4; +} + +size_t ASN1CALL +der_length_visible_string (const heim_visible_string *data) +{ + return strlen(*data); +} + +size_t ASN1CALL +der_length_octet_string (const heim_octet_string *k) +{ + return k->length; +} + +size_t ASN1CALL +der_length_heim_integer (const heim_integer *k) +{ + if (k->length == 0) + return 1; + if (k->negative && k->length == 1 && ((unsigned char *)k->data)[0] == 1) + return 1; + else if (k->negative) + return k->length + (((~(((unsigned char *)k->data)[0])) & 0x80) ? 0 : 1); + else + return k->length + ((((unsigned char *)k->data)[0] & 0x80) ? 1 : 0); +} + +size_t ASN1CALL +der_length_oid (const heim_oid *k) +{ + return len_oid (k); +} + +size_t ASN1CALL +der_length_generalized_time (const time_t *t) +{ + heim_octet_string k; + size_t ret; + + _heim_time2generalizedtime (*t, &k, 1); + ret = k.length; + free(k.data); + return ret; +} + +size_t ASN1CALL +der_length_utctime (const time_t *t) +{ + heim_octet_string k; + size_t ret; + + _heim_time2generalizedtime (*t, &k, 0); + ret = k.length; + free(k.data); + return ret; +} + +size_t ASN1CALL +der_length_boolean (const int *k) +{ + return 1; +} + +size_t ASN1CALL +der_length_bit_string (const heim_bit_string *k) +{ + return (k->length + 7) / 8 + 1; +} diff --git a/third_party/heimdal/lib/asn1/der_locl.h b/third_party/heimdal/lib/asn1/der_locl.h new file mode 100644 index 0000000..a086e18 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_locl.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1997 - 2002, 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __DER_LOCL_H__ +#define __DER_LOCL_H__ + + +#include <config.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <ctype.h> +#include <time.h> +#include <errno.h> +#include <roken.h> + +#include <asn1-common.h> +#include <asn1_err.h> +#include <der.h> +#include <der-private.h> +#include "asn1-template.h" + +time_t _der_timegm (struct tm *); +struct tm * _der_gmtime(time_t t, struct tm *); +size_t _heim_len_unsigned (unsigned); +size_t _heim_len_int (int); + +#endif /* __DER_LOCL_H__ */ diff --git a/third_party/heimdal/lib/asn1/der_print.c b/third_party/heimdal/lib/asn1/der_print.c new file mode 100644 index 0000000..dada747 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_print.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2021 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include "hex.h" + +RCSID("$Id$"); + +char * ASN1CALL +der_print_general_string(const heim_general_string *str, int flags) +{ + return strdup(*str); +} + +char * ASN1CALL +der_print_boolean(const int *i, int flags) +{ + return *i ? strdup("true") : strdup("false"); +} + +char * ASN1CALL +der_print_integer(const int *i, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%d", *i) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_integer64(const int64_t *i, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%lld", (long long)*i) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_unsigned(const unsigned *u, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%u", *u) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_unsigned64(const uint64_t *u, int flags) +{ + char *s = NULL; + + if (asprintf(&s, "%llu", (long long)*u) == -1 || s == NULL) + return NULL; + return s; +} + +char * ASN1CALL +der_print_generalized_time(const time_t *t, int flags) +{ + struct tm tms; + char str[sizeof("1970-01-01T00:00:00Z")]; + +#ifdef WIN32 + if (gmtime_s(&tms, t) != 0 || + strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", &tms) == 0) + return NULL; +#else + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_r(t, &tms)) == 0) + return NULL; +#endif + return strdup(str); +} + +char * ASN1CALL +der_print_utctime(const time_t *t, int flags) +{ + struct tm tms; + char str[sizeof("1970-01-01T00:00:00Z")]; + +#ifdef WIN32 + if (gmtime_s(&tms, t) != 0 || + strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", &tms) == 0) + return NULL; +#else + if (strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%SZ", gmtime_r(t, &tms)) == 0) + return NULL; +#endif + return strdup(str); +} + + +char * ASN1CALL +der_print_utf8string(const heim_utf8_string *str, int flags) +{ + return strdup(*str); +} + +char * ASN1CALL +der_print_printable_string(const heim_printable_string *str, int flags) +{ + return strndup(str->data, str->length); +} + +char * ASN1CALL +der_print_ia5_string(const heim_ia5_string *str, int flags) +{ + return strndup(str->data, str->length); +} + +char * ASN1CALL +der_print_bmp_string(const heim_bmp_string *k, int flags) +{ + return strdup("<BMPString-not-supported>"); +} + +char * ASN1CALL +der_print_universal_string(const heim_universal_string *k, int flags) +{ + return strdup("<UniversalString-not-supported>"); +} + +char * ASN1CALL +der_print_visible_string(const heim_visible_string *str, int flags) +{ + return strdup(*str); +} + +char * ASN1CALL +der_print_octet_string(const heim_octet_string *k, int flags) +{ + char *s = NULL; + + (void) hex_encode(k->data, k->length, &s); + return s; +} + +char * ASN1CALL +der_print_heim_integer(const heim_integer *k, int flags) +{ + char *s = NULL; + + (void) der_print_hex_heim_integer(k, &s); + return s; +} + +char * ASN1CALL +der_print_oid(const heim_oid *k, int flags) +{ + struct rk_strpool *r = NULL; + const char *sym = NULL; + char *s = NULL; + size_t i; + + (void) der_print_heim_oid(k, '.', &s); + + if (!s) + return NULL; + r = rk_strpoolprintf(r, "{\"_type\":\"OBJECT IDENTIFIER\"," + "\"oid\":\"%s\"," + "\"components\":[", + s); + free(s); + for (i = 0; i < k->length; i++) + r = rk_strpoolprintf(r, "%s%u", i ? "," : "", k->components[i]); + if (r) + r = rk_strpoolprintf(r, "]"); + (void) der_find_heim_oid_by_oid(k, &sym); + if (sym && r) { + if ((s = strdup(sym))) { + for (i = 0; s[i]; i++) + if (s[i] == '_') + s[i] = '-'; + } + r = rk_strpoolprintf(r, ",\"name\":\"%s\"", s ? s : sym); + free(s); + } + if (r) + r = rk_strpoolprintf(r, "}"); + return rk_strpoolcollect(r); +} + +char * ASN1CALL +der_print_bit_string(const heim_bit_string *k, int flags) +{ + char *s2 = NULL; + char *s = NULL; + + (void) hex_encode(k->data, k->length / 8, &s); + if (asprintf(&s2, "%llu:%s", (unsigned long long)k->length, s) == -1 || !s2) + s2 = NULL; + free(s); + return s2; +} diff --git a/third_party/heimdal/lib/asn1/der_put.c b/third_party/heimdal/lib/asn1/der_put.c new file mode 100644 index 0000000..106d456 --- /dev/null +++ b/third_party/heimdal/lib/asn1/der_put.c @@ -0,0 +1,717 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +RCSID("$Id$"); + +/* + * All encoding functions take a pointer `p' to first position in + * which to write, from the right, `len' which means the maximum + * number of characters we are able to write. The function returns + * the number of characters written in `size' (if non-NULL). + * The return value is 0 or an error. + */ + +int ASN1CALL +der_put_unsigned (unsigned char *p, size_t len, const unsigned *v, size_t *size) +{ + unsigned char *base = p; + unsigned val = *v; + + *size = 0; + + if (val) { + while (len > 0 && val) { + *p-- = val % 256; + val /= 256; + --len; + } + if (val != 0) + return ASN1_OVERFLOW; + else { + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + } + *size = base - p; + return 0; + } + } else if (len < 1) + return ASN1_OVERFLOW; + else { + *p = 0; + *size = 1; + return 0; + } +} + +int ASN1CALL +der_put_unsigned64 (unsigned char *p, size_t len, const uint64_t *v, size_t *size) +{ + unsigned char *base = p; + uint64_t val = *v; + + *size = 0; + + if (val) { + while (len > 0 && val) { + *p-- = val % 256; + val /= 256; + --len; + } + if (val != 0) + return ASN1_OVERFLOW; + else { + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + } + *size = base - p; + return 0; + } + } else if (len < 1) + return ASN1_OVERFLOW; + else { + *p = 0; + *size = 1; + return 0; + } +} + +int ASN1CALL +der_put_integer (unsigned char *p, size_t len, const int *v, size_t *size) +{ + unsigned char *base = p; + int val = *v; + + *size = 0; + + if(val >= 0) { + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = val % 256; + len--; + val /= 256; + } while(val); + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + len--; + } + } else { + val = ~val; + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = ~(val % 256); + len--; + val /= 256; + } while(val); + if(p[1] < 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + } + } + *size = base - p; + return 0; +} + +int ASN1CALL +der_put_integer64 (unsigned char *p, size_t len, const int64_t *v, size_t *size) +{ + unsigned char *base = p; + int64_t val = *v; + + *size = 0; + + if(val >= 0) { + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = val % 256; + len--; + val /= 256; + } while(val); + if(p[1] >= 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + len--; + } + } else { + val = ~val; + do { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = ~(val % 256); + len--; + val /= 256; + } while(val); + if(p[1] < 128) { + if(len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + } + } + *size = base - p; + return 0; +} + + +int ASN1CALL +der_put_length (unsigned char *p, size_t len, size_t val, size_t *size) +{ + if (size) + *size = 0; + + if (len < 1) + return ASN1_OVERFLOW; + + if (val < 128) { + *p = val; + if (size) + *size = 1; + } else { + size_t l = 0; + + while(val > 0) { + if(len < 2) + return ASN1_OVERFLOW; + *p-- = val % 256; + val /= 256; + len--; + l++; + } + *p = 0x80 | l; + if(size) + *size = l + 1; + } + return 0; +} + +int ASN1CALL +der_put_boolean(unsigned char *p, size_t len, const int *data, size_t *size) +{ + *size = 0; + + if(len < 1) + return ASN1_OVERFLOW; + if(*data != 0) + *p = 0xff; + else + *p = 0; + *size = 1; + return 0; +} + +int ASN1CALL +der_put_general_string (unsigned char *p, size_t len, + const heim_general_string *str, size_t *size) +{ + size_t slen; + + assert(p != NULL && str != NULL && *str != NULL && size != NULL); + *size = 0; + slen = strlen(*str); + if (len < slen) + return ASN1_OVERFLOW; + p -= slen; + memcpy (p+1, *str, slen); + *size = slen; + return 0; +} + +int ASN1CALL +der_put_utf8string (unsigned char *p, size_t len, + const heim_utf8_string *str, size_t *size) +{ + return der_put_general_string(p, len, str, size); +} + +int ASN1CALL +der_put_printable_string (unsigned char *p, size_t len, + const heim_printable_string *str, size_t *size) +{ + return der_put_octet_string(p, len, str, size); +} + +int ASN1CALL +der_put_ia5_string (unsigned char *p, size_t len, + const heim_ia5_string *str, size_t *size) +{ + return der_put_octet_string(p, len, str, size); +} + +int ASN1CALL +der_put_bmp_string (unsigned char *p, size_t len, + const heim_bmp_string *data, size_t *size) +{ + size_t i; + + assert(p != NULL && data != NULL); + + if (size) + *size = 0; + + if (len / 2 < data->length) + return ASN1_OVERFLOW; + p -= data->length * 2; + for (i = 0; i < data->length; i++) { + p[1] = (data->data[i] >> 8) & 0xff; + p[2] = data->data[i] & 0xff; + p += 2; + } + if (size) *size = data->length * 2; + return 0; +} + +int ASN1CALL +der_put_universal_string (unsigned char *p, size_t len, + const heim_universal_string *data, size_t *size) +{ + size_t i; + + if (size) + *size = 0; + + if (len / 4 < data->length) + return ASN1_OVERFLOW; + p -= data->length * 4; + for (i = 0; i < data->length; i++) { + p[1] = (data->data[i] >> 24) & 0xff; + p[2] = (data->data[i] >> 16) & 0xff; + p[3] = (data->data[i] >> 8) & 0xff; + p[4] = data->data[i] & 0xff; + p += 4; + } + if (size) *size = data->length * 4; + return 0; +} + +int ASN1CALL +der_put_visible_string (unsigned char *p, size_t len, + const heim_visible_string *str, size_t *size) +{ + return der_put_general_string(p, len, str, size); +} + +int ASN1CALL +der_put_octet_string (unsigned char *p, size_t len, + const heim_octet_string *data, size_t *size) +{ + assert(p != NULL && data != NULL && size != NULL); + + *size = 0; + if (len < data->length) + return ASN1_OVERFLOW; + p -= data->length; + if (data->length) + memcpy(p+1, data->data, data->length); + *size = data->length; + return 0; +} + +int ASN1CALL +der_put_heim_integer (unsigned char *p, size_t len, + const heim_integer *data, size_t *size) +{ + unsigned char *buf; + int hibitset = 0; + + assert(p != NULL); + + if (size) + *size = 0; + + if (data->length == 0) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 0; + if (size) + *size = 1; + return 0; + } + if (len < data->length) + return ASN1_OVERFLOW; + + assert(data->data != NULL); + buf = data->data; + len -= data->length; + + if (data->negative) { + ssize_t i; + int carry; + + /* + * We represent the parsed integer as a positive value with a + * negativity flag. But we need to put it on the wire as the shortest + * twos-complement byte sequence possible. So we're going to negate + * the number as go. + */ + if (data->length == 1 && *(unsigned char *)data->data == 1) { + *(p--) = 0xff; + } else { + for (i = data->length - 1, carry = 1; i >= 0; i--) { + *p = buf[i] ^ 0xff; + if (carry) + carry = !++*p; + p--; + } + if (p[1] < 128) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 0xff; + len--; + hibitset = 1; + } + } + } else { + p -= data->length; + memcpy(p + 1, buf, data->length); + + if (p[1] >= 128) { + if (len < 1) + return ASN1_OVERFLOW; + p[0] = 0; + len--; + hibitset = 1; + } + } + if (size) + *size = data->length + hibitset; + return 0; +} + +int ASN1CALL +der_put_generalized_time (unsigned char *p, size_t len, + const time_t *data, size_t *size) +{ + heim_octet_string k; + size_t l; + int e; + + e = _heim_time2generalizedtime (*data, &k, 1); + if (e) + return e; + e = der_put_octet_string(p, len, &k, &l); + free(k.data); + if(e) + return e; + if(size) + *size = l; + return 0; +} + +int ASN1CALL +der_put_utctime (unsigned char *p, size_t len, + const time_t *data, size_t *size) +{ + heim_octet_string k; + size_t l; + int e; + + e = _heim_time2generalizedtime (*data, &k, 0); + if (e) + return e; + e = der_put_octet_string(p, len, &k, &l); + free(k.data); + if(e) + return e; + if(size) + *size = l; + return 0; +} + +int ASN1CALL +der_put_oid (unsigned char *p, size_t len, + const heim_oid *data, size_t *size) +{ + unsigned char *base = p; + size_t n; + + for (n = data->length - 1; n >= 2; --n) { + unsigned u = data->components[n]; + + if (len < 1) + return ASN1_OVERFLOW; + *p-- = u % 128; + u /= 128; + --len; + while (u > 0) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 128 + u % 128; + u /= 128; + --len; + } + } + if (len < 1) + return ASN1_OVERFLOW; + *p-- = 40 * data->components[0] + data->components[1]; + *size = base - p; + return 0; +} + +/* + * Output a copy of the DER TLV at `p' with a different outermost tag. + * + * This is used in the implementation of IMPLICIT tags in generated decoder + * functions. + */ +int ASN1CALL +der_replace_tag(const unsigned char *p, size_t len, + unsigned char **out, size_t *outlen, + Der_class class, Der_type type, + unsigned int tag) +{ + Der_class found_class; + Der_type found_type; + unsigned int found_tag; + size_t payload_len, l, tag_len, len_len; + int e; + + assert(p != NULL && out != NULL && outlen != NULL); + + e = der_get_tag(p, len, &found_class, &found_type, &found_tag, &l); + if (e) + return e; + if (found_type != type) + return ASN1_TYPE_MISMATCH; + /* We don't care what found_class and found_tag are though */ + tag_len = der_length_tag(tag); + p += l; + len -= l; + e = der_get_length(p, len, &payload_len, &len_len); + if (e) + return e; + if (payload_len > len) + return ASN1_OVERFLOW; + /* + * `p' now points at the payload; `*out' + the length of the tag points at + * where we should copy the DER length and the payload. + */ + if ((*out = malloc(*outlen = tag_len + len_len + payload_len)) == NULL) + return ENOMEM; + memcpy(*out + tag_len, p, len_len + payload_len); + + /* Put the new tag */ + e = der_put_tag(*out + tag_len - 1, tag_len, class, type, tag, &l); + if (e) + return e; + if (l != tag_len) + return ASN1_OVERFLOW; + return 0; +} + +#if 0 +int ASN1CALL +der_encode_implicit(unsigned char *p, size_t len, + asn1_generic_encoder_f encoder, + void *obj, size_t *size, + Der_type type, + unsigned int ttag, Der_class iclass, unsigned int itag) +{ + size_t ttaglen = der_length_tag(ttag); + size_t itaglen = der_length_tag(itag); + size_t l; + unsigned char *p2; + int e; + + assert(p != NULL && size != NULL); + + /* Attempt to encode in place */ + e = encoder(p, len, obj, size); + if (e == 0) { + /* Fits! Rewrite tag, adjust reported size. */ + e = der_put_tag(p + ttaglen - 1, itaglen, iclass, type, itag, &l); + if (e == 0) { + (*size) -= ttaglen; + (*size) += itaglen; + } + return e; + } + if (e != ASN1_OVERFLOW || itaglen <= ttaglen) + return e; + + /* + * Did not fit because ttaglen > itaglen and this was the last / only thing + * being encoded in a buffer of just the right size. + */ + if ((p2 = malloc(len + ttaglen - itaglen)) == NULL) + e = ENOMEM; + if (e == 0) + e = encoder(p2 + len + ttaglen - itaglen - 1, len + ttaglen - itaglen, + obj, size); + if (e == 0) + e = der_put_tag(p2 + ttaglen - 1, itaglen, iclass, type, itag, &l); + if (e == 0) { + (*size) -= ttaglen; + (*size) += itaglen; + memcpy(p - *size, p2 + ttaglen - itaglen, *size); + } + free(p2); + return e; +} +#endif + +int ASN1CALL +der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + if (tag <= 30) { + if (len < 1) + return ASN1_OVERFLOW; + *p = MAKE_TAG(class, type, tag); + *size = 1; + } else { + size_t ret = 0; + unsigned int continuation = 0; + + do { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = tag % 128 | continuation; + len--; + ret++; + tag /= 128; + continuation = 0x80; + } while(tag > 0); + if (len < 1) + return ASN1_OVERFLOW; + *p-- = MAKE_TAG(class, type, 0x1f); + ret++; + *size = ret; + } + return 0; +} + +int ASN1CALL +der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val, + Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = der_put_length (p, len, len_val, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = der_put_tag (p, len, class, type, tag, &l); + if(e) + return e; + + ret += l; + *size = ret; + return 0; +} + +int +_heim_time2generalizedtime (time_t t, heim_octet_string *s, int gtimep) +{ + struct tm tm; + const size_t len = gtimep ? 15 : 13; + int bytes; + + s->data = NULL; + s->length = 0; + if (_der_gmtime(t, &tm) == NULL) + return ASN1_BAD_TIMEFORMAT; + s->data = malloc(len + 1); + if (s->data == NULL) + return ENOMEM; + s->length = len; + if (gtimep) + bytes = snprintf(s->data, len + 1, "%04d%02d%02d%02d%02d%02dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + else + bytes = snprintf(s->data, len + 1, "%02d%02d%02d%02d%02d%02dZ", + tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + if (bytes > len) + abort(); + + return 0; +} + +int ASN1CALL +der_put_bit_string (unsigned char *p, size_t len, + const heim_bit_string *data, size_t *size) +{ + size_t data_size; + + assert(p != NULL && data != NULL && size != NULL); + + *size = 0; + data_size = (data->length + 7) / 8; + if (len < data_size + 1) + return ASN1_OVERFLOW; + p -= data_size + 1; + + memcpy (p+2, data->data, data_size); + if (data->length && (data->length % 8) != 0) + p[1] = 8 - (data->length % 8); + else + p[1] = 0; + *size = data_size + 1; + return 0; +} + +int +_heim_der_set_sort(const void *a1, const void *a2) +{ + const heim_octet_string *s1, *s2; + int ret; + + assert(a1 != NULL && a2 != NULL); + s1 = a1; + s2 = a2; + ret = memcmp(s1->data, s2->data, + s1->length < s2->length ? s1->length : s2->length); + if (ret != 0) + return ret; + return (int)(s1->length - s2->length); +} diff --git a/third_party/heimdal/lib/asn1/digest.asn1 b/third_party/heimdal/lib/asn1/digest.asn1 new file mode 100644 index 0000000..7a73993 --- /dev/null +++ b/third_party/heimdal/lib/asn1/digest.asn1 @@ -0,0 +1,179 @@ +-- $Id$ + +DIGEST DEFINITIONS ::= +BEGIN + +IMPORTS EncryptedData, Principal FROM krb5; + +DigestTypes ::= BIT STRING { + ntlm-v1(0), + ntlm-v1-session(1), + ntlm-v2(2), + digest-md5(3), + chap-md5(4), + ms-chap-v2(5) +} + +DigestInit ::= SEQUENCE { + type UTF8String, -- http, sasl, chap, cram-md5 -- + channel [0] SEQUENCE { + cb-type UTF8String, + cb-binding UTF8String + } OPTIONAL, + hostname [1] UTF8String OPTIONAL -- for chap/cram-md5 +} + +DigestInitReply ::= SEQUENCE { + nonce UTF8String, -- service nonce/challenge + opaque UTF8String, -- server state + identifier [0] UTF8String OPTIONAL +} + + +DigestRequest ::= SEQUENCE { + type UTF8String, -- http, sasl-md5, chap, cram-md5 -- + digest UTF8String, -- http:md5/md5-sess sasl:clear/int/conf -- + username UTF8String, -- username user used + responseData UTF8String, -- client response + authid [0] UTF8String OPTIONAL, + authentication-user [1] Principal OPTIONAL, -- principal to get key from + realm [2] UTF8String OPTIONAL, + method [3] UTF8String OPTIONAL, + uri [4] UTF8String OPTIONAL, + serverNonce UTF8String, -- same as "DigestInitReply.nonce" + clientNonce [5] UTF8String OPTIONAL, + nonceCount [6] UTF8String OPTIONAL, + qop [7] UTF8String OPTIONAL, + identifier [8] UTF8String OPTIONAL, + hostname [9] UTF8String OPTIONAL, + opaque UTF8String -- same as "DigestInitReply.opaque" +} +-- opaque = hex(cksum(type|serverNonce|identifier|hostname,digest-key)) +-- serverNonce = hex(time[4bytes]random[12bytes])(-cbType:cbBinding) + + +DigestError ::= SEQUENCE { + reason UTF8String, + code INTEGER (-2147483648..2147483647) +} + +DigestResponse ::= SEQUENCE { + success BOOLEAN, + rsp [0] UTF8String OPTIONAL, + tickets [1] SEQUENCE OF OCTET STRING OPTIONAL, + channel [2] SEQUENCE { + cb-type UTF8String, + cb-binding UTF8String + } OPTIONAL, + session-key [3] OCTET STRING OPTIONAL +} + +NTLMInit ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + hostname [1] UTF8String OPTIONAL, + domain [1] UTF8String OPTIONAL +} + +NTLMInitReply ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + opaque [1] OCTET STRING, + targetname [2] UTF8String, + challenge [3] OCTET STRING, + targetinfo [4] OCTET STRING OPTIONAL +} + +NTLMRequest ::= SEQUENCE { + flags [0] INTEGER (0..4294967295), + opaque [1] OCTET STRING, + username [2] UTF8String, + targetname [3] UTF8String, + targetinfo [4] OCTET STRING OPTIONAL, + lm [5] OCTET STRING, + ntlm [6] OCTET STRING, + sessionkey [7] OCTET STRING OPTIONAL +} + +NTLMResponse ::= SEQUENCE { + success [0] BOOLEAN, + flags [1] INTEGER (0..4294967295), + sessionkey [2] OCTET STRING OPTIONAL, + tickets [3] SEQUENCE OF OCTET STRING OPTIONAL +} + +NTLMRequest2 ::= SEQUENCE { + loginUserName [0] UTF8String, + loginDomainName [1] UTF8String, + flags [2] INTEGER (0..4294967295), + lmchallenge [3] OCTET STRING SIZE (8), + ntChallengeResponce [4] OCTET STRING, + lmChallengeResponce [5] OCTET STRING +} + +NTLMReply ::= SEQUENCE { + success [0] BOOLEAN, + flags [1] INTEGER (0..4294967295), + sessionkey [2] OCTET STRING OPTIONAL +} + +DigestReqInner ::= CHOICE { + init [0] DigestInit, + digestRequest [1] DigestRequest, + ntlmInit [2] NTLMInit, + ntlmRequest [3] NTLMRequest, + supportedMechs [4] NULL +} + +DigestREQ ::= [APPLICATION 128] SEQUENCE { + apReq [0] OCTET STRING, + innerReq [1] EncryptedData +} + +DigestRepInner ::= CHOICE { + error [0] DigestError, + initReply [1] DigestInitReply, + response [2] DigestResponse, + ntlmInitReply [3] NTLMInitReply, + ntlmResponse [4] NTLMResponse, + supportedMechs [5] DigestTypes, + ... +} + +DigestREP ::= [APPLICATION 129] SEQUENCE { + apRep [0] OCTET STRING, + innerRep [1] EncryptedData +} + + +-- HTTP + +-- md5 +-- A1 = unq(username-value) ":" unq(realm-value) ":" passwd +-- md5-sess +-- A1 = HEX(H(unq(username-value) ":" unq(realm-value) ":" passwd ) ":" unq(nonce-value) ":" unq(cnonce-value)) + +-- qop == auth +-- A2 = Method ":" digest-uri-value +-- qop == auth-int +-- A2 = Method ":" digest-uri-value ":" H(entity-body) + +-- request-digest = HEX(KD(HEX(H(A1)), +-- unq(nonce-value) ":" nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" HEX(H(A2)))) +-- no "qop" +-- request-digest = HEX(KD(HEX(H(A1)), unq(nonce-value) ":" HEX(H(A2)))) + + +-- SASL: +-- SS = H( { unq(username-value), ":", unq(realm-value), ":", password } ) +-- A1 = { SS, ":", unq(nonce-value), ":", unq(cnonce-value) } +-- A1 = { SS, ":", unq(nonce-value), ":", unq(cnonce-value), ":", unq(authzid-value) } + +-- A2 = "AUTHENTICATE:", ":", digest-uri-value +-- qop == auth-int,auth-conf +-- A2 = "AUTHENTICATE:", ":", digest-uri-value, ":00000000000000000000000000000000" + +-- response-value = HEX( KD ( HEX(H(A1)), +-- { unq(nonce-value), ":" nc-value, ":", +-- unq(cnonce-value), ":", qop-value, ":", +-- HEX(H(A2)) })) + +END diff --git a/third_party/heimdal/lib/asn1/extra.c b/third_party/heimdal/lib/asn1/extra.c new file mode 100644 index 0000000..253ac5a --- /dev/null +++ b/third_party/heimdal/lib/asn1/extra.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2003 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include "heim_asn1.h" +#include <vis.h> +#include <vis-extras.h> + +RCSID("$Id$"); + +int ASN1CALL +encode_heim_any(unsigned char *p, size_t len, + const heim_any *data, size_t *size) +{ + return der_put_octet_string (p, len, data, size); +} + +int ASN1CALL +decode_heim_any(const unsigned char *p, size_t len, + heim_any *data, size_t *size) +{ + size_t len_len, length, l; + Der_class thisclass; + Der_type thistype; + unsigned int thistag; + int e; + + memset(data, 0, sizeof(*data)); + + e = der_get_tag (p, len, &thisclass, &thistype, &thistag, &l); + if (e) return e; + if (l > len) + return ASN1_OVERFLOW; + e = der_get_length(p + l, len - l, &length, &len_len); + if (e) return e; + if (length == ASN1_INDEFINITE) { + if (len < len_len + l) + return ASN1_OVERFLOW; + length = len - (len_len + l); + } else { + if (len < length + len_len + l) + return ASN1_OVERFLOW; + } + + data->data = malloc(length + len_len + l); + if (data->data == NULL) + return ENOMEM; + data->length = length + len_len + l; + memcpy(data->data, p, length + len_len + l); + + if (size) + *size = length + len_len + l; + + return 0; +} + +void ASN1CALL +free_heim_any(heim_any *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_heim_any(const heim_any *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_heim_any(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_heim_any(const heim_any *from, heim_any *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +encode_HEIM_ANY(unsigned char *p, size_t len, + const heim_any *data, size_t *size) +{ + return encode_heim_any(p, len, data, size); +} + +int ASN1CALL +decode_HEIM_ANY(const unsigned char *p, size_t len, + heim_any *data, size_t *size) +{ + return decode_heim_any(p, len, data, size); +} + +void ASN1CALL +free_HEIM_ANY(heim_any *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_HEIM_ANY(const heim_any *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_HEIM_ANY(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_HEIM_ANY(const heim_any *from, heim_any *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +encode_heim_any_set(unsigned char *p, size_t len, + const heim_any_set *data, size_t *size) +{ + return der_put_octet_string (p, len, data, size); +} + +int ASN1CALL +decode_heim_any_set(const unsigned char *p, size_t len, + heim_any_set *data, size_t *size) +{ + return der_get_octet_string(p, len, data, size); +} + +void ASN1CALL +free_heim_any_set(heim_any_set *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_heim_any_set(const heim_any_set *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_heim_any_set(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_heim_any_set(const heim_any_set *from, heim_any_set *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +heim_any_cmp(const heim_any_set *p, const heim_any_set *q) +{ + return der_heim_octet_string_cmp(p, q); +} + +int ASN1CALL +encode_HEIM_ANY_SET(unsigned char *p, size_t len, + const heim_any_set *data, size_t *size) +{ + return encode_heim_any_set(p, len, data, size); +} + +int ASN1CALL +decode_HEIM_ANY_SET(const unsigned char *p, size_t len, + heim_any_set *data, size_t *size) +{ + return decode_heim_any_set(p, len, data, size); +} + +void ASN1CALL +free_HEIM_ANY_SET(heim_any_set *data) +{ + der_free_octet_string(data); +} + +char * ASN1CALL +print_HEIM_ANY_SET(const heim_any_set *data, int flags) +{ + char *s2 = NULL; + char *s = der_print_octet_string(data, 0); + int r = -1; + + (void)flags; + if (s) + r = rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = NULL; + if (r > -1) + (void) asprintf(&s, "\"%s\"", s2); + free(s2); + return s; +} + +size_t ASN1CALL +length_HEIM_ANY_SET(const heim_any *data) +{ + return data->length; +} + +int ASN1CALL +copy_HEIM_ANY_SET(const heim_any_set *from, heim_any_set *to) +{ + return der_copy_octet_string(from, to); +} + +int ASN1CALL +HEIM_ANY_cmp(const heim_any_set *p, const heim_any_set *q) +{ + return der_heim_octet_string_cmp(p, q); +} diff --git a/third_party/heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq b/third_party/heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq Binary files differnew file mode 100644 index 0000000..21ac360 --- /dev/null +++ b/third_party/heimdal/lib/asn1/fuzz-inputs/KrbFastArmoredReq diff --git a/third_party/heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt b/third_party/heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt Binary files differnew file mode 100644 index 0000000..7e9bc70 --- /dev/null +++ b/third_party/heimdal/lib/asn1/fuzz-inputs/minimal-ek.crt diff --git a/third_party/heimdal/lib/asn1/fuzz-inputs/x690sample.der b/third_party/heimdal/lib/asn1/fuzz-inputs/x690sample.der new file mode 100644 index 0000000..ec1c2c2 --- /dev/null +++ b/third_party/heimdal/lib/asn1/fuzz-inputs/x690sample.der @@ -0,0 +1,5 @@ +`aJohnPSmith +DirectorB3 +C19710917aMaryTSmithB1aRalphTSmith +C195711111aSusanBSmith +C19590717
\ No newline at end of file diff --git a/third_party/heimdal/lib/asn1/fuzzer.c b/third_party/heimdal/lib/asn1/fuzzer.c new file mode 100644 index 0000000..527f7e9 --- /dev/null +++ b/third_party/heimdal/lib/asn1/fuzzer.c @@ -0,0 +1,742 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <com_err.h> + +enum trigger_method { FOFF, FRANDOM, FLINEAR, FLINEAR_SIZE }; + +#ifdef ASN1_FUZZER +static enum trigger_method method = FOFF; + +/* FLINEAR */ +static unsigned long fnum, fcur, fsize; +#endif + +int +asn1_fuzzer_method(const char *mode) +{ +#ifdef ASN1_FUZZER + if (mode == NULL || strcasecmp(mode, "off") == 0) { + method = FOFF; + } else if (strcasecmp(mode, "random") == 0) { + method = FRANDOM; + } else if (strcasecmp(mode, "linear") == 0) { + method = FLINEAR; + } else if (strcasecmp(mode, "linear-size") == 0) { + method = FLINEAR_SIZE; + } else + return 1; + return 0; +#else + return 1; +#endif +} + +void +asn1_fuzzer_reset(void) +{ +#ifdef ASN1_FUZZER + fcur = 0; + fsize = 0; + fnum = 0; +#endif +} + +void +asn1_fuzzer_next(void) +{ +#ifdef ASN1_FUZZER + fcur = 0; + fsize = 0; + fnum++; +#endif +} + +int +asn1_fuzzer_done(void) +{ +#ifndef ASN1_FUZZER + abort(); +#else + /* since code paths */ + return (fnum > 10000); +#endif +} + +#ifdef ASN1_FUZZER + +static int +fuzzer_trigger(unsigned int chance) +{ + switch(method) { + case FOFF: + return 0; + case FRANDOM: + if ((rk_random() % chance) != 1) + return 0; + return 1; + case FLINEAR: + if (fnum == fcur++) + return 1; + return 0; + case FLINEAR_SIZE: + return 0; + } + return 0; +} + +static int +fuzzer_size_trigger(unsigned long *cur) +{ + if (method != FLINEAR_SIZE) + return 0; + if (fnum == (*cur)++) + return 1; + return 0; +} + +static size_t +fuzzer_length_len (size_t len) +{ + if (fuzzer_size_trigger(&fsize)) { + len = 0; + } else if (fuzzer_size_trigger(&fsize)) { + len = 129; + } else if (fuzzer_size_trigger(&fsize)) { + len = 0xffff; + } + + if (len < 128) + return 1; + else { + int ret = 0; + do { + ++ret; + len /= 256; + } while (len); + return ret + 1; + } +} + +static int +fuzzer_put_length (unsigned char *p, size_t len, size_t val, size_t *size) +{ + if (len < 1) + return ASN1_OVERFLOW; + + if (fuzzer_size_trigger(&fcur)) { + val = 0; + } else if (fuzzer_size_trigger(&fcur)) { + val = 129; + } else if (fuzzer_size_trigger(&fcur)) { + val = 0xffff; + } + + if (val < 128) { + *p = val; + *size = 1; + } else { + size_t l = 0; + + while(val > 0) { + if(len < 2) + return ASN1_OVERFLOW; + *p-- = val % 256; + val /= 256; + len--; + l++; + } + *p = 0x80 | l; + if(size) + *size = l + 1; + } + return 0; +} + +static int +fuzzer_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + unsigned fcont = 0; + + if (tag <= 30) { + if (len < 1) + return ASN1_OVERFLOW; + if (fuzzer_trigger(100)) + *p = MAKE_TAG(class, type, 0x1f); + else + *p = MAKE_TAG(class, type, tag); + *size = 1; + } else { + size_t ret = 0; + unsigned int continuation = 0; + + do { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = tag % 128 | continuation; + len--; + ret++; + tag /= 128; + continuation = 0x80; + } while(tag > 0); + if (len < 1) + return ASN1_OVERFLOW; + if (fuzzer_trigger(100)) + *p-- = MAKE_TAG(class, type, 0); + else + *p-- = MAKE_TAG(class, type, 0x1f); + ret++; + *size = ret; + } + return 0; +} + +static int +fuzzer_put_length_and_tag (unsigned char *p, size_t len, size_t len_val, + Der_class class, Der_type type, + unsigned int tag, size_t *size) +{ + size_t ret = 0; + size_t l; + int e; + + e = fuzzer_put_length (p, len, len_val, &l); + if(e) + return e; + p -= l; + len -= l; + ret += l; + e = fuzzer_put_tag (p, len, class, type, tag, &l); + if(e) + return e; + + ret += l; + *size = ret; + return 0; +} + +static int +fuzzer_put_general_string (unsigned char *p, size_t len, + const heim_general_string *str, size_t *size) +{ + size_t slen = strlen(*str); + + if (len < slen) + return ASN1_OVERFLOW; + p -= slen; + if (slen >= 2 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%s", 2); + } else if (slen >= 2 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%n", 2); + } else if (slen >= 4 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%10n", 4); + } else if (slen >= 10 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%n%n%n%n%n", 10); + } else if (slen >= 10 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%n%p%s%d%x", 10); + } else if (slen >= 7 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%.1024d", 7); + } else if (slen >= 7 && fuzzer_trigger(100)) { + memcpy(p+1, *str, slen); + memcpy(p+1, "%.2049d", 7); + } else if (fuzzer_trigger(100)) { + memset(p+1, 0, slen); + } else if (fuzzer_trigger(100)) { + memset(p+1, 0xff, slen); + } else if (fuzzer_trigger(100)) { + memset(p+1, 'A', slen); + } else { + memcpy(p+1, *str, slen); + } + *size = slen; + return 0; +} + + +struct asn1_type_func fuzzerprim[A1T_NUM_ENTRY] = { +#define fuzel(name, type) { \ + (asn1_type_encode)fuzzer_put_##name, \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } +#define el(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } +#define elber(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name##_ber, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + sizeof(type) \ + } + el(integer, int), + el(integer64, int64_t), + el(heim_integer, heim_integer), + el(integer, int), + el(unsigned, unsigned), + el(uninteger64, uint64_t), + fuzel(general_string, heim_general_string), + el(octet_string, heim_octet_string), + elber(octet_string, heim_octet_string), + el(ia5_string, heim_ia5_string), + el(bmp_string, heim_bmp_string), + el(universal_string, heim_universal_string), + el(printable_string, heim_printable_string), + el(visible_string, heim_visible_string), + el(utf8string, heim_utf8_string), + el(generalized_time, time_t), + el(utctime, time_t), + el(bit_string, heim_bit_string), + { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean, + (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer, + (asn1_type_release)der_free_integer, sizeof(int) + }, + el(oid, heim_oid), + el(general_string, heim_general_string), +#undef fuzel +#undef el +#undef elber +}; + + + +int +_asn1_encode_fuzzer(const struct asn1_template *t, + unsigned char *p, size_t len, + const void *data, size_t *size) +{ + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + size_t oldlen = len; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_encode_fuzzer(t->ptr, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->encode)(p, len, el, &newsize); + } + + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + const void *olddata = data; + size_t l, datalen; + + data = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } + + ret = _asn1_encode_fuzzer(t->ptr, p, len, data, &datalen); + if (ret) + return ret; + + len -= datalen; p -= datalen; + + ret = fuzzer_put_length_and_tag(p, len, datalen, + A1_TAG_CLASS(t->tt), + A1_TAG_TYPE(t->tt), + A1_TAG_TAG(t->tt), &l); + if (ret) + return ret; + + p -= l; len -= l; + + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (type > sizeof(fuzzerprim)/sizeof(fuzzerprim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (fuzzerprim[type].encode)(p, len, el, &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + heim_octet_string *val; + unsigned char *elptr = el->val; + size_t i, totallen; + + if (el->len == 0) + break; + + if (el->len > UINT_MAX/sizeof(val[0])) + return ERANGE; + + val = malloc(sizeof(val[0]) * el->len); + if (val == NULL) + return ENOMEM; + + for(totallen = 0, i = 0; i < el->len; i++) { + unsigned char *next; + size_t l; + + val[i].length = _asn1_length(t->ptr, elptr); + val[i].data = malloc(val[i].length); + + ret = _asn1_encode_fuzzer(t->ptr, DPO(val[i].data, val[i].length - 1), + val[i].length, elptr, &l); + if (ret) + break; + + next = elptr + ellen; + if (next < elptr) { + ret = ASN1_OVERFLOW; + break; + } + elptr = next; + totallen += val[i].length; + } + if (ret == 0 && totallen > len) + ret = ASN1_OVERFLOW; + if (ret) { + do { + free(val[i].data); + } while(i-- > 0); + free(val); + return ret; + } + + len -= totallen; + + qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort); + + i = el->len - 1; + do { + p -= val[i].length; + memcpy(p + 1, val[i].data, val[i].length); + free(val[i].data); + } while(i-- > 0); + free(val); + + break; + + } + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + size_t newsize; + unsigned int i; + unsigned char *elptr = el->val; + + if (el->len == 0) + break; + + elptr += ellen * (el->len - 1); + + for (i = 0; i < el->len; i++) { + ret = _asn1_encode_fuzzer(t->ptr, p, len, + elptr, + &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + elptr -= ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t elements = A1_HEADER_LEN(bmember); + size_t pos; + unsigned char c = 0; + unsigned int bitset = 0; + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + bmember += elements; + + if (rfc1510) + pos = 31; + else + pos = bmember->offset; + + while (elements && len) { + while (bmember->offset / 8 < pos / 8) { + if (rfc1510 || bitset || c) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + c = 0; + pos -= 8; + } + _asn1_bmember_put_bit(&c, data, bmember->offset, size, &bitset); + elements--; bmember--; + } + if (rfc1510 || bitset) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + + if (len < 1) + return ASN1_OVERFLOW; + if (rfc1510 || bitset == 0) + *p-- = 0; + else + *p-- = bitset - 1; + + len--; + + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + size_t datalen; + const void *el; + + if (*element > A1_HEADER_LEN(choice)) { + printf("element: %d\n", *element); + return ASN1_PARSE_ERROR; + } + + if (*element == 0) { + ret += der_put_octet_string(p, len, + DPOC(data, choice->tt), &datalen); + } else { + choice += *element; + el = DPOC(data, choice->offset); + ret = _asn1_encode_fuzzer(choice->ptr, p, len, el, &datalen); + if (ret) + return ret; + } + len -= datalen; p -= datalen; + + break; + } + default: + ABORT_ON_ERROR(); + } + t--; + elements--; + } + + if (fuzzer_trigger(1000)) { + memset(p + 1, 0, oldlen - len); + } else if (fuzzer_trigger(1000)) { + memset(p + 1, 0x41, oldlen - len); + } else if (fuzzer_trigger(1000)) { + memset(p + 1, 0xff, oldlen - len); + } + + if (size) + *size = oldlen - len; + + return 0; +} + +size_t +_asn1_length_fuzzer(const struct asn1_template *t, const void *data) +{ + size_t elements = A1_HEADER_LEN(t); + size_t ret = 0; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret += _asn1_length(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + ret += (f->length)(el); + } + break; + } + case A1_OP_TAG: { + size_t datalen; + const void *olddata = data; + + data = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } + datalen = _asn1_length(t->ptr, data); + ret += der_length_tag(A1_TAG_TAG(t->tt)) + fuzzer_length_len(datalen); + ret += datalen; + data = olddata; + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + ret += (asn1_template_prim[type].length)(el); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + ret += _asn1_length(t->ptr, element); + element += ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t elements = A1_HEADER_LEN(bmember); + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + if (rfc1510) { + ret += 5; + } else { + + ret += 1; + + bmember += elements; + + while (elements) { + if (_asn1_bmember_isset_bit(data, bmember->offset, size)) { + ret += (bmember->offset / 8) + 1; + break; + } + elements--; bmember--; + } + } + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + ret += der_length_octet_string(DPOC(data, choice->tt)); + } else { + choice += *element; + ret += _asn1_length(choice->ptr, DPOC(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + elements--; + t--; + } + return ret; +} + +#endif /* ASN1_FUZZER */ diff --git a/third_party/heimdal/lib/asn1/gen.c b/third_party/heimdal/lib/asn1/gen.c new file mode 100644 index 0000000..55ec5f6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen.c @@ -0,0 +1,2090 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +extern const char *enum_prefix; +extern int prefix_enum; + +RCSID("$Id$"); + +FILE *jsonfile, *privheaderfile, *headerfile, *oidsfile, *codefile, *logfile, *templatefile; +FILE *symsfile; + +#define STEM "asn1" + +static const char *orig_filename; +static char *privheader, *header, *template; +static const char *headerbase = STEM; + +/* XXX same as der_length_tag */ +static size_t +length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + +/* + * list of all IMPORTs + */ + +struct import { + const char *module; + struct import *next; +}; + +static struct import *imports = NULL; + +void +add_import (const char *module) +{ + struct import *tmp = emalloc (sizeof(*tmp)); + + tmp->module = module; + tmp->next = imports; + imports = tmp; + + fprintf (headerfile, "#include <%s_asn1.h>\n", module); + fprintf(jsonfile, "{\"imports\":\"%s\"}\n", module); +} + +/* + * List of all exported symbols + * + * XXX A hash table would be nice here. + */ + +struct sexport { + const char *name; + int defined; + struct sexport *next; +}; + +static struct sexport *exports = NULL; + +void +add_export (const char *name) +{ + struct sexport *tmp = emalloc (sizeof(*tmp)); + + tmp->name = name; + tmp->next = exports; + exports = tmp; +} + +int +is_export(const char *name) +{ + struct sexport *tmp; + + if (exports == NULL) /* no export list, all exported */ + return 1; + + for (tmp = exports; tmp != NULL; tmp = tmp->next) { + if (strcmp(tmp->name, name) == 0) { + tmp->defined = 1; + return 1; + } + } + return 0; +} + +const char * +get_filename (void) +{ + return orig_filename; +} + +void +init_generate (const char *filename, const char *base) +{ + char *fn = NULL; + + orig_filename = filename; + if (base != NULL) { + headerbase = strdup(base); + if (headerbase == NULL) + errx(1, "strdup"); + } + + /* JSON file */ + if (asprintf(&fn, "%s.json", headerbase) < 0 || fn == NULL) + errx(1, "malloc"); + jsonfile = fopen(fn, "w"); + if (jsonfile == NULL) + err(1, "open %s", fn); + free(fn); + fn = NULL; + + /* public header file */ + if (asprintf(&header, "%s.h", headerbase) < 0 || header == NULL) + errx(1, "malloc"); + if (asprintf(&fn, "%s.h", headerbase) < 0 || fn == NULL) + errx(1, "malloc"); + headerfile = fopen (fn, "w"); + if (headerfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + /* private header file */ + if (asprintf(&privheader, "%s-priv.h", headerbase) < 0 || privheader == NULL) + errx(1, "malloc"); + if (asprintf(&fn, "%s-priv.h", headerbase) < 0 || fn == NULL) + errx(1, "malloc"); + privheaderfile = fopen (fn, "w"); + if (privheaderfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + /* template file */ + if (asprintf(&template, "%s-template.c", headerbase) < 0 || template == NULL) + errx(1, "malloc"); + fprintf (headerfile, + "/* Generated from %s */\n" + "/* Do not edit */\n\n", + filename); + fprintf (headerfile, + "#ifndef __%s_h__\n" + "#define __%s_h__\n\n", headerbase, headerbase); + fprintf (headerfile, + "#include <stddef.h>\n" + "#include <stdint.h>\n" + "#include <time.h>\n\n"); + fprintf (headerfile, + "#ifndef __asn1_common_definitions__\n" + "#define __asn1_common_definitions__\n\n"); + fprintf (headerfile, + "#ifndef __HEIM_BASE_DATA__\n" + "#define __HEIM_BASE_DATA__ 1\n" + "struct heim_base_data {\n" + " size_t length;\n" + " void *data;\n" + "};\n" + "typedef struct heim_base_data heim_octet_string;\n" + "#endif\n\n"); + fprintf (headerfile, + "typedef struct heim_integer {\n" + " size_t length;\n" + " void *data;\n" + " int negative;\n" + "} heim_integer;\n\n"); + fprintf (headerfile, + "typedef char *heim_general_string;\n\n" + ); + fprintf (headerfile, + "typedef char *heim_utf8_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_base_data heim_printable_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_base_data heim_ia5_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_bmp_string {\n" + " size_t length;\n" + " uint16_t *data;\n" + "} heim_bmp_string;\n\n"); + fprintf (headerfile, + "typedef struct heim_universal_string {\n" + " size_t length;\n" + " uint32_t *data;\n" + "} heim_universal_string;\n\n"); + fprintf (headerfile, + "typedef char *heim_visible_string;\n\n" + ); + fprintf (headerfile, + "typedef struct heim_oid {\n" + " size_t length;\n" + " unsigned *components;\n" + "} heim_oid;\n\n"); + fprintf (headerfile, + "typedef struct heim_bit_string {\n" + " size_t length;\n" + " void *data;\n" + "} heim_bit_string;\n\n"); + fprintf (headerfile, + "typedef struct heim_base_data heim_any;\n" + "typedef struct heim_base_data heim_any_set;\n" + "typedef struct heim_base_data HEIM_ANY;\n" + "typedef struct heim_base_data HEIM_ANY_SET;\n\n"); + + fprintf (headerfile, + "enum asn1_print_flags {\n" + " ASN1_PRINT_INDENT = 1,\n" + "};\n\n"); + fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \\\n" + " do { \\\n" + " (BL) = length_##T((S)); \\\n" + " (B) = calloc(1, (BL)); \\\n" + " if((B) == NULL) { \\\n" + " *(L) = 0; \\\n" + " (R) = ENOMEM; \\\n" + " } else { \\\n" + " (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n" + " (S), (L)); \\\n" + " if((R) != 0) { \\\n" + " free((B)); \\\n" + " (B) = NULL; \\\n" + " *(L) = 0; \\\n" + " } \\\n" + " } \\\n" + " } while (0)\n\n", + headerfile); + fputs("#ifdef _WIN32\n" + "#ifndef ASN1_LIB\n" + "#define ASN1EXP __declspec(dllimport)\n" + "#else\n" + "#define ASN1EXP\n" + "#endif\n" + "#define ASN1CALL __stdcall\n" + "#else\n" + "#define ASN1EXP\n" + "#define ASN1CALL\n" + "#endif\n", + headerfile); + fputs("#ifndef ENOTSUP\n" + "/* Very old MSVC CRTs lack ENOTSUP */\n" + "#define ENOTSUP EINVAL\n" + "#endif\n", + headerfile); + fprintf (headerfile, "struct units;\n\n"); + fprintf (headerfile, "#endif\n\n"); + if (asprintf(&fn, "%s_files", base) < 0 || fn == NULL) + errx(1, "malloc"); + logfile = fopen(fn, "w"); + if (logfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + if (asprintf(&fn, "%s_oids.c", base) < 0 || fn == NULL) + errx(1, "malloc"); + oidsfile = fopen(fn, "w"); + if (oidsfile == NULL) + err (1, "open %s", fn); + if (asprintf(&fn, "%s_syms.c", base) < 0 || fn == NULL) + errx(1, "malloc"); + symsfile = fopen(fn, "w"); + if (symsfile == NULL) + err (1, "open %s", fn); + free(fn); + fn = NULL; + + /* if one code file, write into the one codefile */ + if (one_code_file) + return; + + templatefile = fopen (template, "w"); + if (templatefile == NULL) + err (1, "open %s", template); + + fprintf (templatefile, + "/* Generated from %s */\n" + "/* Do not edit */\n\n" + "#include <stdio.h>\n" + "#include <stdlib.h>\n" + "#include <time.h>\n" + "#include <string.h>\n" + "#include <errno.h>\n" + "#include <limits.h>\n" + "#include <asn1_err.h>\n" + "#include <%s>\n", + filename, + type_file_string); + + fprintf (templatefile, + "#include <%s>\n" + "#include <%s>\n" + "#include <der.h>\n" + "#include <asn1-template.h>\n", + header, privheader); + + +} + +void +close_generate (void) +{ + fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase); + + if (headerfile && fclose(headerfile) == EOF) + err(1, "writes to public header file failed"); + if (privheaderfile && fclose(privheaderfile) == EOF) + err(1, "writes to private header file failed"); + if (templatefile && fclose(templatefile) == EOF) + err(1, "writes to template file failed"); + if (!jsonfile) abort(); + if (fclose(jsonfile) == EOF) + err(1, "writes to JSON file failed"); + if (!oidsfile) abort(); + if (fclose(oidsfile) == EOF) + err(1, "writes to OIDs file failed"); + if (!symsfile) abort(); + if (fclose(symsfile) == EOF) + err(1, "writes to symbols file failed"); + if (!logfile) abort(); + fprintf(logfile, "\n"); + if (fclose(logfile) == EOF) + err(1, "writes to log file failed"); +} + +void +gen_assign_defval(const char *var, struct value *val) +{ + switch(val->type) { + case stringvalue: + fprintf(codefile, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var, val->u.stringvalue); + break; + case integervalue: + fprintf(codefile, "%s = %lld;\n", + var, (long long)val->u.integervalue); + break; + case booleanvalue: + if(val->u.booleanvalue) + fprintf(codefile, "%s = 1;\n", var); + else + fprintf(codefile, "%s = 0;\n", var); + break; + default: + abort(); + } +} + +void +gen_compare_defval(const char *var, struct value *val) +{ + switch(val->type) { + case stringvalue: + fprintf(codefile, "if(strcmp(%s, \"%s\") != 0)\n", var, val->u.stringvalue); + break; + case integervalue: + fprintf(codefile, "if(%s != %lld)\n", + var, (long long)val->u.integervalue); + break; + case booleanvalue: + if(val->u.booleanvalue) + fprintf(codefile, "if(!%s)\n", var); + else + fprintf(codefile, "if(%s)\n", var); + break; + default: + abort(); + } +} + +void +generate_header_of_codefile(const char *name) +{ + char *filename = NULL; + + if (codefile != NULL) + abort(); + + if (asprintf (&filename, "%s_%s.c", STEM, name) < 0 || filename == NULL) + errx(1, "malloc"); + codefile = fopen (filename, "w"); + if (codefile == NULL) + err (1, "fopen %s", filename); + if (logfile) + fprintf(logfile, "%s ", filename); + free(filename); + filename = NULL; + fprintf (codefile, + "/* Generated from %s */\n" + "/* Do not edit */\n\n" + "#if defined(_WIN32) && !defined(ASN1_LIB)\n" + "# error \"ASN1_LIB must be defined\"\n" + "#endif\n" + "#include <stdio.h>\n" + "#include <stdlib.h>\n" + "#include <time.h>\n" + "#include <string.h>\n" + "#include <errno.h>\n" + "#include <limits.h>\n" + "#include <%s>\n", + orig_filename, + type_file_string); + + fprintf (codefile, + "#include \"%s\"\n" + "#include \"%s\"\n", + header, privheader); + fprintf (codefile, + "#include <asn1_err.h>\n" + "#include <der.h>\n" + "#include <asn1-template.h>\n\n"); + + if (parse_units_flag) + fprintf (codefile, + "#include <parse_units.h>\n\n"); + +#ifdef _WIN32 + fprintf(codefile, "#pragma warning(disable: 4101)\n\n"); +#endif +} + +void +close_codefile(void) +{ + if (codefile == NULL) + abort(); + + if (fclose(codefile) == EOF) + err(1, "writes to source code file failed"); + codefile = NULL; +} + +/* Object identifiers are parsed backwards; this reverses that */ +struct objid ** +objid2list(struct objid *o) +{ + struct objid *el, **list; + size_t i, len; + + for (el = o, len = 0; el; el = el->next) + len++; + if (len == 0) + return NULL; + list = ecalloc(len + 1, sizeof(*list)); + + for (i = 0; o; o = o->next) + list[i++] = o; + list[i] = NULL; + + /* Reverse the list */ + for (i = 0; i < (len>>1); i++) { + el = list[i]; + list[i] = list[len - (i + 1)]; + list[len - (i + 1)] = el; + } + return list; +} + +void +generate_constant (const Symbol *s) +{ + switch(s->value->type) { + case booleanvalue: + break; + case integervalue: + /* + * Work around the fact that OpenSSL defines macros for PKIX constants + * that we want to generate as enums, which causes conflicts for things + * like ub-name (ub_name). + */ + fprintf(headerfile, + "#ifdef %s\n" + "#undef %s\n" + "#endif\n" + "enum { %s = %lld };\n\n", + s->gen_name, s->gen_name, s->gen_name, + (long long)s->value->u.integervalue); + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_INTVAL(\"%s\", \"%s\", %s, %lld)\n", + s->name, s->gen_name, s->gen_name, + (long long)s->value->u.integervalue); + fprintf(jsonfile, + "{\"name\":\"%s\",\"gen_name\":\"%s\",\"type\":\"INTEGER\"," + "\"constant\":true,\"exported\":%s,\"value\":%lld}\n", + s->name, s->gen_name, is_export(s->name) ? "true" : "false", + (long long)s->value->u.integervalue); + break; + case nullvalue: + break; + case stringvalue: + break; + case objectidentifiervalue: { + struct objid *o, **list; + size_t i, len; + char *gen_upper; + + if (!one_code_file) + generate_header_of_codefile(s->gen_name); + + list = objid2list(s->value->u.objectidentifiervalue); + for (len = 0; list && list[len]; len++) + ; + if (len == 0) { + errx(1, "Empty OBJECT IDENTIFIER named %s\n", s->name); + break; + } + + fprintf(jsonfile, + "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"type\":\"OBJECT IDENTIFIER\"," + "\"constant\":true,\"exported\":%s,\"value\":[\n", + s->name, s->gen_name, is_export(s->name) ? "true" : "false"); + fprintf (headerfile, "/* OBJECT IDENTIFIER %s ::= { ", s->name); + for (i = 0; i < len; i++) { + o = list[i]; + fprintf(headerfile, "%s(%d) ", + o->label ? o->label : "label-less", o->value); + if (o->label == NULL) + fprintf(jsonfile, "%s{\"label\":null,\"value\":%d}", + i ? "," : "", o->value); + else + fprintf(jsonfile, "%s{\"label\":\"%s\",\"value\":%d}", + i ? "," : "", o->label, o->value); + } + fprintf(jsonfile, "]}\n"); + + fprintf (codefile, "static unsigned oid_%s_variable_num[%lu] = {", + s->gen_name, (unsigned long)len); + for (i = 0; list[i]; i++) { + fprintf(codefile, "%s %d", i ? "," : "", list[i]->value); + } + fprintf(codefile, "};\n"); + + fprintf (codefile, "const heim_oid asn1_oid_%s = " + "{ %lu, oid_%s_variable_num };\n\n", + s->gen_name, (unsigned long)len, s->gen_name); + + fprintf(oidsfile, "DEFINE_OID_WITH_NAME(%s)\n", s->gen_name); + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_OID(\"%s\", \"%s\", %s)\n", + s->name, s->gen_name, s->gen_name); + + free(list); + + /* header file */ + + gen_upper = strdup(s->gen_name); + len = strlen(gen_upper); + for (i = 0; i < len; i++) + gen_upper[i] = toupper((unsigned char)s->gen_name[i]); + + fprintf (headerfile, "} */\n"); + fprintf (headerfile, + "extern ASN1EXP const heim_oid asn1_oid_%s;\n" + "#define ASN1_OID_%s (&asn1_oid_%s)\n\n", + s->gen_name, + gen_upper, + s->gen_name); + + free(gen_upper); + + if (!one_code_file) + close_codefile(); + + break; + } + default: + abort(); + } +} + +int +is_tagged_type(const Type *t) +{ + /* + * Start by chasing aliasings like this: + * + * Type0 ::= ... + * Type1 ::= Type0 + * .. + * TypeN ::= TypeN-1 + * + * to <Type0>, then check if <Type0> is tagged. + */ + while (t->type == TType) { + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + abort(); + + } + if (t->type == TTag && t->tag.tagenv == TE_EXPLICIT) + return 1; + if (t->type == TTag) { + if (t->subtype) + return is_tagged_type(t->subtype); + if (t->symbol && t->symbol->type) + return is_tagged_type(t->symbol->type); + /* This is the tag */ + return 1; + } + return 0; +} + +int +is_primitive_type(const Type *t) +{ + /* + * Start by chasing aliasings like this: + * + * Type0 ::= ... + * Type1 ::= Type0 + * .. + * TypeN ::= TypeN-1 + * + * to <Type0>, then check if <Type0> is primitive. + */ + while (t->type == TType && + t->symbol && + t->symbol->type) { + if (t->symbol->type->type == TType) + t = t->symbol->type; /* Alias */ + else if (t->symbol->type->type == TTag && + t->symbol->type->tag.tagenv == TE_IMPLICIT) + /* + * IMPLICIT-tagged alias, something like: + * + * Type0 ::= [0] IMPLICIT ... + * + * Just recurse. + */ + return is_primitive_type(t->symbol->type); + else + break; + + } + /* EXPLICIT non-UNIVERSAL tags are always constructed */ + if (t->type == TTag && t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) + return 0; + if (t->symbol && t->symbol->type) { + /* EXPLICIT non-UNIVERSAL tags are constructed */ + if (t->symbol->type->type == TTag && + t->symbol->type->tag.tagclass != ASN1_C_UNIV && + t->symbol->type->tag.tagenv == TE_EXPLICIT) + return 0; + /* EXPLICIT UNIVERSAL tags are constructed if they are SEQUENCE/SET */ + if (t->symbol->type->type == TTag && + t->symbol->type->tag.tagclass == ASN1_C_UNIV) { + switch (t->symbol->type->tag.tagvalue) { + case UT_Sequence: return 0; + case UT_Set: return 0; + default: return 1; + } + } + } + switch(t->type) { + case TInteger: + case TBoolean: + case TOctetString: + case TBitString: + case TEnumerated: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TOID: + case TUTCTime: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TNull: + return 1; + case TTag: + return is_primitive_type(t->subtype); + default: + return 0; + } +} + +static void +space(int level) +{ + while(level-- > 0) + fprintf(headerfile, " "); +} + +static const char * +last_member_p(struct member *m) +{ + struct member *n = HEIM_TAILQ_NEXT(m, members); + if (n == NULL) + return ""; + if (n->ellipsis && HEIM_TAILQ_NEXT(n, members) == NULL) + return ""; + return ","; +} + +static struct member * +have_ellipsis(Type *t) +{ + struct member *m; + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->ellipsis) + return m; + } + return NULL; +} + +static void +define_asn1 (int level, Type *t) +{ + switch (t->type) { + case TType: + if (!t->symbol && t->typeref.iosclass) { + fprintf(headerfile, "%s.&%s", + t->typeref.iosclass->symbol->name, + t->typeref.field->name); + } else if (t->symbol) + fprintf(headerfile, "%s", t->symbol->name); + else + abort(); + break; + case TInteger: + if(t->members == NULL) { + fprintf (headerfile, "INTEGER"); + if (t->range) + fprintf (headerfile, " (%lld..%lld)", + (long long)t->range->min, + (long long)t->range->max); + } else { + Member *m; + fprintf (headerfile, "INTEGER {\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space (level + 1); + fprintf(headerfile, "%s(%lld)%s\n", m->gen_name, + (long long)m->val, last_member_p(m)); + } + space(level); + fprintf (headerfile, "}"); + } + break; + case TBoolean: + fprintf (headerfile, "BOOLEAN"); + break; + case TOctetString: + fprintf (headerfile, "OCTET STRING"); + break; + case TEnumerated: + case TBitString: { + Member *m; + + space(level); + if(t->type == TBitString) + fprintf (headerfile, "BIT STRING {\n"); + else + fprintf (headerfile, "ENUMERATED {\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space(level + 1); + fprintf(headerfile, "%s(%lld)%s\n", m->name, + (long long)m->val, last_member_p(m)); + } + space(level); + fprintf (headerfile, "}"); + break; + } + case TChoice: + case TSet: + case TSequence: { + Member *m; + size_t max_width = 0; + + if(t->type == TChoice) + fprintf(headerfile, "CHOICE {\n"); + else if(t->type == TSet) + fprintf(headerfile, "SET {\n"); + else + fprintf(headerfile, "SEQUENCE {\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + if(strlen(m->name) > max_width) + max_width = strlen(m->name); + } + max_width += 3; + if(max_width < 16) max_width = 16; + HEIM_TAILQ_FOREACH(m, t->members, members) { + size_t width = max_width; + space(level + 1); + if (m->ellipsis) { + fprintf (headerfile, "..."); + } else { + width -= fprintf(headerfile, "%s", m->name); + fprintf(headerfile, "%*s", (int)width, ""); + define_asn1(level + 1, m->type); + if(m->optional) + fprintf(headerfile, " OPTIONAL"); + } + if(last_member_p(m)) + fprintf (headerfile, ","); + fprintf (headerfile, "\n"); + } + space(level); + fprintf (headerfile, "}"); + break; + } + case TSequenceOf: + fprintf (headerfile, "SEQUENCE OF "); + define_asn1 (0, t->subtype); + break; + case TSetOf: + fprintf (headerfile, "SET OF "); + define_asn1 (0, t->subtype); + break; + case TGeneralizedTime: + fprintf (headerfile, "GeneralizedTime"); + break; + case TGeneralString: + fprintf (headerfile, "GeneralString"); + break; + case TTeletexString: + fprintf (headerfile, "TeletexString"); + break; + case TTag: { + const char *classnames[] = { "UNIVERSAL ", "APPLICATION ", + "" /* CONTEXT */, "PRIVATE " }; + if(t->tag.tagclass != ASN1_C_UNIV) + fprintf (headerfile, "[%s%d] ", + classnames[t->tag.tagclass], + t->tag.tagvalue); + if(t->tag.tagenv == TE_IMPLICIT) + fprintf (headerfile, "IMPLICIT "); + define_asn1 (level, t->subtype); + break; + } + case TUTCTime: + fprintf (headerfile, "UTCTime"); + break; + case TUTF8String: + space(level); + fprintf (headerfile, "UTF8String"); + break; + case TPrintableString: + space(level); + fprintf (headerfile, "PrintableString"); + break; + case TIA5String: + space(level); + fprintf (headerfile, "IA5String"); + break; + case TBMPString: + space(level); + fprintf (headerfile, "BMPString"); + break; + case TUniversalString: + space(level); + fprintf (headerfile, "UniversalString"); + break; + case TVisibleString: + space(level); + fprintf (headerfile, "VisibleString"); + break; + case TOID : + space(level); + fprintf(headerfile, "OBJECT IDENTIFIER"); + break; + case TNull: + space(level); + fprintf (headerfile, "NULL"); + break; + default: + abort (); + } +} + +static void +getnewbasename(char **newbasename, int typedefp, const char *basename, const char *name) +{ + if (typedefp) + *newbasename = strdup(name); + else { + if (name[0] == '*') + name++; + if (asprintf(newbasename, "%s_%s", basename, name) < 0) + errx(1, "malloc"); + } + if (*newbasename == NULL) + err(1, "malloc"); +} + +typedef enum define_type_options { + DEF_TYPE_NONE = 0, + DEF_TYPE_PRESERVE = 1, + DEF_TYPE_TYPEDEFP = 2, + DEF_TYPE_EMIT_NAME = 4 +} define_type_options; +static void define_type(int, const char *, const char *, Type *, Type *, define_type_options); + +/* + * Get the SET/SEQUENCE member pair and CLASS field pair defining an open type. + * + * There are three cases: + * + * - open types embedded in OCTET STRING, with the open type object class + * relation declared via a constraint + * + * - open types not embedded in OCTET STRING, which are really more like ANY + * DEFINED BY types, so, HEIM_ANY + * + * - open types in a nested structure member where the type ID field is in a + * member of the ancestor structure (this happens in PKIX's `AttributeSet', + * where the open type is essentially a SET OF HEIM_ANY). + * + * In a type like PKIX's SingleAttribute the type ID member would be the one + * named "type" and the open type member would be the one named "value", and + * the corresponding fields of the ATTRIBUTE class would be named "id" and + * "Type". + * + * NOTE: We assume a single open type member pair in any SET/SEQUENCE. In + * principle there could be more pairs and we could iterate them, or + * better yet, we could be given the name of an open type member and then + * just find its related type ID member and fields, then our caller would + * iterate the SET/SEQUENCE type's members looking for open type members + * and would call this function for each one found. + */ +void +get_open_type_defn_fields(const Type *t, + Member **typeidmember, + Member **opentypemember, + Field **typeidfield, + Field **opentypefield, + int *is_array_of) +{ + Member *m; + Field *junk1, *junk2; + char *idmembername = NULL; + + if (!typeidfield) typeidfield = &junk1; + if (!opentypefield) opentypefield = &junk2; + + *typeidfield = *opentypefield = NULL; + *typeidmember = *opentypemember = NULL; + *is_array_of = 0; + + /* Look for the open type member */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + Type *subtype = m->type; + Type *sOfType = NULL; + + while (subtype->type == TTag || + subtype->type == TSetOf || + subtype->type == TSequenceOf) { + if (subtype->type == TTag && subtype->subtype) { + if (subtype->subtype->type == TOctetString || + subtype->subtype->type == TBitString) + break; + subtype = subtype->subtype; + } else if (subtype->type == TSetOf || subtype->type == TSequenceOf) { + sOfType = subtype; + if (sOfType->symbol) + break; + if (subtype->subtype) + subtype = subtype->subtype; + } else + break; + } + /* + * If we traversed through a non-inlined SET OF or SEQUENCE OF type, + * then this cannot be an open type field. + */ + if (sOfType && sOfType->symbol) + continue; + /* + * The type of the field we're interested in has to have an information + * object constraint. + */ + if (!subtype->constraint) + continue; + if (subtype->type != TType && subtype->type != TTag) + continue; + /* + * Check if it's an ANY-like member or like an OCTET STRING CONTAINING + * member. Those are the only two possibilities. + */ + if ((subtype->type == TTag || subtype->type == TType) && + subtype->subtype && + subtype->constraint->ctype == CT_CONTENTS && + subtype->constraint->u.content.type && + subtype->constraint->u.content.type->type == TType && + !subtype->constraint->u.content.type->subtype && + subtype->constraint->u.content.type->constraint && + subtype->constraint->u.content.type->constraint->ctype == CT_TABLE_CONSTRAINT) { + /* Type like OCTET STRING or BIT STRING CONTAINING open type */ + if (*opentypemember) + errx(1, "Multiple open type members %s and %s for the same " + "field %s?", (*opentypemember)->name, m->name, + (*opentypefield)->name); + *opentypemember = m; + *opentypefield = subtype->constraint->u.content.type->typeref.field; + *is_array_of = sOfType != NULL; + idmembername = subtype->constraint->u.content.type->constraint->u.content.crel.membername; + break; + } else if (subtype->symbol && strcmp(subtype->symbol->name, "HEIM_ANY") == 0) { + /* Open type, but NOT embedded in OCTET STRING or BIT STRING */ + if (*opentypemember) + errx(1, "Multiple open type members %s and %s for the same " + "field %s?", (*opentypemember)->name, m->name, + (*opentypefield)->name); + *opentypemember = m; + *opentypefield = subtype->typeref.field; + *is_array_of = sOfType != NULL; + idmembername = subtype->constraint->u.content.crel.membername; + break; + } + } + + if (!idmembername) + errx(1, "Missing open type id member in %s", + t->symbol ? t->symbol->name : "<unknown type>"); + /* Look for the type ID member identified in the previous loop */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (!m->type->subtype || strcmp(m->name, idmembername) != 0) + continue; + if (m->type->constraint && + m->type->constraint->ctype == CT_TABLE_CONSTRAINT) + *typeidfield = m->type->typeref.field; + else if (m->type->subtype->constraint && + m->type->subtype->constraint->ctype == CT_TABLE_CONSTRAINT) + *typeidfield = m->type->subtype->typeref.field; + else + continue; + /* This is the type ID field (because there _is_ a subtype) */ + *typeidmember = m; + break; + } +} + +/* + * Generate CHOICE-like struct fields for open types declared via + * X.681/682/683 syntax. + * + * We could support multiple open type members in a SET/SEQUENCE, but for now + * we support only one. + */ +static void +define_open_type(int level, const char *newbasename, const char *name, const char *basename, Type *pt, Type *t) +{ + Member *opentypemember, *typeidmember; + Field *opentypefield, *typeidfield; + ObjectField *of; + IOSObjectSet *os = pt->actual_parameter; + IOSObject **objects; + size_t nobjs, i; + int is_array_of_open_type; + + get_open_type_defn_fields(pt, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + if (!opentypemember || !typeidmember || + !opentypefield || !typeidfield) + errx(1, "Open type specification in %s is incomplete", name); + + sort_object_set(os, typeidfield, &objects, &nobjs); + + fprintf(headerfile, "struct {\n"); + fprintf(jsonfile, "{\"opentype\":true,\"arraytype\":%s,", + is_array_of_open_type ? "true" : "false"); + fprintf(jsonfile, "\"classname\":\"%s\",", os->iosclass->symbol->name); + fprintf(jsonfile, "\"objectsetname\":\"%s\",", os->symbol->name); + fprintf(jsonfile, "\"typeidmember\":\"%s\",", typeidmember->name); + fprintf(jsonfile, "\"opentypemember\":\"%s\",", opentypemember->name); + fprintf(jsonfile, "\"typeidfield\":\"%s\",", typeidfield->name); + fprintf(jsonfile, "\"opentypefield\":\"%s\",", opentypefield->name); + + /* Iterate objects in the object set, gen enum labels */ + fprintf(headerfile, "enum { choice_%s_iosnumunknown = 0,\n", + newbasename); + fprintf(jsonfile, "\"opentypeids\":["); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) != 0) + continue; + if (!of->value || !of->value->s) + errx(1, "Unknown value in value field %s of object %s", + of->name, objects[i]->symbol->name); + fprintf(headerfile, "choice_%s_iosnum_%s,\n", + newbasename, of->value->s->gen_name); + fprintf(jsonfile, "\"%s\"", of->value->s->gen_name); + fprintf(jsonfile, "%s", (i + 1) < nobjs ? "," : ""); + } + } + fprintf(jsonfile, "],\n"); + fprintf(headerfile, "} element;\n"); + + if (is_array_of_open_type) + fprintf(headerfile, "unsigned int len;\n"); + + /* Iterate objects in the object set, gen union arms */ + fprintf(headerfile, "union {\nvoid *_any;\n"); + fprintf(jsonfile, "\"members\":["); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + char *n = NULL; + + /* XXX Print the type IDs into the jsonfile too pls */ + + if (strcmp(of->name, opentypefield->name) != 0) + continue; + if (!of->type || (!of->type->symbol && of->type->type != TTag) || + of->type->tag.tagclass != ASN1_C_UNIV) { + warnx("Ignoring unknown or unset type field %s of object %s", + of->name, objects[i]->symbol->name); + continue; + } + + if (asprintf(&n, "*%s", objects[i]->symbol->gen_name) < 0 || n == NULL) + err(1, "malloc"); + define_type(level + 2, n, newbasename, NULL, of->type, DEF_TYPE_NONE); + fprintf(jsonfile, "%s", (i + 1) < nobjs ? "," : ""); + free(n); + } + } + fprintf(jsonfile, "]}\n"); + if (is_array_of_open_type) { + fprintf(headerfile, "} *val;\n} _ioschoice_%s;\n", opentypemember->gen_name); + } else { + fprintf(headerfile, "} u;\n"); + fprintf(headerfile, "} _ioschoice_%s;\n", opentypemember->gen_name); + } + free(objects); +} + +static const char * const tagclassnames[] = { + "UNIVERSAL", "APPLICATION", "CONTEXT", "PRIVATE" +}; + +static void +define_type(int level, const char *name, const char *basename, + Type *pt, Type *t, define_type_options opts) +{ + const char *label_prefix = NULL; + const char *label_prefix_sep = NULL; + char *newbasename = NULL; + + fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"is_type\":true,\"exported\":%s,\"typedef\":%s,", + basename, name, + t->symbol && is_export(t->symbol->name) ? "true" : "false", + (opts & DEF_TYPE_TYPEDEFP) ? "true" : "false"); + + switch (t->type) { + case TType: + space(level); + if (!t->symbol && t->actual_parameter) { + define_open_type(level, newbasename, name, basename, t, t); + } else if (!t->symbol && pt->actual_parameter) { + define_open_type(level, newbasename, name, basename, pt, t); + } else if (t->symbol) { + fprintf(headerfile, "%s %s;\n", t->symbol->gen_name, name); + fprintf(jsonfile, "\"ttype\":\"%s\"," + "\"alias\":true\n", t->symbol->gen_name); + } else + abort(); + break; + case TInteger: + if (t->symbol && t->symbol->emitted_definition) + break; + + space(level); + if(t->members) { + Member *m; + + label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : ""); + label_prefix_sep = prefix_enum ? "_" : ""; + fprintf (headerfile, "enum %s {\n", (opts & DEF_TYPE_TYPEDEFP) ? name : ""); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"enum\"," + "\"members\":[\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space (level + 1); + fprintf(headerfile, "%s%s%s = %lld%s\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + fprintf(jsonfile, "{\"%s%s%s\":%lld}%s\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + } + fprintf(headerfile, "} %s;\n", name); + fprintf(jsonfile, "]"); + } else if (t->range == NULL) { + fprintf(headerfile, "heim_integer %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"heim_integer\""); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + fprintf(headerfile, "int64_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"int64_t\""); + } else if (t->range->min < 0) { + fprintf (headerfile, "int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"int\""); + } else if (t->range->max > UINT_MAX) { + fprintf (headerfile, "uint64_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"uint64_t\""); + } else { + fprintf (headerfile, "unsigned int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"unsigned int\""); + } + break; + case TBoolean: + space(level); + fprintf (headerfile, "int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"BOOLEAN\",\"ctype\":\"unsigned int\""); + break; + case TOctetString: + space(level); + fprintf (headerfile, "heim_octet_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"OCTET STRING\",\"ctype\":\"heim_octet_string\""); + break; + case TBitString: { + Member *m; + Type i; + struct range range = { 0, UINT_MAX }; + size_t max_memno = 0; + size_t bitset_size; + + if (t->symbol && t->symbol->emitted_definition) + break; + memset(&i, 0, sizeof(i)); + + /* + * range.max implies the size of the base unsigned integer used for the + * bitfield members. If it's less than or equal to UINT_MAX, then that + * will be unsigned int, otherwise it will be uint64_t. + * + * We could just use uint64_t, yes, but for now, and in case that any + * projects were exposing the BIT STRING types' C representations in + * ABIs prior to this compiler supporting BIT STRING with larger + * members, we stick to this. + */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > max_memno) + max_memno = m->val; + } + if (max_memno > 63) + range.max = INT64_MAX; + else + range.max = 1ULL << max_memno; + + i.type = TInteger; + i.range = ⦥ + i.members = NULL; + i.constraint = NULL; + + space(level); + fprintf(jsonfile, "\"ttype\":\"BIT STRING\","); + if(HEIM_TAILQ_EMPTY(t->members)) { + fprintf (headerfile, "heim_bit_string %s;\n", name); + fprintf(jsonfile, "\"ctype\":\"heim_bit_string\""); + } else { + int64_t pos = 0; + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ctype\":\"struct %s\",\"members\":[\n", newbasename); + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *n = NULL; + + /* + * pad unused bits beween declared members (hopefully this + * forces the compiler to give us an obvious layout) + */ + while (pos < m->val) { + if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 || + n == NULL) + err(1, "malloc"); + define_type(level + 1, n, newbasename, NULL, &i, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, ","); + free(n); + pos++; + } + + n = NULL; + if (asprintf (&n, "%s:1", m->gen_name) < 0 || n == NULL) + errx(1, "malloc"); + define_type(level + 1, n, newbasename, NULL, &i, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "%s", last_member_p(m)); + free (n); + n = NULL; + pos++; + } + /* pad unused tail (ditto) */ + bitset_size = max_memno; + if (max_memno > 31) + bitset_size += 64 - (max_memno % 64); + else + bitset_size = 32; + if (pos < bitset_size) + fprintf(jsonfile, ","); + while (pos < bitset_size) { + char *n = NULL; + if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 || + n == NULL) + errx(1, "malloc"); + define_type(level + 1, n, newbasename, NULL, &i, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "%s", (pos + 1) < bitset_size ? "," : ""); + free(n); + pos++; + } + + space(level); + fprintf(headerfile, "}%s%s;\n\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + fprintf(jsonfile, "]"); + } + break; + } + case TEnumerated: { + Member *m; + + if (t->symbol && t->symbol->emitted_definition) + break; + + label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : ""); + label_prefix_sep = prefix_enum ? "_" : ""; + space(level); + fprintf (headerfile, "enum %s {\n", (opts & DEF_TYPE_TYPEDEFP) ? name : ""); + fprintf(jsonfile, "\"ctype\":\"enum %s\",\"extensible\":%s,\"members\":[\n", + (opts & DEF_TYPE_TYPEDEFP) ? name : "", have_ellipsis(t) ? "true" : "false"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space(level + 1); + if (m->ellipsis) { + fprintf (headerfile, "/* ... */\n"); + } else { + fprintf(headerfile, "%s%s%s = %lld%s\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + fprintf(jsonfile, "{\"%s%s%s\":%lld%s}\n", + label_prefix, label_prefix_sep, + m->gen_name, (long long)m->val, last_member_p(m)); + } + } + space(level); + fprintf(headerfile, "}%s%s;\n\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + fprintf(jsonfile, "]"); + break; + } + case TSet: + case TSequence: { + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + int decorated = 0; + + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + space(level); + + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ttype\":\"%s\",\"extensible\":%s," + "\"ctype\":\"struct %s\"", + t->type == TSet ? "SET" : "SEQUENCE", + have_ellipsis(t) ? "true" : "false", newbasename); + if (t->type == TSequence && (opts & DEF_TYPE_PRESERVE)) { + space(level + 1); + fprintf(headerfile, "heim_octet_string _save;\n"); + fprintf(jsonfile, ",\"preserve\":true"); + } + fprintf(jsonfile, ",\"members\":[\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->ellipsis) { + ; + } else if (m->optional || m->defval) { + char *n = NULL, *defval = NULL; + const char *namep, *defvalp; + + if (m->defval) { + switch (m->defval->type) { + case stringvalue: + if (asprintf(&defval, "\"%s\"", m->defval->u.stringvalue) < 0 || defval == NULL) + errx(1, "malloc"); + defvalp = defval; + break; + case integervalue: + if (asprintf(&defval, "%lld", (long long)m->defval->u.integervalue) < 0 || defval == NULL) + errx(1, "malloc"); + defvalp = defval; + break; + case booleanvalue: + defvalp = m->defval->u.booleanvalue ? "true" : "false"; + break; + default: + abort(); + } + } else + defvalp = "null"; + + if (m->optional) { + if (asprintf(&n, "*%s", m->gen_name) < 0 || n == NULL) + errx(1, "malloc"); + namep = n; + } else + namep = m->gen_name; + + fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"optional\":%s,\"defval\":%s,\"type\":", + m->name, m->gen_name, m->optional ? "true" : "false", defvalp); + define_type(level + 1, namep, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "}%s", last_member_p(m)); + free (n); + free (defval); + } else { + fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\"," + "\"optional\":false,\"type\":", m->name, m->gen_name); + define_type(level + 1, m->gen_name, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "}%s", last_member_p(m)); + } + } + fprintf(jsonfile, "]"); + if (t->actual_parameter && t->actual_parameter->objects) { + fprintf(jsonfile, ",\"opentype\":"); + define_open_type(level, newbasename, name, basename, t, t); + } + while (decorate_type(newbasename, &deco, &more_deco)) { + decorated++; + space(level + 1); + fprintf(headerfile, "%s %s%s;\n", deco.field_type, + deco.opt ? "*" : "", deco.field_name); + if (deco.first) + fprintf(jsonfile, ",\"decorate\":["); + fprintf(jsonfile, "%s{" + "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s," + "\"external\":%s,\"pointer\":%s,\"void_star\":%s," + "\"struct_star\":%s," + "\"copy_function\":\"%s\"," + "\"free_function\":\"%s\",\"header_name\":%s%s%s" + "}", + deco.first ? "" : ",", + deco.field_type, deco.field_name, + deco.opt ? "true" : "false", deco.ext ? "true" : "false", + deco.ptr ? "true" : "false", deco.void_star ? "true" : "false", + deco.struct_star ? "true" : "false", + deco.copy_function_name ? deco.copy_function_name : "", + deco.free_function_name ? deco.free_function_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"", + deco.header_name ? deco.header_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"" + ); + } + if (decorated) + fprintf(jsonfile, "]"); + space(level); + fprintf(headerfile, "}%s%s;\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + free(deco.field_type); + break; + } + case TSetOf: + case TSequenceOf: { + Type i; + struct range range = { 0, UINT_MAX }; + + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + memset(&i, 0, sizeof(i)); + i.type = TInteger; + i.range = ⦥ + + space(level); + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ttype\":\"%s\",\"ctype\":\"struct %s\",\"members\":[", + t->type == TSetOf ? "SET OF" : "SEQUENCE OF", newbasename); + define_type(level + 1, "len", newbasename, t, &i, DEF_TYPE_NONE); + fprintf(jsonfile, ","); + define_type(level + 1, "*val", newbasename, t, t->subtype, DEF_TYPE_NONE | DEF_TYPE_EMIT_NAME); + space(level); + fprintf(headerfile, "}%s%s;\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + fprintf(jsonfile, "]"); + break; + } + case TGeneralizedTime: + space(level); + fprintf (headerfile, "time_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"GeneralizedTime\",\"ctype\":\"time_t\""); + break; + case TGeneralString: + space(level); + fprintf (headerfile, "heim_general_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"GeneralString\",\"ctype\":\"heim_general_string\""); + break; + case TTeletexString: + space(level); + fprintf (headerfile, "heim_general_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"TeletexString\",\"ctype\":\"heim_general_string\""); + break; + case TTag: + if (t->implicit_choice) { + fprintf(jsonfile, "\"desired_tagenv\":\"IMPLICIT\","); + } + fprintf(jsonfile, "\"tagclass\":\"%s\",\"tagvalue\":%d,\"tagenv\":\"%s\",\n", + tagclassnames[t->tag.tagclass], t->tag.tagvalue, + t->tag.tagenv == TE_EXPLICIT ? "EXPLICIT" : "IMPLICIT"); + fprintf(jsonfile, "\"ttype\":\n"); + define_type(level, name, basename, t, t->subtype, opts); + break; + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + int decorated = 0; + int first = 1; + Member *m; + + getnewbasename(&newbasename, (opts & DEF_TYPE_TYPEDEFP) || level == 0, basename, name); + + space(level); + fprintf (headerfile, "struct %s {\n", newbasename); + fprintf(jsonfile, "\"ttype\":\"CHOICE\",\"ctype\":\"struct %s\"", + newbasename); + if ((opts & DEF_TYPE_PRESERVE)) { + space(level + 1); + fprintf(headerfile, "heim_octet_string _save;\n"); + fprintf(jsonfile, ",\"preserve\":true"); + } + space(level + 1); + fprintf (headerfile, "enum %s_enum {\n", newbasename); + m = have_ellipsis(t); + if (m) { + space(level + 2); + fprintf (headerfile, "%s = 0,\n", m->label); + first = 0; + } + fprintf(jsonfile, ",\"extensible\":%s", m ? "true" : "false"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + space(level + 2); + if (m->ellipsis) + fprintf (headerfile, "/* ... */\n"); + else + fprintf (headerfile, "%s%s%s\n", m->label, + first ? " = 1" : "", + last_member_p(m)); + first = 0; + } + space(level + 1); + fprintf (headerfile, "} element;\n"); + space(level + 1); + fprintf (headerfile, "union {\n"); + fprintf(jsonfile, ",\"members\":[\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->ellipsis) { + space(level + 2); + fprintf(headerfile, "heim_octet_string asn1_ellipsis;\n"); + } else if (m->optional) { + char *n = NULL; + + if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL) + errx(1, "malloc"); + fprintf(jsonfile, "{\"optional\":"); + define_type(level + 2, n, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "}%s", last_member_p(m)); + free (n); + } else { + define_type(level + 2, m->gen_name, newbasename, t, m->type, DEF_TYPE_EMIT_NAME); + fprintf(jsonfile, "%s", last_member_p(m)); + } + } + space(level + 1); + fprintf (headerfile, "} u;\n"); + fprintf(jsonfile, "]"); + + while (decorate_type(newbasename, &deco, &more_deco)) { + decorated++; + space(level + 1); + fprintf(headerfile, "%s %s%s;\n", deco.field_type, + deco.opt ? "*" : "", deco.field_name); + if (deco.first) + fprintf(jsonfile, ",\"decorate\":["); + fprintf(jsonfile, "%s{" + "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s," + "\"external\":%s,\"pointer\":%s,\"void_star\":%s," + "\"struct_star\":%s," + "\"copy_function\":\"%s\"," + "\"free_function\":\"%s\",\"header_name\":%s%s%s" + "}", + deco.first ? "" : ",", + deco.field_type, deco.field_name, + deco.opt ? "true" : "false", deco.ext ? "true" : "false", + deco.ptr ? "true" : "false", deco.void_star ? "true" : "false", + deco.struct_star ? "true" : "false", + deco.copy_function_name ? deco.copy_function_name : "", + deco.free_function_name ? deco.free_function_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"", + deco.header_name ? deco.header_name : "", + deco.header_name && deco.header_name[0] == '"' ? "" : "\"" + ); + } + if (decorated) + fprintf(jsonfile, "]"); + + space(level); + fprintf(headerfile, "}%s%s;\n", + (opts & DEF_TYPE_EMIT_NAME) ? " " : "", + (opts & DEF_TYPE_EMIT_NAME) ? name : ""); + break; + } + case TUTCTime: + space(level); + fprintf (headerfile, "time_t %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"UTCTime\",\"ctype\":\"time_t\""); + break; + case TUTF8String: + space(level); + fprintf (headerfile, "heim_utf8_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"UTF8String\",\"ctype\":\"heim_utf8_string\""); + break; + case TPrintableString: + space(level); + fprintf (headerfile, "heim_printable_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"PrintableString\",\"ctype\":\"heim_printable_string\""); + break; + case TIA5String: + space(level); + fprintf (headerfile, "heim_ia5_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"IA5String\",\"ctype\":\"heim_ia5_string\""); + break; + case TBMPString: + space(level); + fprintf (headerfile, "heim_bmp_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"BMPString\",\"ctype\":\"heim_bmp_string\""); + break; + case TUniversalString: + space(level); + fprintf (headerfile, "heim_universal_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"UniversalString\",\"ctype\":\"heim_universal_string\""); + break; + case TVisibleString: + space(level); + fprintf (headerfile, "heim_visible_string %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"VisibleString\",\"ctype\":\"heim_visible_string\""); + break; + case TOID : + space(level); + fprintf (headerfile, "heim_oid %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"OBJECT IDENTIFIER\",\"ctype\":\"heim_oid\""); + break; + case TNull: + space(level); + fprintf (headerfile, "int %s;\n", name); + fprintf(jsonfile, "\"ttype\":\"NULL\",\"ctype\":\"int\""); + break; + default: + abort (); + } + fprintf(jsonfile, "}\n"); + free(newbasename); +} + +static void +declare_type(const Symbol *s, Type *t, int typedefp) +{ + char *newbasename = NULL; + + if (typedefp) + fprintf(headerfile, "typedef "); + + switch (t->type) { + case TType: + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_PRESERVE | DEF_TYPE_TYPEDEFP | + (s->emitted_declaration ? 0 : DEF_TYPE_EMIT_NAME)); + if (template_flag && !s->emitted_declaration) + generate_template_type_forward(s->gen_name); + emitted_declaration(s); + return; + case TInteger: + case TBoolean: + case TOctetString: + case TBitString: + case TEnumerated: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TUTCTime: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TOID : + case TNull: + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_PRESERVE | DEF_TYPE_TYPEDEFP | + (s->emitted_declaration ? 0 : DEF_TYPE_EMIT_NAME)); + if (template_flag && !s->emitted_declaration) + generate_template_type_forward(s->gen_name); + emitted_declaration(s); + emitted_definition(s); + return; + case TTag: + if (!s->emitted_declaration) + declare_type(s, t->subtype, FALSE); + emitted_declaration(s); + return; + default: + break; + } + + switch (t->type) { + case TSet: + case TSequence: { + struct decoration deco; + ssize_t more_deco = -1; + + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); + fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + while (decorate_type(newbasename, &deco, &more_deco)) { + if (deco.header_name) + fprintf(headerfile, "#include %s\n", deco.header_name); + free(deco.field_type); + } + break; + } + case TSetOf: + case TSequenceOf: + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); + fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + break; + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + + getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name); + fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name); + while (decorate_type(newbasename, &deco, &more_deco)) { + if (deco.header_name) + fprintf(headerfile, "#include %s\n", deco.header_name); + free(deco.field_type); + } + break; + } + default: + abort (); + } + free(newbasename); + emitted_declaration(s); +} + +static void generate_subtypes_header_helper(const Member *m); +static void generate_type_header(const Symbol *); + +static void +generate_subtypes_header_helper(const Member *m) +{ + Member *sm; + Symbol *s; + + if (m->ellipsis) + return; + if (m->type->symbol && (s = getsym(m->type->symbol->name)) && + !s->emitted_definition) { + /* A field of some named type; recurse */ + if (!m->optional && !m->defval) + generate_type_header(s); + return; + } + if (!m->type->subtype && !m->type->members) + return; + if (m->type->type == TTag && + m->type->subtype && m->type->subtype->symbol && + (s = getsym(m->type->subtype->symbol->name))) { + if (!m->optional && !m->defval) + generate_type_header(s); + return; + } + if (m->type->subtype) { + switch (m->type->subtype->type) { + case TSet: + case TSequence: + case TChoice: + break; + default: + return; + } + /* A field of some anonymous (inlined) structured type */ + HEIM_TAILQ_FOREACH(sm, m->type->subtype->members, members) { + generate_subtypes_header_helper(sm); + } + } + if (m->type->members) { + HEIM_TAILQ_FOREACH(sm, m->type->members, members) { + generate_subtypes_header_helper(sm); + } + } +} + +static void +generate_subtypes_header(const Symbol *s) +{ + Type *t = s->type; + Member *m; + + /* + * Recurse down structured types to make sure top-level types get + * defined before they are referenced. + * + * We'll take care to skip OPTIONAL member fields of constructed types so + * that we can have circular types like: + * + * Foo ::= SEQUENCE { + * bar Bar OPTIONAL + * } + * + * Bar ::= SEQUENCE { + * foo Foo OPTIONAL + * } + * + * not unlike XDR, which uses `*' to mean "optional", except in XDR it's + * called a "pointer". With some care we should be able to eventually + * support the silly XDR linked list example: + * + * ListOfFoo ::= SEQUENCE { + * someField SomeType, + * next ListOfFoo OPTIONAL + * } + * + * Not that anyone needs it -- just use a SEQUENCE OF and be done. + */ + + while (t->type == TTag && t->subtype) { + switch (t->subtype->type) { + case TTag: + case TSet: + case TSequence: + case TChoice: + t = t->subtype; + continue; + default: + break; + } + break; + } + + switch (t->type) { + default: return; + case TType: { + Symbol *s2; + if (t->symbol && (s2 = getsym(t->symbol->name)) != s) + generate_type_header(s2); + return; + } + case TSet: + case TSequence: + case TChoice: + break; + } + + HEIM_TAILQ_FOREACH(m, t->members, members) { + generate_subtypes_header_helper(m); + } +} + +static void +generate_type_header (const Symbol *s) +{ + Type *t = s->type; + + if (!s->type) + return; + + /* + * Recurse down the types of member fields of `s' to make sure that + * referenced types have had their definitions emitted already if the + * member fields are not OPTIONAL/DEFAULTed. + */ + generate_subtypes_header(s); + if (!s->emitted_asn1) { + fprintf(headerfile, "/*\n"); + fprintf(headerfile, "%s ::= ", s->name); + define_asn1 (0, s->type); + fprintf(headerfile, "\n*/\n\n"); + emitted_asn1(s); + } + + /* + * Emit enums for the outermost tag of this type. These are needed for + * dealing with IMPLICIT tags so we know what to rewrite the tag to when + * decoding. + * + * See gen_encode.c and gen_decode.c for a complete explanation. Short + * version: we need to change the prototypes of the length/encode/decode + * functions to take an optional IMPLICIT tag to use instead of the type's + * outermost tag, but for now we hack it, and to do that we need to know + * the type's outermost tag outside the context of the bodies of the codec + * functions we generate for it. Using an enum means no extra space is + * needed in stripped objects. + */ + if (!s->emitted_tag_enums) { + while (t->type == TType && s->type->symbol && s->type->symbol->type) { + if (t->subtype) + t = t->subtype; + else + t = s->type->symbol->type; + } + + if (t->type == TType && t->symbol && + strcmp(t->symbol->name, "HEIM_ANY") != 0) { + /* + * This type is ultimately an alias of an imported type, so we don't + * know its outermost tag here. + */ + fprintf(headerfile, + "enum { asn1_tag_length_%s = asn1_tag_length_%s,\n" + " asn1_tag_class_%s = asn1_tag_class_%s,\n" + " asn1_tag_tag_%s = asn1_tag_tag_%s };\n", + s->gen_name, s->type->symbol->gen_name, + s->gen_name, s->type->symbol->gen_name, + s->gen_name, s->type->symbol->gen_name); + emitted_tag_enums(s); + } else if (t->type != TType) { + /* This type's outermost tag is known here */ + fprintf(headerfile, + "enum { asn1_tag_length_%s = %lu,\n" + " asn1_tag_class_%s = %d,\n" + " asn1_tag_tag_%s = %d };\n", + s->gen_name, (unsigned long)length_tag(s->type->tag.tagvalue), + s->gen_name, s->type->tag.tagclass, + s->gen_name, s->type->tag.tagvalue); + emitted_tag_enums(s); + } + } + + if (s->emitted_definition) + return; + + if (is_export(s->name)) + fprintf(symsfile, "ASN1_SYM_TYPE(\"%s\", \"%s\", %s)\n", + s->name, s->gen_name, s->gen_name); + + if (!s->emitted_declaration) { + fprintf(headerfile, "typedef "); + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_TYPEDEFP | DEF_TYPE_EMIT_NAME | + (preserve_type(s->name) ? DEF_TYPE_PRESERVE : 0)); + } else if (s->type->type == TType) { + /* This is a type alias and we've already declared it */ + } else if (s->type->type == TTag && + s->type->subtype != NULL && + s->type->subtype->symbol != NULL) { + /* This is a type alias and we've already declared it */ + } else { + define_type(0, s->gen_name, s->gen_name, NULL, s->type, + DEF_TYPE_TYPEDEFP | + (preserve_type(s->name) ? DEF_TYPE_PRESERVE : 0)); + } + fprintf(headerfile, "\n"); + + emitted_definition(s); +} + +void +generate_type_header_forwards(const Symbol *s) +{ + declare_type(s, s->type, TRUE); + fprintf(headerfile, "\n"); + if (template_flag) + generate_template_type_forward(s->gen_name); +} + +void +generate_type (const Symbol *s) +{ + FILE *h; + const char * exp; + + if (!one_code_file) + generate_header_of_codefile(s->gen_name); + + generate_type_header(s); + + if (template_flag) + generate_template(s); + + if (template_flag == 0 || is_template_compat(s) == 0) { + generate_type_encode (s); + generate_type_decode (s); + generate_type_free (s); + generate_type_length (s); + generate_type_copy (s); + generate_type_print_stub(s); + } + generate_type_seq (s); + generate_glue (s->type, s->gen_name); + + /* generate prototypes */ + + if (is_export(s->name)) { + h = headerfile; + exp = "ASN1EXP "; + } else { + h = privheaderfile; + exp = ""; + } + + fprintf (h, + "%sint ASN1CALL " + "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n", + exp, + s->gen_name, s->gen_name); + fprintf (h, + "%sint ASN1CALL " + "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n", + exp, + s->gen_name, s->gen_name); + fprintf (h, + "%ssize_t ASN1CALL length_%s(const %s *);\n", + exp, + s->gen_name, s->gen_name); + fprintf (h, + "%sint ASN1CALL copy_%s (const %s *, %s *);\n", + exp, + s->gen_name, s->gen_name, s->gen_name); + fprintf (h, + "%svoid ASN1CALL free_%s (%s *);\n", + exp, + s->gen_name, s->gen_name); + + fprintf(h, + "%schar * ASN1CALL print_%s (const %s *, int);\n", + exp, + s->gen_name, s->gen_name); + + fprintf(h, "\n\n"); + + if (!one_code_file) { + fprintf(codefile, "\n\n"); + close_codefile(); + } +} diff --git a/third_party/heimdal/lib/asn1/gen_copy.c b/third_party/heimdal/lib/asn1/gen_copy.c new file mode 100644 index 0000000..c6d420a --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_copy.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static int used_fail; + +static void +copy_primitive (const char *typename, const char *from, const char *to) +{ + fprintf (codefile, "if(der_copy_%s(%s, %s)) goto fail;\n", + typename, from, to); + used_fail++; +} + +static void +copy_type (const char *from, const char *to, const Type *t, int preserve) +{ + switch (t->type) { + case TType: +#if 0 + copy_type (from, to, t->symbol->type, preserve); +#endif + fprintf (codefile, "if(copy_%s(%s, %s)) goto fail;\n", + t->symbol->gen_name, from, to); + used_fail++; + break; + case TInteger: + if (t->range == NULL && t->members == NULL) { + copy_primitive ("heim_integer", from, to); + break; + } + HEIM_FALLTHROUGH; + case TBoolean: + case TEnumerated : + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TOctetString: + copy_primitive ("octet_string", from, to); + break; + case TBitString: + if (HEIM_TAILQ_EMPTY(t->members)) + copy_primitive ("bit_string", from, to); + else + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TSet: + case TSequence: + case TChoice: { + Member *m, *have_ellipsis = NULL; + + if(t->members == NULL) + break; + + if ((t->type == TSequence || t->type == TChoice) && preserve) { + fprintf(codefile, + "{ int ret;\n" + "ret = der_copy_octet_string(&(%s)->_save, &(%s)->_save);\n" + "if (ret) goto fail;\n" + "}\n", + from, to); + used_fail++; + } + + if(t->type == TChoice) { + fprintf(codefile, "(%s)->element = (%s)->element;\n", to, from); + fprintf(codefile, "switch((%s)->element) {\n", from); + } + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *fs; + char *ts; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + if(t->type == TChoice) + fprintf(codefile, "case %s:\n", m->label); + + if (asprintf (&fs, "%s(%s)->%s%s", + m->optional ? "" : "&", from, + t->type == TChoice ? "u." : "", m->gen_name) < 0) + errx(1, "malloc"); + if (fs == NULL) + errx(1, "malloc"); + if (asprintf (&ts, "%s(%s)->%s%s", + m->optional ? "" : "&", to, + t->type == TChoice ? "u." : "", m->gen_name) < 0) + errx(1, "malloc"); + if (ts == NULL) + errx(1, "malloc"); + if(m->optional){ + fprintf(codefile, "if(%s) {\n", fs); + fprintf(codefile, "%s = calloc(1, sizeof(*%s));\n", ts, ts); + fprintf(codefile, "if(%s == NULL) goto fail;\n", ts); + used_fail++; + } + copy_type (fs, ts, m->type, FALSE); + if(m->optional){ + fprintf(codefile, "}else\n"); + fprintf(codefile, "%s = NULL;\n", ts); + } + free (fs); + free (ts); + if(t->type == TChoice) + fprintf(codefile, "break;\n"); + } + if(t->type == TChoice) { + if (have_ellipsis) { + fprintf(codefile, "case %s: {\n" + "int ret;\n" + "ret=der_copy_octet_string(&(%s)->u.%s, &(%s)->u.%s);\n" + "if (ret) goto fail;\n" + "break;\n" + "}\n", + have_ellipsis->label, + from, have_ellipsis->gen_name, + to, have_ellipsis->gen_name); + used_fail++; + } + fprintf(codefile, "}\n"); + } + break; + } + case TSetOf: + case TSequenceOf: { + char *f = NULL, *T = NULL; + + fprintf (codefile, "if(((%s)->val = " + "calloc(1, (%s)->len * sizeof(*(%s)->val))) == NULL && (%s)->len != 0)\n", + to, from, to, from); + fprintf (codefile, "goto fail;\n"); + used_fail++; + fprintf(codefile, + "for((%s)->len = 0; (%s)->len < (%s)->len; (%s)->len++){\n", + to, to, from, to); + if (asprintf(&f, "&(%s)->val[(%s)->len]", from, to) < 0) + errx(1, "malloc"); + if (f == NULL) + errx(1, "malloc"); + if (asprintf(&T, "&(%s)->val[(%s)->len]", to, to) < 0) + errx(1, "malloc"); + if (T == NULL) + errx(1, "malloc"); + copy_type(f, T, t->subtype, FALSE); + fprintf(codefile, "}\n"); + free(f); + free(T); + break; + } + case TGeneralizedTime: + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TGeneralString: + copy_primitive ("general_string", from, to); + break; + case TTeletexString: + copy_primitive ("general_string", from, to); + break; + case TUTCTime: + fprintf(codefile, "*(%s) = *(%s);\n", to, from); + break; + case TUTF8String: + copy_primitive ("utf8string", from, to); + break; + case TPrintableString: + copy_primitive ("printable_string", from, to); + break; + case TIA5String: + copy_primitive ("ia5_string", from, to); + break; + case TBMPString: + copy_primitive ("bmp_string", from, to); + break; + case TUniversalString: + copy_primitive ("universal_string", from, to); + break; + case TVisibleString: + copy_primitive ("visible_string", from, to); + break; + case TTag: + copy_type (from, to, t->subtype, preserve); + break; + case TOID: + copy_primitive ("oid", from, to); + break; + case TNull: + break; + default : + abort (); + } +} + +void +generate_type_copy (const Symbol *s) +{ + struct decoration deco; + ssize_t more_deco = -1; + int preserve = preserve_type(s->name) ? TRUE : FALSE; + int save_used_fail = used_fail; + + used_fail = 0; + + fprintf (codefile, "int ASN1CALL\n" + "copy_%s(const %s *from, %s *to)\n" + "{\n" + "memset(to, 0, sizeof(*to));\n", + s->gen_name, s->gen_name, s->gen_name); + copy_type ("from", "to", s->type, preserve); + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (deco.ext && deco.copy_function_name == NULL) { + /* Decorated with field of external type but no copy function */ + if (deco.ptr) + fprintf(codefile, "(to)->%s = 0;\n", deco.field_name); + else + fprintf(codefile, "memset(&(to)->%s, 0, sizeof((to)->%s));\n", + deco.field_name, deco.field_name); + } else if (deco.ext) { + /* Decorated with field of external type w/ copy function */ + if (deco.ptr) { + fprintf(codefile, "if (from->%s) {\n", deco.field_name); + fprintf(codefile, "(to)->%s = calloc(1, sizeof(*(to)->%s));\n", + deco.field_name, deco.field_name); + fprintf(codefile, "if (%s((from)->%s, (to)->%s)) goto fail;\n", + deco.copy_function_name, deco.field_name, deco.field_name); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "if (%s(&(from)->%s, &(to)->%s)) goto fail;\n", + deco.copy_function_name, deco.field_name, deco.field_name); + } + } else if (deco.opt) { + /* Decorated with optional field of ASN.1 type */ + fprintf(codefile, "if (from->%s) {\n", deco.field_name); + fprintf(codefile, "(to)->%s = calloc(1, sizeof(*(to)->%s));\n", deco.field_name, deco.field_name); + fprintf(codefile, "if (copy_%s((from)->%s, (to)->%s)) goto fail;\n", deco.field_type, deco.field_name, deco.field_name); + fprintf(codefile, "}\n"); + } else { + /* Decorated with required field of ASN.1 type */ + fprintf(codefile, "if (copy_%s(&(from)->%s, &(to)->%s)) goto fail;\n", deco.field_type, deco.field_name, deco.field_name); + } + used_fail++; + free(deco.field_type); + } + fprintf (codefile, "return 0;\n"); + + if (used_fail) + fprintf (codefile, "fail:\n" + "free_%s(to);\n" + "return ENOMEM;\n", + s->gen_name); + + fprintf(codefile, + "}\n\n"); + used_fail = save_used_fail; +} + diff --git a/third_party/heimdal/lib/asn1/gen_decode.c b/third_party/heimdal/lib/asn1/gen_decode.c new file mode 100644 index 0000000..fa9d79a --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_decode.c @@ -0,0 +1,841 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" +#include "lex.h" + +RCSID("$Id$"); + +static void +decode_primitive (const char *typename, const char *name, const char *forwstr) +{ +#if 0 + fprintf (codefile, + "e = decode_%s(p, len, %s, &l);\n" + "%s;\n", + typename, + name, + forwstr); +#else + fprintf (codefile, + "e = der_get_%s(p, len, %s, &l);\n" + "if(e) %s;\np += l; len -= l; ret += l;\n", + typename, + name, + forwstr); +#endif +} + +static void +find_tag (const Type *t, + Der_class *cl, Der_type *ty, unsigned *tag) +{ + switch (t->type) { + case TBitString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_BitString; + break; + case TBoolean: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Boolean; + break; + case TChoice: + errx(1, "Cannot have recursive CHOICE"); + case TEnumerated: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Enumerated; + break; + case TGeneralString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_GeneralString; + break; + case TTeletexString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_TeletexString; + break; + case TGeneralizedTime: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_GeneralizedTime; + break; + case TIA5String: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_IA5String; + break; + case TInteger: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Integer; + break; + case TNull: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_Null; + break; + case TOID: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_OID; + break; + case TOctetString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_OctetString; + break; + case TPrintableString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_PrintableString; + break; + case TSequence: + case TSequenceOf: + *cl = ASN1_C_UNIV; + *ty = CONS; + *tag = UT_Sequence; + break; + case TSet: + case TSetOf: + *cl = ASN1_C_UNIV; + *ty = CONS; + *tag = UT_Set; + break; + case TTag: + *cl = t->tag.tagclass; + *ty = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype) ? PRIM : CONS; + *tag = t->tag.tagvalue; /* XXX is this correct? */ + break; + case TType: + if ((t->symbol->stype == Stype && t->symbol->type == NULL) + || t->symbol->stype == SUndefined) { + lex_error_message("%s is imported or still undefined, " + " can't generate tag checking data in CHOICE " + "without this information", + t->symbol->name); + exit(1); + } + find_tag(t->symbol->type, cl, ty, tag); + return; + case TUTCTime: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_UTCTime; + break; + case TUTF8String: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_UTF8String; + break; + case TBMPString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_BMPString; + break; + case TUniversalString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_UniversalString; + break; + case TVisibleString: + *cl = ASN1_C_UNIV; + *ty = PRIM; + *tag = UT_VisibleString; + break; + default: + abort(); + } +} + +static void +range_check(const char *name, + const char *length, + const char *forwstr, + struct range *r) +{ + if (r->min == r->max + 2 || r->min < r->max) + fprintf (codefile, + "if ((%s)->%s > %lld) {\n" + "e = ASN1_MAX_CONSTRAINT; %s;\n" + "}\n", + name, length, (long long)r->max, forwstr); + if ((r->min - 1 == r->max || r->min < r->max) && r->min > 0) + fprintf (codefile, + "if ((%s)->%s < %lld) {\n" + "e = ASN1_MIN_CONSTRAINT; %s;\n" + "}\n", + name, length, (long long)r->min, forwstr); + if (r->max == r->min) + fprintf (codefile, + "if ((%s)->%s != %lld) {\n" + "e = ASN1_EXACT_CONSTRAINT; %s;\n" + "}\n", + name, length, (long long)r->min, forwstr); +} + +static int +decode_type(const char *name, const Type *t, int optional, struct value *defval, + const char *forwstr, const char *tmpstr, const char *dertype, + unsigned int depth) +{ + switch (t->type) { + case TType: { + if (optional) + fprintf(codefile, + "%s = calloc(1, sizeof(*%s));\n" + "if (%s == NULL) %s;\n", + name, name, name, forwstr); + fprintf (codefile, + "e = decode_%s(p, len, %s, &l);\n", + t->symbol->gen_name, name); + if (optional) { + fprintf (codefile, + "if(e == ASN1_MISSING_FIELD) {\n" + "free(%s);\n" + "%s = NULL;\n" + "} else if (e) { %s; \n" + "} else {\n" + "p += l; len -= l; ret += l;\n" + "}\n", + name, name, forwstr); + } else if (defval) { + fprintf(codefile, + "if (e == ASN1_MISSING_FIELD) {\n"); + /* + * `name' starts with an ampersand here and is not an lvalue. + * We skip the ampersand and then it is an lvalue. + */ + gen_assign_defval(name + 1, defval); + fprintf(codefile, + "} else if (e) { %s;\n" + "} else { p += l; len -= l; ret += l; }\n", + forwstr); + } else { + fprintf (codefile, + "if(e) %s;\n", + forwstr); + fprintf (codefile, + "p += l; len -= l; ret += l;\n"); + } + break; + } + case TInteger: + if(t->members) { + /* + * This will produce a worning, how its hard to fix since: + * if its enum to an NameType, we can add appriate + * type-cast. If its not though, we have to figure out if + * there is negative enum enum and use appropriate + * signness and size on the intertype we cast the result + * too. + */ + fprintf(codefile, + "{\n" + "int enumint;\n"); + decode_primitive ("integer", "&enumint", forwstr); + fprintf(codefile, + "*%s = enumint;\n" + "}\n", + name); + } else if (t->range == NULL) { + decode_primitive ("heim_integer", name, forwstr); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + decode_primitive ("integer64", name, forwstr); + } else if (t->range->min < 0) { + decode_primitive ("integer", name, forwstr); + } else if (t->range->max > UINT_MAX) { + decode_primitive ("unsigned64", name, forwstr); + } else { + decode_primitive ("unsigned", name, forwstr); + } + break; + case TBoolean: + decode_primitive ("boolean", name, forwstr); + break; + case TEnumerated: + decode_primitive ("enumerated", name, forwstr); + break; + case TOctetString: + if (dertype) { + fprintf(codefile, + "if (%s == CONS) {\n", + dertype); + decode_primitive("octet_string_ber", name, forwstr); + fprintf(codefile, + "} else {\n"); + } + decode_primitive ("octet_string", name, forwstr); + if (dertype) + fprintf(codefile, "}\n"); + if (t->range) + range_check(name, "length", forwstr, t->range); + break; + case TBitString: { + Member *m; + int pos = 0; + + if (HEIM_TAILQ_EMPTY(t->members)) { + decode_primitive ("bit_string", name, forwstr); + break; + } + fprintf(codefile, + "if (len < 1) return ASN1_OVERRUN;\n" + "p++; len--; ret++;\n"); + fprintf(codefile, + "do {\n" + "if (len < 1) break;\n"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + while (m->val / 8 > pos / 8) { + fprintf (codefile, + "p++; len--; ret++;\n" + "if (len < 1) break;\n"); + pos += 8; + } + fprintf(codefile, + "(%s)->%s = (*p >> %d) & 1;\n", + name, m->gen_name, (int)(7 - m->val % 8)); + } + fprintf(codefile, + "} while(0);\n"); + fprintf (codefile, + "p += len; ret += len;\n"); + break; + } + case TSequence: { + Member *m; + + if (t->members == NULL) + break; + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s = NULL; + + if (m->ellipsis) + continue; + + if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", + name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + decode_type(s, m->type, m->optional, m->defval, forwstr, + m->gen_name, NULL, depth + 1); + free (s); + } + + break; + } + case TSet: { + /* + * SET { ... } is the dumbest construct in ASN.1. It's semantically + * indistinguishable from SEQUENCE { ... } but in BER you can write the + * fields in any order you wish, and in DER you have to write them in + * lexicographic order. If you want a reason to hate ASN.1, this is + * certainly one, though the real reason to hate ASN.1 is BER/DER/CER, + * and, really, all tag-length-value (TLV) encodings ever invented, + * including Protocol Buffers. Fortunately not all ASN.1 encoding + * rules are TLV or otherwise self-describing. "Self-describing" + * encoding rules other than those meant to be [somewhat] readable by + * humans, such as XML and JSON, are simply dumb. But SET { ... } is a + * truly special sort of dumb. The only possible use of SET { ... } + * might well be for ASN.1 mappings of XML schemas(?). + */ + Member *m; + unsigned int memno; + + if(t->members == NULL) + break; + + fprintf(codefile, "{\n"); + fprintf(codefile, "uint64_t members = 0;\n"); + fprintf(codefile, "while(len > 0) {\n"); + fprintf(codefile, + "Der_class class;\n" + "Der_type type;\n" + "unsigned int tag;\n" + "e = der_get_tag (p, len, &class, &type, &tag, NULL);\n" + "if(e) %s;\n", forwstr); + fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n"); + memno = 0; + HEIM_TAILQ_FOREACH(m, t->members, members) { + Type *mst = m->type; /* Member sub-type */ + char *s; + + while (mst->type == TType) { + assert(mst->subtype || (mst->symbol && mst->symbol->type)); + mst = mst->subtype ? mst->subtype : mst->symbol->type; + } + assert(mst->type == TTag); + + fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n", + classname(mst->tag.tagclass), + (mst->tag.tagclass == ASN1_C_UNIV || mst->tag.tagenv == TE_IMPLICIT) && + is_primitive_type(mst->subtype) ? "PRIM" : "CONS", + valuename(mst->tag.tagclass, mst->tag.tagvalue)); + + if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + if(m->optional) + fprintf(codefile, + "%s = calloc(1, sizeof(*%s));\n" + "if (%s == NULL) { e = ENOMEM; %s; }\n", + s, s, s, forwstr); + decode_type (s, mst, 0, NULL, forwstr, m->gen_name, NULL, depth + 1); + free (s); + + fprintf(codefile, "members |= (1ULL << %u);\n", memno); + memno++; + fprintf(codefile, "break;\n"); + } + fprintf(codefile, + "default:\n" + "return ASN1_MISPLACED_FIELD;\n" + "break;\n"); + fprintf(codefile, "}\n"); + fprintf(codefile, "}\n"); + memno = 0; + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s; + + if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + fprintf(codefile, "if((members & (1ULL << %u)) == 0)\n", memno); + if(m->optional) + fprintf(codefile, "%s = NULL;\n", s); + else if(m->defval) + gen_assign_defval(s, m->defval); + else + fprintf(codefile, "return ASN1_MISSING_FIELD;\n"); + free(s); + memno++; + } + fprintf(codefile, "}\n"); + break; + } + case TSetOf: + case TSequenceOf: { + char *n = NULL; + char *sname = NULL; + + fprintf (codefile, + "{\n" + "size_t %s_origlen = len;\n" + "size_t %s_oldret = ret;\n" + "size_t %s_olen = 0;\n" + "void *%s_tmp;\n" + "ret = 0;\n" + "(%s)->len = 0;\n" + "(%s)->val = NULL;\n", + tmpstr, + tmpstr, + tmpstr, + tmpstr, + name, + name); + + fprintf (codefile, + "while(ret < %s_origlen) {\n" + "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n" + "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n" + "%s_olen = %s_nlen;\n" + "%s_tmp = realloc((%s)->val, %s_olen);\n" + "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n" + "(%s)->val = %s_tmp;\n", + tmpstr, + tmpstr, tmpstr, name, + tmpstr, tmpstr, forwstr, + tmpstr, tmpstr, + tmpstr, name, tmpstr, + tmpstr, forwstr, + name, tmpstr); + + if (asprintf (&n, "&(%s)->val[(%s)->len]", name, name) < 0 || n == NULL) + errx(1, "malloc"); + if (asprintf (&sname, "%s_s_of", tmpstr) < 0 || sname == NULL) + errx(1, "malloc"); + decode_type(n, t->subtype, 0, NULL, forwstr, sname, NULL, depth + 1); + fprintf (codefile, + "(%s)->len++;\n" + "len = %s_origlen - ret;\n" + "}\n" + "ret += %s_oldret;\n" + "}\n", + name, + tmpstr, tmpstr); + if (t->range) + range_check(name, "len", forwstr, t->range); + free (n); + free (sname); + break; + } + case TGeneralizedTime: + decode_primitive ("generalized_time", name, forwstr); + break; + case TGeneralString: + decode_primitive ("general_string", name, forwstr); + break; + case TTeletexString: + decode_primitive ("general_string", name, forwstr); + break; + case TTag:{ + char *tname = NULL, *typestring = NULL; + char *ide = NULL; + int replace_tag = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + + /* + * XXX See the comments in gen_encode() about this. + */ + if (t->tag.tagenv == TE_IMPLICIT && !prim && + t->subtype->type != TSequenceOf && t->subtype->type != TSetOf && + t->subtype->type != TChoice) { + if (t->subtype->symbol && + (t->subtype->type == TSequence || + t->subtype->type == TSet)) + replace_tag = 1; + else if (t->subtype->symbol && + strcmp(t->subtype->symbol->name, "HEIM_ANY") != 0) + replace_tag = 1; + } else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol) + replace_tag = is_tagged_type(t->subtype->symbol->type); + + if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL) + errx(1, "malloc"); + + fprintf(codefile, + "{\n" + "size_t %s_datalen;\n" + "Der_type %s;\n", + tmpstr, typestring); + if (replace_tag) + fprintf(codefile, + "const unsigned char *psave%u = p;\n" + "unsigned char *pcopy%u;\n" + "size_t lensave%u, lsave%u;\n", + depth, depth, depth, depth); + else if (support_ber) + fprintf(codefile, + "int is_indefinite%u;\n", depth); + if (!replace_tag) + fprintf(codefile, + "size_t %s_oldlen;\n", tmpstr); + + fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, " + "&%s_datalen, &l);\n", + classname(t->tag.tagclass), + typestring, + valuename(t->tag.tagclass, t->tag.tagvalue), + tmpstr); + + /* XXX hardcode for now */ + if (!replace_tag && support_ber && t->subtype->type == TOctetString) { + ide = typestring; + } else { + fprintf(codefile, + "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n", + typestring, + prim ? "PRIM" : "CONS"); + } + + if(optional) { + fprintf(codefile, + "if(e) {\n" + "%s = NULL;\n" + "} else {\n" + "%s = calloc(1, sizeof(*%s));\n" + "if (%s == NULL) { e = ENOMEM; %s; }\n", + name, name, name, name, forwstr); + } else if (defval) { + char *s; + + if (asprintf(&s, "*(%s)", name) == -1 || s == NULL) + return ENOMEM; + fprintf(codefile, "if (e && e != ASN1_MISSING_FIELD) %s;\n", forwstr); + fprintf(codefile, "if (e == ASN1_MISSING_FIELD) {\n"); + gen_assign_defval(s, defval); + free(s); + fprintf(codefile, "e = 0; l= 0;\n} else {\n"); + } else { + fprintf(codefile, "if (e) %s;\n", forwstr); + } + + if (replace_tag) + fprintf(codefile, + "lsave%u = %s_datalen + l;\n" + "lensave%u = len;\n" + "e = der_replace_tag(p, len, &pcopy%u, &len, asn1_tag_class_%s, %s, asn1_tag_tag_%s);\n" + "if (e) %s;\n" + "p = pcopy%u;\n", + depth, tmpstr, depth, depth, t->subtype->symbol->gen_name, + prim ? "PRIM" : "CONS", + t->subtype->symbol->gen_name, + forwstr, depth); + else + fprintf(codefile, + "p += l; len -= l; ret += l;\n"); + if (!replace_tag) + fprintf(codefile, + "%s_oldlen = len;\n", + tmpstr); + if (support_ber && !replace_tag) + fprintf (codefile, + "if((is_indefinite%u = _heim_fix_dce(%s_datalen, &len)) < 0)\n" + "{ e = ASN1_BAD_FORMAT; %s; }\n" + "if (is_indefinite%u) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }", + depth, tmpstr, forwstr, depth, forwstr); + else if (!replace_tag) + fprintf(codefile, + "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n" + "len = %s_datalen;\n", tmpstr, forwstr, tmpstr); + if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL) + errx(1, "malloc"); + /* + * If `replace_tag' then here `p' and `len' will be the copy mutated by + * der_replace_tag(). + */ + decode_type(name, t->subtype, 0, NULL, forwstr, tname, ide, depth + 1); + if (replace_tag) + fprintf(codefile, + "p = psave%u + lsave%u;\n" + "len = lensave%u - lsave%u;\n" + "ret += lsave%u - l;\n" + "free(pcopy%u);\n", + depth, depth, depth, depth, depth, depth); + else if(support_ber) + fprintf(codefile, + "if(is_indefinite%u){\n" + "len += 2;\n" + "e = der_match_tag_and_length(p, len, " + "(Der_class)0, &%s, UT_EndOfContent, " + "&%s_datalen, &l);\n" + "if(e) %s;\n" + "p += l; len -= l; ret += l;\n" + "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n" + "} else \n", + depth, + typestring, + tmpstr, + forwstr, + typestring, forwstr); + if (!replace_tag) + fprintf(codefile, + "len = %s_oldlen - %s_datalen;\n", + tmpstr, tmpstr); + if (optional) + fprintf(codefile, "}\n"); + else if (defval) + fprintf(codefile, "}\n"); + fprintf(codefile, "}\n"); + free(tname); + free(typestring); + break; + } + case TChoice: { + Member *m, *have_ellipsis = NULL; + const char *els = ""; + + if (t->members == NULL) + break; + + HEIM_TAILQ_FOREACH(m, t->members, members) { + const Type *tt = m->type; + char *s = NULL; + Der_class cl; + Der_type ty; + unsigned tag; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + find_tag(tt, &cl, &ty, &tag); + + fprintf(codefile, + "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n", + els, + classname(cl), + ty ? "CONS" : "PRIM", + valuename(cl, tag)); + fprintf(codefile, + "(%s)->element = %s;\n", + name, m->label); + if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&", + name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + decode_type(s, m->type, m->optional, NULL, forwstr, m->gen_name, + NULL, depth + 1); + free(s); + fprintf(codefile, + "}\n"); + els = "else "; + } + if (have_ellipsis) { + fprintf(codefile, + "else {\n" + "(%s)->element = %s;\n" + "(%s)->u.%s.data = calloc(1, len);\n" + "if ((%s)->u.%s.data == NULL) {\n" + "e = ENOMEM; %s;\n" + "}\n" + "(%s)->u.%s.length = len;\n" + "memcpy((%s)->u.%s.data, p, len);\n" + "p += len;\n" + "ret += len;\n" + "len = 0;\n" + "}\n", + name, have_ellipsis->label, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + forwstr, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name); + } else { + fprintf(codefile, + "else {\n" + "e = ASN1_PARSE_ERROR;\n" + "%s;\n" + "}\n", + forwstr); + } + break; + } + case TUTCTime: + decode_primitive ("utctime", name, forwstr); + break; + case TUTF8String: + decode_primitive ("utf8string", name, forwstr); + break; + case TPrintableString: + decode_primitive ("printable_string", name, forwstr); + break; + case TIA5String: + decode_primitive ("ia5_string", name, forwstr); + break; + case TBMPString: + decode_primitive ("bmp_string", name, forwstr); + break; + case TUniversalString: + decode_primitive ("universal_string", name, forwstr); + break; + case TVisibleString: + decode_primitive ("visible_string", name, forwstr); + break; + case TNull: + fprintf (codefile, "/* NULL */\n"); + break; + case TOID: + decode_primitive ("oid", name, forwstr); + break; + default : + abort (); + } + return 0; +} + +void +generate_type_decode (const Symbol *s) +{ + int preserve = preserve_type(s->name) ? TRUE : FALSE; + + fprintf (codefile, "int ASN1CALL\n" + "decode_%s(const unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE," + " size_t len HEIMDAL_UNUSED_ATTRIBUTE, %s *data, size_t *size)\n" + "{\n", + s->gen_name, s->gen_name); + + switch (s->type->type) { + case TInteger: + case TBoolean: + case TOctetString: + case TOID: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TUTCTime: + case TNull: + case TEnumerated: + case TBitString: + case TSequence: + case TSequenceOf: + case TSet: + case TSetOf: + case TTag: + case TType: + case TChoice: + fprintf (codefile, + "size_t ret = 0;\n" + "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" + "int e HEIMDAL_UNUSED_ATTRIBUTE;\n"); + if (preserve) + fprintf (codefile, "const unsigned char *begin = p;\n"); + + fprintf (codefile, "\n"); + fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */ + + decode_type("data", s->type, 0, NULL, "goto fail", "Top", NULL, 1); + if (preserve) + fprintf (codefile, + "data->_save.data = calloc(1, ret);\n" + "if (data->_save.data == NULL) { \n" + "e = ENOMEM; goto fail; \n" + "}\n" + "data->_save.length = ret;\n" + "memcpy(data->_save.data, begin, ret);\n"); + fprintf (codefile, + "if(size) *size = ret;\n" + "return 0;\n"); + fprintf (codefile, + "fail:\n" + "free_%s(data);\n" + "return e;\n", + s->gen_name); + break; + default: + abort (); + } + fprintf (codefile, "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_encode.c b/third_party/heimdal/lib/asn1/gen_encode.c new file mode 100644 index 0000000..403ddac --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_encode.c @@ -0,0 +1,747 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +/* XXX same as der_length_tag */ +static size_t +length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + +static void +encode_primitive (const char *typename, const char *name) +{ + fprintf (codefile, + "e = der_put_%s(p, len, %s, &l);\n" + "if (e) return e;\np -= l; len -= l; ret += l;\n\n", + typename, + name); +} + +const char * +classname(Der_class class) +{ + const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL", + "ASN1_C_CONTEXT", "ASN1_C_PRIV" }; + if ((int)class >= sizeof(cn) / sizeof(cn[0])) + return "???"; + return cn[class]; +} + + +const char * +valuename(Der_class class, int value) +{ + static char s[32]; + struct { + int value; + const char *s; + } *p, values[] = { +#define X(Y) { Y, #Y } + X(UT_BMPString), + X(UT_BitString), + X(UT_Boolean), + X(UT_EmbeddedPDV), + X(UT_Enumerated), + X(UT_External), + X(UT_GeneralString), + X(UT_GeneralizedTime), + X(UT_GraphicString), + X(UT_IA5String), + X(UT_Integer), + X(UT_Null), + X(UT_NumericString), + X(UT_OID), + X(UT_ObjectDescriptor), + X(UT_OctetString), + X(UT_PrintableString), + X(UT_Real), + X(UT_RelativeOID), + X(UT_Sequence), + X(UT_Set), + X(UT_TeletexString), + X(UT_UTCTime), + X(UT_UTF8String), + X(UT_UniversalString), + X(UT_VideotexString), + X(UT_VisibleString), +#undef X + { -1, NULL } + }; + if(class == ASN1_C_UNIV) { + for(p = values; p->value != -1; p++) + if(p->value == value) + return p->s; + } + snprintf(s, sizeof(s), "%d", value); + return s; +} + +static int +encode_type (const char *name, const Type *t, const char *tmpstr) +{ + int constructed = 1; + + switch (t->type) { + case TType: +#if 0 + encode_type (name, t->symbol->type); +#endif + fprintf (codefile, + "e = encode_%s(p, len, %s, &l);\n" + "if (e) return e;\np -= l; len -= l; ret += l;\n\n", + t->symbol->gen_name, name); + constructed = !is_primitive_type(t); + break; + case TInteger: + if(t->members) { + fprintf(codefile, + "{\n" + "int enumint = (int)*%s;\n", + name); + encode_primitive("integer", "&enumint"); + fprintf(codefile, "}\n;"); + } else if (t->range == NULL) { + encode_primitive("heim_integer", name); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + encode_primitive("integer64", name); + } else if (t->range->min < 0) { + encode_primitive("integer", name); + } else if (t->range->max > UINT_MAX) { + encode_primitive("unsigned64", name); + } else { + encode_primitive("unsigned", name); + } + + constructed = 0; + break; + case TBoolean: + encode_primitive ("boolean", name); + constructed = 0; + break; + case TOctetString: + encode_primitive ("octet_string", name); + constructed = 0; + break; + case TBitString: { + Member *m; + int pos; + + if (HEIM_TAILQ_EMPTY(t->members)) { + encode_primitive("bit_string", name); + constructed = 0; + break; + } + + fprintf (codefile, "{\n" + "unsigned char c = 0;\n"); + if (!rfc1510_bitstring) + fprintf (codefile, + "int rest = 0;\n" + "int bit_set = 0;\n"); +#if 0 + pos = t->members->prev->val; + /* fix for buggy MIT (and OSF?) code */ + if (pos > 31) + abort (); +#endif + /* + * It seems that if we do not always set pos to 31 here, the MIT + * code will do the wrong thing. + * + * I hate ASN.1 (and DER), but I hate it even more when everybody + * has to screw it up differently. + */ + pos = HEIM_TAILQ_LAST(t->members, memhead)->val; + if (rfc1510_bitstring) { + if (pos < 31) + pos = 31; + } + + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + while (m->val / 8 < pos / 8) { + if (!rfc1510_bitstring) + fprintf (codefile, + "if (c != 0 || bit_set) {\n"); + fprintf (codefile, + "if (len < 1) return ASN1_OVERFLOW;\n" + "*p-- = c; len--; ret++;\n"); + if (!rfc1510_bitstring) + fprintf (codefile, + "if (!bit_set) {\n" + "rest = 0;\n" + "while(c) { \n" + "if (c & 1) break;\n" + "c = c >> 1;\n" + "rest++;\n" + "}\n" + "bit_set = 1;\n" + "}\n" + "}\n"); + fprintf (codefile, + "c = 0;\n"); + pos -= 8; + } + fprintf (codefile, + "if((%s)->%s) {\n" + "c |= 1<<%d;\n", + name, m->gen_name, (int)(7 - m->val % 8)); + fprintf (codefile, + "}\n"); + } + + if (!rfc1510_bitstring) + fprintf (codefile, + "if (c != 0 || bit_set) {\n"); + fprintf (codefile, + "if (len < 1) return ASN1_OVERFLOW;\n" + "*p-- = c; len--; ret++;\n"); + if (!rfc1510_bitstring) + fprintf (codefile, + "if (!bit_set) {\n" + "rest = 0;\n" + "if(c) { \n" + "while(c) { \n" + "if (c & 1) break;\n" + "c = c >> 1;\n" + "rest++;\n" + "}\n" + "}\n" + "}\n" + "}\n"); + + fprintf (codefile, + "if (len < 1) return ASN1_OVERFLOW;\n" + "*p-- = %s;\n" + "len -= 1;\n" + "ret += 1;\n" + "}\n\n", + rfc1510_bitstring ? "0" : "rest"); + constructed = 0; + break; + } + case TEnumerated : { + encode_primitive ("enumerated", name); + constructed = 0; + break; + } + + case TSet: + case TSequence: { + Member *m; + + if (t->members == NULL) + break; + + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + char *s = NULL; + + if (m->ellipsis) + continue; + + if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + fprintf(codefile, "/* %s */\n", m->name); + if (m->optional) + fprintf (codefile, + "if(%s) ", + s); + else if(m->defval) + gen_compare_defval(s + 1, m->defval); + fprintf (codefile, "{\n"); + fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr); + fprintf (codefile, "ret = 0;\n"); + encode_type (s, m->type, m->gen_name); + fprintf (codefile, "ret += %s_oldret;\n", tmpstr); + fprintf (codefile, "}\n"); + free (s); + } + break; + } + case TSetOf: { + + fprintf(codefile, + "{\n" + "heim_octet_string *val;\n" + "size_t elen = 0, totallen = 0;\n" + "int eret = 0;\n"); + + fprintf(codefile, + "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n" + "return ERANGE;\n", + name); + + fprintf(codefile, + "val = calloc(1, sizeof(val[0]) * (%s)->len);\n" + "if (val == NULL && (%s)->len != 0) return ENOMEM;\n", + name, name); + + fprintf(codefile, + "for(i = 0; i < (int)(%s)->len; i++) {\n", + name); + + fprintf(codefile, + "ASN1_MALLOC_ENCODE(%s, val[i].data, " + "val[i].length, &(%s)->val[i], &elen, eret);\n", + t->subtype->symbol->gen_name, + name); + + fprintf(codefile, + "if(eret) {\n" + "i--;\n" + "while (i >= 0) {\n" + "free(val[i].data);\n" + "i--;\n" + "}\n" + "free(val);\n" + "return eret;\n" + "}\n" + "totallen += elen;\n" + "}\n"); + + fprintf(codefile, + "if (totallen > len) {\n" + "for (i = 0; i < (int)(%s)->len; i++) {\n" + "free(val[i].data);\n" + "}\n" + "free(val);\n" + "return ASN1_OVERFLOW;\n" + "}\n", + name); + + fprintf(codefile, + "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n", + name); + + fprintf (codefile, + "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" + "p -= val[i].length;\n" + "ret += val[i].length;\n" + "memcpy(p + 1, val[i].data, val[i].length);\n" + "free(val[i].data);\n" + "}\n" + "free(val);\n" + "}\n", + name); + break; + } + case TSequenceOf: { + char *sname = NULL; + char *n = NULL; + + fprintf (codefile, + "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n" + "size_t %s_for_oldret = ret;\n" + "ret = 0;\n", + name, tmpstr); + if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL) + errx(1, "malloc"); + if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL) + errx(1, "malloc"); + encode_type (n, t->subtype, sname); + fprintf (codefile, + "ret += %s_for_oldret;\n" + "}\n", + tmpstr); + free (n); + free (sname); + break; + } + case TGeneralizedTime: + encode_primitive ("generalized_time", name); + constructed = 0; + break; + case TGeneralString: + encode_primitive ("general_string", name); + constructed = 0; + break; + case TTeletexString: + encode_primitive ("general_string", name); + constructed = 0; + break; + case TTag: { + char *tname = NULL; + int replace_tag = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + int c; + if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL) + errx(1, "malloc"); + /* + * HACK HACK HACK + * + * This is part of the fix to the bug where we treated IMPLICIT tags of + * named types as EXPLICIT. I.e. + * + * Foo ::= SEQUENCE { ... } + * Bar ::= SEQUENCE { foo [0] IMPLICIT Foo } + * + * would get a context [0] constructed tag *and* a universal sequence + * constructed tag when it should get only the first tag. + * + * Properly fixing this would require changing the signatures of the + * encode, length, and decode functions we generate to take an optional + * tag to replace the one the encoder would generate / decoder would + * expect. That would change the ABI, which... isn't stable, but it's + * a bit soon to make that change. + * + * So, we're looking for IMPLICIT, and if we see any, we generate code + * to replace the tag. + * + * On the decode side we need to know what tag to restore. For this we + * generate enums in the generated header. + * + * NOTE: We *do* "replace" the tags of IMPLICIT-tagged primitive types, + * but our primitive codec functions leave those tags out, which + * is why we don't have to der_replace_tag() them here. + */ + /* + * If the tag is IMPLICIT and it's not primitive and the subtype is not + * any kind of structure... + */ + if (t->tag.tagenv == TE_IMPLICIT && !prim && + t->subtype->type != TSequenceOf && t->subtype->type != TSetOf && + t->subtype->type != TChoice) { + /* If it is a named type for a structured thing */ + if (t->subtype->symbol && + (t->subtype->type == TSequence || + t->subtype->type == TSet)) + replace_tag = 1; + else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any")) + replace_tag = 1; + } else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol) + /* + * Because the subtype is named we are generating its codec + * functions, and those will be adding their UNIVERSAL or whatever + * tags unlike our raw primtive codec library. + */ + replace_tag = is_tagged_type(t->subtype->symbol->type); + + if (replace_tag) + fprintf(codefile, + "{ unsigned char *psave_%s = p, *pfree_%s = NULL;\n" + "size_t l2_%s, lensave_%s = len;\n" + "len = length_%s(%s);\n" + /* Allocate a temp buffer for the encoder */ + "if ((p = pfree_%s = calloc(1, len)) == NULL) return ENOMEM;\n" + /* Make p point to the last byte of the allocated buf */ + "p += len - 1;\n", + tmpstr, tmpstr, tmpstr, tmpstr, + t->subtype->symbol->gen_name, name, tmpstr); + + /* XXX Currently we generate code that leaks `pfree_%s` here. */ + c = encode_type (name, t->subtype, tname); + /* Explicit non-UNIVERSAL tags are always constructed */ + if (!c && t->tag.tagclass != ASN1_C_UNIV && t->tag.tagenv == TE_EXPLICIT) + c = 1; + if (replace_tag) + fprintf(codefile, + "if (len) { free(pfree_%s); return EINVAL; }\n" + /* + * Here we have `p' pointing to one byte before the buffer + * we allocated above. + * + * [ T_wrong | LL | VVVV ] // temp buffer + * ^ ^ + * | | + * | \ + * \ +-- p + 1 + * +-- p + * + * psave_<fieldName> still points to the last byte in the + * original buffer passed in where we should write the + * encoding of <fieldName>. + * + * We adjust psave_<fieldName> to point to before the TLV + * encoding of <fieldName> (with wrong tag) in the original + * buffer (this may NOT be a valid pointer, but we won't + * dereference it): + * + * [ ... | T_wrong | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_<fieldName> + */ + "psave_%s -= l;\n" + /* + * We further adjust psave_<fieldName> to point to the last + * byte of what should be the T(ag) of the TLV encoding of + * <fieldName> (this is now a valid pointer), then... + * + * |<--->| (not written yet) + * | | |<-------->| (not written yet) + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_<fieldName> + */ + "psave_%s += asn1_tag_length_%s;\n" + /* + * ...copy the L(ength)V(alue) of the TLV encoding of + * <fieldName>. + * + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_<fieldName> + 1 + * + * |<----->| length is + * | | `l' - asn1_tag_length_<fieldName> + * [ T_wrong | LL | VVVV ] // temp buffer + * ^ ^ + * | | + * | \ + * \ +-- p + 1 + asn1_tag_length_%s + * +-- p + 1 + */ + "memcpy(psave_%s + 1, p + 1 + asn1_tag_length_%s, l - asn1_tag_length_%s);\n" + /* + * Encode the IMPLICIT tag. Recall that encoders like + * der_put_tag() take a pointer to the last byte they + * should write to, and a length of bytes to the left of + * that that they are allowed to write into. + * + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- psave_<fieldName> + */ + "e = der_put_tag(psave_%s, %zu, %s, %s, %d, &l2_%s);\n" + "if (e) { free(pfree_%s); return e; }\n" + /* Restore `len' and adjust it (see `p' below) */ + "len = lensave_%s - (l + %zu - asn1_tag_length_%s);\n" + /* + * Adjust `ret' to account for the difference in size + * between the length of the right and wrong tags. + */ + "ret += %zu - asn1_tag_length_%s;\n" + /* Free the buffer and restore `p' */ + "free(pfree_%s);\n" + /* + * Make `p' point into the original buffer again, to one + * byte before the bytes we wrote: + * + * [ ... | T_right | LL | VVVVV | ... ] // original buffer + * ^ + * | + * \ + * +-- p + */ + "p = psave_%s - (1 + %zu - asn1_tag_length_%s); }\n", + tmpstr, tmpstr, tmpstr, t->subtype->symbol->name, + tmpstr, t->subtype->symbol->name, t->subtype->symbol->name, + tmpstr, length_tag(t->tag.tagvalue), + classname(t->tag.tagclass), + c ? "CONS" : "PRIM", + t->tag.tagvalue, + tmpstr, + + tmpstr, tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name, + length_tag(t->tag.tagvalue), t->subtype->symbol->name, + tmpstr, tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name); + else + fprintf(codefile, + "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n" + "if (e) return e;\np -= l; len -= l; ret += l;\n\n", + classname(t->tag.tagclass), + c ? "CONS" : "PRIM", + valuename(t->tag.tagclass, t->tag.tagvalue)); + free(tname); + constructed = c; + break; + } + case TChoice:{ + Member *m, *have_ellipsis = NULL; + char *s = NULL; + + if (t->members == NULL) + break; + + fprintf(codefile, "\n"); + + if (asprintf (&s, "(%s)", name) < 0 || s == NULL) + errx(1, "malloc"); + fprintf(codefile, "switch(%s->element) {\n", s); + + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + char *s2 = NULL; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + fprintf (codefile, "case %s: {", m->label); + if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&", + s, m->gen_name) < 0 || s2 == NULL) + errx(1, "malloc"); + if (m->optional) + fprintf (codefile, "if(%s) {\n", s2); + fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr); + fprintf (codefile, "ret = 0;\n"); + constructed = encode_type (s2, m->type, m->gen_name); + fprintf (codefile, "ret += %s_oldret;\n", tmpstr); + if(m->optional) + fprintf (codefile, "}\n"); + fprintf(codefile, "break;\n"); + fprintf(codefile, "}\n"); + free (s2); + } + free (s); + if (have_ellipsis) { + fprintf(codefile, + "case %s: {\n" + "if (len < (%s)->u.%s.length)\n" + "return ASN1_OVERFLOW;\n" + "p -= (%s)->u.%s.length;\n" + "ret += (%s)->u.%s.length;\n" + "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n" + "break;\n" + "}\n", + have_ellipsis->label, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name, + name, have_ellipsis->gen_name); + } + fprintf(codefile, "};\n"); + break; + } + case TOID: + encode_primitive ("oid", name); + constructed = 0; + break; + case TUTCTime: + encode_primitive ("utctime", name); + constructed = 0; + break; + case TUTF8String: + encode_primitive ("utf8string", name); + constructed = 0; + break; + case TPrintableString: + encode_primitive ("printable_string", name); + constructed = 0; + break; + case TIA5String: + encode_primitive ("ia5_string", name); + constructed = 0; + break; + case TBMPString: + encode_primitive ("bmp_string", name); + constructed = 0; + break; + case TUniversalString: + encode_primitive ("universal_string", name); + constructed = 0; + break; + case TVisibleString: + encode_primitive ("visible_string", name); + constructed = 0; + break; + case TNull: + fprintf (codefile, "/* NULL */\n"); + constructed = 0; + break; + default: + abort (); + } + return constructed; +} + +void +generate_type_encode (const Symbol *s) +{ + fprintf (codefile, "int ASN1CALL\n" + "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE," + " const %s *data, size_t *size)\n" + "{\n", + s->gen_name, s->gen_name); + + switch (s->type->type) { + case TInteger: + case TBoolean: + case TOctetString: + case TGeneralizedTime: + case TGeneralString: + case TTeletexString: + case TUTCTime: + case TUTF8String: + case TPrintableString: + case TIA5String: + case TBMPString: + case TUniversalString: + case TVisibleString: + case TNull: + case TBitString: + case TEnumerated: + case TOID: + case TSequence: + case TSequenceOf: + case TSet: + case TSetOf: + case TTag: + case TType: + case TChoice: + fprintf (codefile, + "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n" + "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" + "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n"); + + encode_type("data", s->type, "Top"); + + fprintf (codefile, "*size = ret;\n" + "return 0;\n"); + break; + default: + abort (); + } + fprintf (codefile, "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_free.c b/third_party/heimdal/lib/asn1/gen_free.c new file mode 100644 index 0000000..ff80063 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_free.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static void +free_primitive (const char *typename, const char *name) +{ + fprintf (codefile, "der_free_%s(%s);\n", typename, name); +} + +static void +free_type (const char *name, const Type *t, int preserve) +{ + switch (t->type) { + case TType: +#if 0 + free_type (name, t->symbol->type, preserve); +#endif + fprintf (codefile, "free_%s(%s);\n", t->symbol->gen_name, name); + break; + case TInteger: + if (t->range == NULL && t->members == NULL) { + free_primitive ("heim_integer", name); + break; + } + HEIM_FALLTHROUGH; + case TBoolean: + case TEnumerated : + case TNull: + case TGeneralizedTime: + case TUTCTime: + /* + * This doesn't do much, but it leaves zeros where garbage might + * otherwise have been found. Gets us closer to having the equivalent + * of a memset()-to-zero data structure after calling the free + * functions. + */ + fprintf(codefile, "*%s = 0;\n", name); + break; + case TBitString: + if (HEIM_TAILQ_EMPTY(t->members)) + free_primitive("bit_string", name); + break; + case TOctetString: + free_primitive ("octet_string", name); + break; + case TChoice: + case TSet: + case TSequence: { + Member *m, *have_ellipsis = NULL; + + if (t->members == NULL) + break; + + if ((t->type == TSequence || t->type == TChoice) && preserve) + fprintf(codefile, "der_free_octet_string(&data->_save);\n"); + + if(t->type == TChoice) + fprintf(codefile, "switch((%s)->element) {\n", name); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s; + + if (m->ellipsis){ + have_ellipsis = m; + continue; + } + + if(t->type == TChoice) + fprintf(codefile, "case %s:\n", m->label); + if (asprintf (&s, "%s(%s)->%s%s", + m->optional ? "" : "&", name, + t->type == TChoice ? "u." : "", m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + if(m->optional) + fprintf(codefile, "if(%s) {\n", s); + free_type (s, m->type, FALSE); + if(m->optional) + fprintf(codefile, + "free(%s);\n" + "%s = NULL;\n" + "}\n",s, s); + free (s); + if(t->type == TChoice) + fprintf(codefile, "break;\n"); + } + + if(t->type == TChoice) { + if (have_ellipsis) + fprintf(codefile, + "case %s:\n" + "der_free_octet_string(&(%s)->u.%s);\n" + "break;", + have_ellipsis->label, + name, have_ellipsis->gen_name); + fprintf(codefile, "}\n"); + } + break; + } + case TSetOf: + case TSequenceOf: { + char *n; + + fprintf (codefile, "if ((%s)->val)\nwhile((%s)->len){\n", name, name); + if (asprintf (&n, "&(%s)->val[(%s)->len-1]", name, name) < 0 || n == NULL) + errx(1, "malloc"); + free_type(n, t->subtype, FALSE); + fprintf(codefile, + "(%s)->len--;\n" + "} else (%s)->len = 0;\n", + name, name); + fprintf(codefile, + "free((%s)->val);\n" + "(%s)->val = NULL;\n", name, name); + free(n); + break; + } + case TGeneralString: + free_primitive ("general_string", name); + break; + case TTeletexString: + free_primitive ("general_string", name); + break; + case TUTF8String: + free_primitive ("utf8string", name); + break; + case TPrintableString: + free_primitive ("printable_string", name); + break; + case TIA5String: + free_primitive ("ia5_string", name); + break; + case TBMPString: + free_primitive ("bmp_string", name); + break; + case TUniversalString: + free_primitive ("universal_string", name); + break; + case TVisibleString: + free_primitive ("visible_string", name); + break; + case TTag: + free_type (name, t->subtype, preserve); + break; + case TOID : + free_primitive ("oid", name); + break; + default : + abort (); + } +} + +void +generate_type_free (const Symbol *s) +{ + struct decoration deco; + ssize_t more_deco = -1; + int preserve = preserve_type(s->name) ? TRUE : FALSE; + + fprintf (codefile, "void ASN1CALL\n" + "free_%s(%s *data)\n" + "{\n", + s->gen_name, s->gen_name); + + free_type ("data", s->type, preserve); + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (deco.ext && deco.free_function_name == NULL) { + /* Decorated with field of external type but no free function */ + if (deco.ptr) + fprintf(codefile, "(data)->%s = 0;\n", deco.field_name); + else + fprintf(codefile, + "memset(&(data)->%s, 0, sizeof((data)->%s));\n", + deco.field_name, deco.field_name); + } else if (deco.ext) { + /* Decorated with field of external type w/ free function */ + if (deco.ptr) { + fprintf(codefile, "if ((data)->%s) {\n", deco.field_name); + fprintf(codefile, "%s((data)->%s);\n", + deco.free_function_name, deco.field_name); + fprintf(codefile, "(data)->%s = 0;\n", deco.field_name); + fprintf(codefile, "}\n"); + } else { + fprintf(codefile, "%s(&(data)->%s);\n", + deco.free_function_name, deco.field_name); + fprintf(codefile, + "memset(&(data)->%s, 0, sizeof((data)->%s));\n", + deco.field_name, deco.field_name); + } + } else if (deco.opt) { + /* Decorated with optional field of ASN.1 type */ + fprintf(codefile, "if ((data)->%s) {\n", deco.field_name); + fprintf(codefile, "free_%s((data)->%s);\n", + deco.field_type, deco.field_name); + fprintf(codefile, "free((data)->%s);\n", deco.field_name); + fprintf(codefile, "(data)->%s = NULL;\n", deco.field_name); + fprintf(codefile, "}\n"); + } else { + /* Decorated with required field of ASN.1 type */ + fprintf(codefile, "free_%s(&(data)->%s);\n", + deco.field_type, deco.field_name); + } + free(deco.field_type); + } + fprintf (codefile, "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_glue.c b/third_party/heimdal/lib/asn1/gen_glue.c new file mode 100644 index 0000000..424e5de --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_glue.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 1997, 1999, 2000, 2003 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static FILE * +get_code_file(void) +{ + if (!one_code_file && template_flag && templatefile) + return templatefile; + return codefile; +} + +static void +generate_2int (const Type *t, const char *gen_name) +{ + Member *m; + + fprintf (headerfile, + "uint64_t %s2int(%s);\n", + gen_name, gen_name); + + fprintf (get_code_file(), + "uint64_t %s2int(%s f)\n" + "{\n" + "uint64_t r = 0;\n", + gen_name, gen_name); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + fprintf (get_code_file(), "if(f.%s) r |= (1ULL << %d);\n", + m->gen_name, (int)m->val); + } + fprintf (get_code_file(), "return r;\n" + "}\n\n"); +} + +static void +generate_int2 (const Type *t, const char *gen_name) +{ + Member *m; + + fprintf (headerfile, + "%s int2%s(uint64_t);\n", + gen_name, gen_name); + + fprintf (get_code_file(), + "%s int2%s(uint64_t n)\n" + "{\n" + "\t%s flags;\n\n" + "\tmemset(&flags, 0, sizeof(flags));\n\n", + gen_name, gen_name, gen_name); + + if(t->members) { + HEIM_TAILQ_FOREACH(m, t->members, members) { + fprintf (get_code_file(), "\tflags.%s = (n >> %d) & 1;\n", + m->gen_name, (int)m->val); + } + } + fprintf (get_code_file(), "\treturn flags;\n" + "}\n\n"); +} + +/* + * This depends on the bit string being declared in increasing order + */ + +static void +generate_units (const Type *t, const char *gen_name) +{ + Member *m; + + fprintf (headerfile, + "const struct units * asn1_%s_units(void);\n", + gen_name); + + fprintf (get_code_file(), + "static struct units %s_units[] = {\n", + gen_name); + + if(t->members) { + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + fprintf (get_code_file(), + "\t{\"%s\",\t1ULL << %d},\n", m->name, (int)m->val); + } + } + + fprintf (get_code_file(), + "\t{NULL,\t0}\n" + "};\n\n"); + + fprintf (get_code_file(), + "const struct units * asn1_%s_units(void){\n" + "return %s_units;\n" + "}\n\n", + gen_name, gen_name); + + +} + +void +generate_glue (const Type *t, const char *gen_name) +{ + switch(t->type) { + case TTag: + generate_glue(t->subtype, gen_name); + break; + case TBitString : { + Member *m; + + if (HEIM_TAILQ_EMPTY(t->members)) + break; + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > 63) { + warnx("Not generating 2int, int2, or units for %s due to " + "having a member valued more than 63", gen_name); + return; + } + } + generate_2int (t, gen_name); + generate_int2 (t, gen_name); + if (parse_units_flag) + generate_units (t, gen_name); + break; + } + default : + break; + } +} diff --git a/third_party/heimdal/lib/asn1/gen_length.c b/third_party/heimdal/lib/asn1/gen_length.c new file mode 100644 index 0000000..ab5c5f3 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_length.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static void +length_primitive (const char *typename, + const char *name, + const char *variable) +{ + fprintf (codefile, "%s += der_length_%s(%s);\n", variable, typename, name); +} + +/* XXX same as der_length_tag */ +static size_t +length_tag(unsigned int tag) +{ + size_t len = 0; + + if(tag <= 30) + return 1; + while(tag) { + tag /= 128; + len++; + } + return len + 1; +} + + +static int +length_type (const char *name, const Type *t, + const char *variable, const char *tmpstr) +{ + switch (t->type) { + case TType: +#if 0 + length_type (name, t->symbol->type); +#endif + fprintf (codefile, "%s += length_%s(%s);\n", + variable, t->symbol->gen_name, name); + break; + case TInteger: + if(t->members) { + fprintf(codefile, + "{\n" + "int enumint = *%s;\n", name); + length_primitive ("integer", "&enumint", variable); + fprintf(codefile, "}\n"); + } else if (t->range == NULL) { + length_primitive ("heim_integer", name, variable); + } else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) { + length_primitive ("integer64", name, variable); + } else if (t->range->min < 0) { + length_primitive ("integer", name, variable); + } else if (t->range->max > UINT_MAX) { + length_primitive ("unsigned64", name, variable); + } else { + length_primitive ("unsigned", name, variable); + } + break; + case TBoolean: + fprintf (codefile, "%s += 1;\n", variable); + break; + case TEnumerated : + length_primitive ("enumerated", name, variable); + break; + case TOctetString: + length_primitive ("octet_string", name, variable); + break; + case TBitString: { + if (HEIM_TAILQ_EMPTY(t->members)) + length_primitive("bit_string", name, variable); + else { + if (!rfc1510_bitstring) { + Member *m; + int pos = HEIM_TAILQ_LAST(t->members, memhead)->val; + + fprintf(codefile, + "do {\n"); + HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) { + while (m->val / 8 < pos / 8) { + pos -= 8; + } + fprintf (codefile, + "if((%s)->%s) { %s += %d; break; }\n", + name, m->gen_name, variable, (pos + 8) / 8); + } + fprintf(codefile, + "} while(0);\n"); + fprintf (codefile, "%s += 1;\n", variable); + } else { + fprintf (codefile, "%s += 5;\n", variable); + } + } + break; + } + case TSet: + case TSequence: + case TChoice: { + Member *m, *have_ellipsis = NULL; + + if (t->members == NULL) + break; + + if(t->type == TChoice) + fprintf (codefile, "switch((%s)->element) {\n", name); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *s; + + if (m->ellipsis) { + have_ellipsis = m; + continue; + } + + if(t->type == TChoice) + fprintf(codefile, "case %s:\n", m->label); + + if (asprintf (&s, "%s(%s)->%s%s", + m->optional ? "" : "&", name, + t->type == TChoice ? "u." : "", m->gen_name) < 0 || s == NULL) + errx(1, "malloc"); + if (m->optional) + fprintf (codefile, "if(%s)", s); + else if(m->defval) + gen_compare_defval(s + 1, m->defval); + fprintf (codefile, "{\n" + "size_t %s_oldret = %s;\n" + "%s = 0;\n", tmpstr, variable, variable); + length_type (s, m->type, "ret", m->gen_name); + fprintf (codefile, "ret += %s_oldret;\n", tmpstr); + fprintf (codefile, "}\n"); + free (s); + if(t->type == TChoice) + fprintf(codefile, "break;\n"); + } + if(t->type == TChoice) { + if (have_ellipsis) + fprintf(codefile, + "case %s:\n" + "ret += (%s)->u.%s.length;\n" + "break;\n", + have_ellipsis->label, + name, + have_ellipsis->gen_name); + fprintf (codefile, "}\n"); /* switch */ + } + break; + } + case TSetOf: + case TSequenceOf: { + char *n = NULL; + char *sname = NULL; + + fprintf (codefile, + "{\n" + "size_t %s_oldret = %s;\n" + "unsigned int n_%s;\n" + "%s = 0;\n", + tmpstr, variable, tmpstr, variable); + + fprintf (codefile, "for(n_%s = (%s)->len; n_%s > 0; --n_%s){\n", + tmpstr, name, tmpstr, tmpstr); + fprintf (codefile, "size_t %s_for_oldret = %s;\n" + "%s = 0;\n", tmpstr, variable, variable); + if (asprintf (&n, "&(%s)->val[n_%s - 1]", name, tmpstr) < 0 || n == NULL) + errx(1, "malloc"); + if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL) + errx(1, "malloc"); + length_type(n, t->subtype, variable, sname); + fprintf (codefile, "%s += %s_for_oldret;\n", + variable, tmpstr); + fprintf (codefile, "}\n"); + + fprintf (codefile, + "%s += %s_oldret;\n" + "}\n", variable, tmpstr); + free(n); + free(sname); + break; + } + case TGeneralizedTime: + length_primitive ("generalized_time", name, variable); + break; + case TGeneralString: + length_primitive ("general_string", name, variable); + break; + case TTeletexString: + length_primitive ("general_string", name, variable); + break; + case TUTCTime: + length_primitive ("utctime", name, variable); + break; + case TUTF8String: + length_primitive ("utf8string", name, variable); + break; + case TPrintableString: + length_primitive ("printable_string", name, variable); + break; + case TIA5String: + length_primitive ("ia5_string", name, variable); + break; + case TBMPString: + length_primitive ("bmp_string", name, variable); + break; + case TUniversalString: + length_primitive ("universal_string", name, variable); + break; + case TVisibleString: + length_primitive ("visible_string", name, variable); + break; + case TNull: + fprintf (codefile, "/* NULL */\n"); + break; + case TTag:{ + char *tname = NULL; + int replace_tag = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + + if (asprintf(&tname, "%s_tag", tmpstr) < 0 || tname == NULL) + errx(1, "malloc"); + length_type (name, t->subtype, variable, tname); + /* See the comments in encode_type() about IMPLICIT tags */ + if (t->tag.tagenv == TE_IMPLICIT && !prim && + t->subtype->type != TSequenceOf && t->subtype->type != TSetOf && + t->subtype->type != TChoice) { + if (t->subtype->symbol && + (t->subtype->type == TSequence || + t->subtype->type == TSet)) + replace_tag = 1; + else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any")) + replace_tag = 1; + } else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol) + replace_tag = is_tagged_type(t->subtype->symbol->type); + if (replace_tag) + /* + * We're replacing the tag of the underlying type. If that type is + * imported, then we don't know its tag, so we rely on the + * asn1_tag_tag_<TypeName> enum value we generated for it, and we + * use the asn1_tag_length_<TypeName> enum value to avoid having to + * call der_length_tag() at run-time. + */ + fprintf(codefile, "ret += %lu - asn1_tag_length_%s;\n", + (unsigned long)length_tag(t->tag.tagvalue), + t->subtype->symbol->gen_name); + else + fprintf(codefile, "ret += %lu + der_length_len (ret);\n", + (unsigned long)length_tag(t->tag.tagvalue)); + free(tname); + break; + } + case TOID: + length_primitive ("oid", name, variable); + break; + default : + abort (); + } + return 0; +} + +void +generate_type_length (const Symbol *s) +{ + fprintf (codefile, + "size_t ASN1CALL\n" + "length_%s(const %s *data)\n" + "{\n" + "size_t ret = 0;\n", + s->gen_name, s->gen_name); + + length_type ("data", s->type, "ret", "Top"); + fprintf (codefile, "return ret;\n}\n\n"); +} + diff --git a/third_party/heimdal/lib/asn1/gen_locl.h b/third_party/heimdal/lib/asn1/gen_locl.h new file mode 100644 index 0000000..f37f149 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_locl.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __GEN_LOCL_H__ +#define __GEN_LOCL_H__ + +#include <config.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <ctype.h> +#include <time.h> +#include <errno.h> +#include <err.h> +#include <roken.h> +#include <getarg.h> +#include "hash.h" +#include "symbol.h" +#include "asn1-common.h" +#include "der.h" +#include "der-private.h" + +/* + * XXX We need to move all module state out of globals and into a struct that + * we pass around when parsing and compiling a module, and also that we keep on + * a linked list of parsed modules. + * + * This is needed to: + * + * - implement IMPORTS correctly, because we need to know the type of a symbol + * in order to emit an extern declaration of it + * - implement value parsing + * - implement an ASN.1 library that does value parsing + * + * Value parsing, in particular, would be fantastic. We could then have + * options in hxtool(1) to load arbitrary ASN.1 modules and then parse SAN + * values given in ASN.1 value syntax on the command-line or in files. Eat + * your heart out OpenSSL if we do this! + * + * As well we'll need a `-I' option to the compiler so it knows where to find + * modules to IMPORT FROM. + */ +typedef struct asn1_module { + /* Name of ASN.1 module file: */ + const char *orig_filename; + /* Name of file to always include for common type definitions: */ + const char *type_file_string; + /* Name of public header file for module: */ + const char *header; + /* Name of private header file for module: */ + const char *privheader; + /* Basename of module: */ + const char *headerbase; + /* Open stdio file handles for output: */ + FILE *jsonfile; + FILE *privheaderfile; + FILE *headerfile; + FILE *oidsfile; + FILE *codefile; + FILE *logfile; + FILE *templatefile; + /* Module contents: */ + struct sexport *exports; + struct import *imports; + Hashtab *htab; /* symbols */ + /* Template state: */ + struct templatehead *template; + struct tlisthead *tlistmaster; + /* CLI options and flags needed everywhere: */ + getarg_strings preserve; + getarg_strings seq; + const char *enum_prefix; + unsigned int one_code_file:1; + unsigned int support_ber:1; + unsigned int parse_units_flag:1; + unsigned int prefix_enum:1; /* Should be a getarg_strings of bitrsting types to do this for */ + unsigned int rfc1510_bitstring:1; /* Should be a getarg_strings of bitrsting types to do this for */ +} *asn1_module; + +void generate_type (const Symbol *); +void generate_type_header_forwards(const Symbol *); +void generate_constant (const Symbol *); +void generate_type_encode (const Symbol *); +void generate_type_decode (const Symbol *); +void generate_type_free (const Symbol *); +void generate_type_length (const Symbol *); +void generate_type_print_stub(const Symbol *); +void generate_type_copy (const Symbol *); +void generate_type_seq (const Symbol *); +void generate_glue (const Type *, const char*); + +const char *classname(Der_class); +const char *valuename(Der_class, int); + +void gen_compare_defval(const char *, struct value *); +void gen_assign_defval(const char *, struct value *); + +int objid_cmp(struct objid *, struct objid *); + +void init_generate (const char *, const char *); +const char *get_filename (void); +void close_generate(void); +void add_import(const char *); +void add_export(const char *); +int is_export(const char *); +int yyparse(void); +int is_primitive_type(const Type *); +int is_tagged_type(const Type *); + +int preserve_type(const char *); +int seq_type(const char *); + +struct decoration { + char *field_type; /* C type name */ + char *field_name; /* C struct field name */ + char *copy_function_name; /* copy constructor function name */ + char *free_function_name; /* destructor function name */ + char *header_name; /* header name */ + unsigned int decorated:1; + unsigned int first:1; /* optional */ + unsigned int opt:1; /* optional */ + unsigned int ext:1; /* external */ + unsigned int ptr:1; /* external, pointer */ + unsigned int void_star:1; /* external, void * */ + unsigned int struct_star:1; /* external, struct foo * */ +}; +int decorate_type(const char *, struct decoration *, ssize_t *); + +void generate_header_of_codefile(const char *); +void close_codefile(void); + +void get_open_type_defn_fields(const Type *, Member **, Member **, Field **, + Field **, int *); +void sort_object_set(IOSObjectSet *, Field *, IOSObject ***, size_t *); +int object_cmp(const void *, const void *); + +int is_template_compat (const Symbol *); +void generate_template(const Symbol *); +void generate_template_type_forward(const char *); +void generate_template_objectset_forwards(const Symbol *); +void gen_template_import(const Symbol *); + +struct objid **objid2list(struct objid *); + +extern FILE *jsonfile, *privheaderfile, *headerfile, *codefile, *logfile, *templatefile; +extern const char *fuzzer_string; +extern int support_ber; +extern int template_flag; +extern int rfc1510_bitstring; +extern int one_code_file; +extern int original_order; +extern int parse_units_flag; +extern char *type_file_string; + +extern int error_flag; + +#endif /* __GEN_LOCL_H__ */ diff --git a/third_party/heimdal/lib/asn1/gen_print.c b/third_party/heimdal/lib/asn1/gen_print.c new file mode 100644 index 0000000..4cca9e0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_print.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +void +generate_type_print_stub(const Symbol *s) +{ + fprintf(codefile, "char * ASN1CALL\n" + "print_%s(const %s *data, int flags)\n" + "{ errno = EINVAL; return 0; }\n\n", + s->gen_name, s->gen_name); +} diff --git a/third_party/heimdal/lib/asn1/gen_seq.c b/third_party/heimdal/lib/asn1/gen_seq.c new file mode 100644 index 0000000..9762813 --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_seq.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static FILE * +get_code_file(void) +{ + if (!one_code_file && template_flag && templatefile) + return templatefile; + return codefile; +} + +void +generate_type_seq (const Symbol *s) +{ + char *subname; + Type *type; + + if (!seq_type(s->name)) + return; + type = s->type; + while(type->type == TTag) + type = type->subtype; + + if (type->type != TSequenceOf && type->type != TSetOf) { + fprintf(stderr, "%s not seq of %d\n", s->name, (int)type->type); + return; + } + + /* + * Require the subtype to be a type so we can name it and use + * copy_/free_ + */ + + if (type->subtype->type != TType) { + fprintf(stderr, "%s subtype is not a type, can't generate " + "sequence code for this case: %d\n", + s->name, (int)type->subtype->type); + exit(1); + } + + subname = type->subtype->symbol->gen_name; + + fprintf (headerfile, + "ASN1EXP int ASN1CALL add_%s (%s *, const %s *);\n" + "ASN1EXP int ASN1CALL remove_%s (%s *, unsigned int);\n", + s->gen_name, s->gen_name, subname, + s->gen_name, s->gen_name); + + fprintf (get_code_file(), "int ASN1CALL\n" + "add_%s(%s *data, const %s *element)\n" + "{\n", + s->gen_name, s->gen_name, subname); + + fprintf (get_code_file(), + "int ret;\n" + "void *ptr;\n" + "\n" + "ptr = realloc(data->val, \n" + "\t(data->len + 1) * sizeof(data->val[0]));\n" + "if (ptr == NULL) return ENOMEM;\n" + "data->val = ptr;\n\n" + "ret = copy_%s(element, &data->val[data->len]);\n" + "if (ret) return ret;\n" + "data->len++;\n" + "return 0;\n", + subname); + + fprintf (get_code_file(), "}\n\n"); + + fprintf (get_code_file(), "int ASN1CALL\n" + "remove_%s(%s *data, unsigned int element)\n" + "{\n", + s->gen_name, s->gen_name); + + fprintf (get_code_file(), + "void *ptr;\n" + "\n" + "if (data->len == 0 || element >= data->len)\n" + "\treturn ASN1_OVERRUN;\n" + "free_%s(&data->val[element]);\n" + "data->len--;\n" + /* don't move if its the last element */ + "if (element < data->len)\n" + "\tmemmove(&data->val[element], &data->val[element + 1], \n" + "\t\tsizeof(data->val[0]) * (data->len - element));\n" + /* resize but don't care about failures since it doesn't matter */ + "ptr = realloc(data->val, data->len * sizeof(data->val[0]));\n" + "if (ptr != NULL || data->len == 0) data->val = ptr;\n" + "return 0;\n", + subname); + + fprintf (get_code_file(), "}\n\n"); +} diff --git a/third_party/heimdal/lib/asn1/gen_template.c b/third_party/heimdal/lib/asn1/gen_template.c new file mode 100644 index 0000000..67d18ec --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_template.c @@ -0,0 +1,1675 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Currently we generate C source code defining constant arrays of structures + * containing a sort of a "byte-coded" template of an ASN.1 compiler to be + * interpreted at run-time. + */ + +#include "gen_locl.h" +#include <vis.h> +#include <vis-extras.h> + +static const char *symbol_name(const char *, const Type *); +static void generate_template_type(const char *, const char **, const char *, const char *, const char *, + Type *, int, int, int); + +static const char * +ttype_symbol(const char *basename, const Type *t) +{ + return t->symbol->gen_name; +} + +static const char * +integer_symbol(const char *basename, const Type *t) +{ + if (t->members) + /* + * XXX enum foo -- compute the size either from inspecting the members + * and applying the ABI's rules for enum size, OR infer the field + * size from a template by using the offsetof field. The latter is + * hard to do though. + */ + return "int"; + else if (t->range == NULL) + return "heim_integer"; + else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + return "int64_t"; + else if (t->range->min < 0) + return "int"; + else if (t->range->max > UINT_MAX) + return "uint64_t"; + else + return "unsigned"; +} + +static const char * +boolean_symbol(const char *basename, const Type *t) +{ + return "int"; +} + + +static const char * +octetstring_symbol(const char *basename, const Type *t) +{ + return "heim_octet_string"; +} + +static const char * +sequence_symbol(const char *basename, const Type *t) +{ + return basename; +} + +static const char * +time_symbol(const char *basename, const Type *t) +{ + return "time_t"; +} + +static const char * +tag_symbol(const char *basename, const Type *t) +{ + return symbol_name(basename, t->subtype); +} + +static const char * +generalstring_symbol(const char *basename, const Type *t) +{ + return "heim_general_string"; +} + +static const char * +printablestring_symbol(const char *basename, const Type *t) +{ + return "heim_printable_string"; +} + +static const char * +ia5string_symbol(const char *basename, const Type *t) +{ + return "heim_ia5_string"; +} + +static const char * +teletexstring_symbol(const char *basename, const Type *t) +{ + return "heim_general_string"; +} + +static const char * +visiblestring_symbol(const char *basename, const Type *t) +{ + return "heim_visible_string"; +} + +static const char * +utf8string_symbol(const char *basename, const Type *t) +{ + return "heim_utf8_string"; +} + +static const char * +bmpstring_symbol(const char *basename, const Type *t) +{ + return "heim_bmp_string"; +} + +static const char * +universalstring_symbol(const char *basename, const Type *t) +{ + return "heim_universal_string"; +} + +static const char * +oid_symbol(const char *basename, const Type *t) +{ + return "heim_oid"; +} + +static const char * +bitstring_symbol(const char *basename, const Type *t) +{ + if (t->members) + return basename; + return "heim_bit_string"; +} + + + +/* Keep this sorted by `type' so we can just index this by type */ +const struct { + enum typetype type; + const char *(*symbol_name)(const char *, const Type *); + int is_struct; +} types[] = { + { TBitString, bitstring_symbol, 0 }, + { TBoolean, boolean_symbol, 0 }, + { TChoice, sequence_symbol, 1 }, + { TEnumerated, integer_symbol, 0 }, + { TGeneralString, generalstring_symbol, 0 }, + { TTeletexString, teletexstring_symbol, 0 }, + { TGeneralizedTime, time_symbol, 0 }, + { TIA5String, ia5string_symbol, 0 }, + { TInteger, integer_symbol, 0 }, + { TNull, integer_symbol, 1 }, + { TOID, oid_symbol, 0 }, + { TOctetString, octetstring_symbol, 0 }, + { TPrintableString, printablestring_symbol, 0 }, + { TSequence, sequence_symbol, 1 }, + { TSequenceOf, tag_symbol, 1 }, + { TSet, sequence_symbol, 1 }, + { TSetOf, tag_symbol, 1 }, + { TTag, tag_symbol, 1 }, + { TType, ttype_symbol, 1 }, + { TUTCTime, time_symbol, 0 }, + { TUTF8String, utf8string_symbol, 0 }, + { TBMPString, bmpstring_symbol, 0 }, + { TUniversalString, universalstring_symbol, 0 }, + { TVisibleString, visiblestring_symbol, 0 }, +}; + +static FILE * +get_code_file(void) +{ + if (!one_code_file) + return templatefile; + return codefile; +} + + +static int +is_supported_type_p(const Type *t) +{ + return t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type; +} + +int +is_template_compat (const Symbol *s) +{ + return is_supported_type_p(s->type); +} + +static const char * +symbol_name(const char *basename, const Type *t) +{ + if (t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type) + return (types[t->type].symbol_name)(basename, t); + if (t->type >= 0 && t->type <= TVisibleString) + errx(1, "types[] is not sorted"); + errx(1, "unknown der type: %d\n", t->type); + return NULL; +} + + +static char * +partial_offset(const char *basetype, const char *name, int need_offset, int isstruct) +{ + char *str; + if (name == NULL || need_offset == 0) + return strdup("0"); + if (asprintf(&str, "offsetof(%s%s, %s)", isstruct ? "struct " : "", basetype, name) < 0 || str == NULL) + errx(1, "malloc"); + return str; +} + +struct template { + char *line; + char *tt; + char *offset; + char *ptr; + HEIM_TAILQ_ENTRY(template) members; +}; + +HEIM_TAILQ_HEAD(templatehead, template); + +struct tlist { + char *name; + char *header; + struct templatehead template; + HEIM_TAILQ_ENTRY(tlist) tmembers; +}; + +HEIM_TAILQ_HEAD(tlisthead, tlist); + +static void tlist_header(struct tlist *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static struct template * + add_line(struct templatehead *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static int tlist_cmp(const struct tlist *, const struct tlist *); + +static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +static void add_line_string(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +static void add_line_pointer_reference(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + + +static struct tlisthead tlistmaster = HEIM_TAILQ_HEAD_INITIALIZER(tlistmaster); +static unsigned long numdups = 0; + +static struct tlist * +tlist_new(const char *name) +{ + struct tlist *tl = calloc(1, sizeof(*tl)); + tl->name = strdup(name); + HEIM_TAILQ_INIT(&tl->template); + return tl; +} + +static void +tlist_header(struct tlist *t, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL) + errx(1, "malloc"); + va_end(ap); +} + +static unsigned long +tlist_count(struct tlist *tl) +{ + unsigned int count = 0; + struct template *q; + + HEIM_TAILQ_FOREACH(q, &tl->template, members) { + count++; + } + return count; +} + +static void +tlist_add(struct tlist *tl) +{ + HEIM_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers); +} + +static void +tlist_print(struct tlist *tl) +{ + struct template *q; + unsigned int i = 1; + FILE *f = get_code_file(); + + fprintf(f, "const struct asn1_template asn1_%s[] = {\n", tl->name); + fprintf(f, "/* 0 */ %s,\n", tl->header); + HEIM_TAILQ_FOREACH(q, &tl->template, members) { + int last = (HEIM_TAILQ_LAST(&tl->template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); +} + +static struct tlist * +tlist_find_by_name(const char *name) +{ + struct tlist *ql; + HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (strcmp(ql->name, name) == 0) + return ql; + } + return NULL; +} + +static int +tlist_cmp_name(const char *tname, const char *qname) +{ + struct tlist *tl = tlist_find_by_name(tname); + struct tlist *ql = tlist_find_by_name(qname); + if (tl == NULL) + return 1; + if (ql == NULL) + return -1; + return tlist_cmp(tl, ql); +} + +static int +tlist_cmp(const struct tlist *tl, const struct tlist *ql) +{ + int ret; + struct template *t, *q; + + if (tl == ql) + return 0; + ret = strcmp(tl->header, ql->header); + if (ret != 0) return ret; + + q = HEIM_TAILQ_FIRST(&ql->template); + HEIM_TAILQ_FOREACH(t, &tl->template, members) { + if (q == NULL) return 1; + + if (t->ptr == NULL || q->ptr == NULL) { + ret = strcmp(t->line, q->line); + if (ret != 0) return ret; + } else { + ret = strcmp(t->tt, q->tt); + if (ret != 0) return ret; + + ret = strcmp(t->offset, q->offset); + if (ret != 0) return ret; + + if ((ret = strcmp(t->ptr, q->ptr)) != 0 || + (ret = tlist_cmp_name(t->ptr, q->ptr)) != 0) + return ret; + } + q = HEIM_TAILQ_NEXT(q, members); + } + if (q != NULL) return -1; + return 0; +} + + +static const char * +tlist_find_dup(const struct tlist *tl) +{ + struct tlist *ql; + + HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (tlist_cmp(ql, tl) == 0) { + numdups++; + return ql->name; + } + } + return NULL; +} + + +/* + * Add an entry to a template. + */ + +static struct template * +add_line(struct templatehead *t, const char *fmt, ...) +{ + struct template *q = calloc(1, sizeof(*q)); + va_list ap; + va_start(ap, fmt); + if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL) + errx(1, "malloc"); + va_end(ap); + HEIM_TAILQ_INSERT_TAIL(t, q, members); + return q; +} + +/* + * Add an entry to a template, with the pointer field being a symbol name of a + * template (i.e., an array, which decays to a pointer as usual in C). + */ +static void +add_line_pointer(struct templatehead *t, + const char *ptr, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + if (ptr[0] == '&') + q = add_line(t, "{ %s, %s, %s }", tt, offset, ptr); + else + q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(ptr); +} + +/* + * Add an entry to a template where the pointer field is a string literal. + */ +static void +add_line_string(struct templatehead *t, + const char *str, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + q = add_line(t, "{ %s, %s, \"%s\" }", tt, offset, str); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(str); +} + +/* + * Add an entry to a template, with the pointer field being a reference to + * named object of a type other than a template or other array type. + */ +static void +add_line_pointer_reference(struct templatehead *t, + const char *ptr, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + q = add_line(t, "{ %s, %s, (const void *)&asn1_%s }", tt, offset, ptr); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(ptr); +} + +static int +use_extern(const Symbol *s) +{ + if (s->type == NULL) + return 1; + return 0; +} + +static int +is_struct(const Type *t, int isstruct) +{ + if (t->type == TType) + return 0; + if (t->type == TSequence || t->type == TSet || t->type == TChoice) + return 1; + if (t->type == TTag) + return is_struct(t->subtype, isstruct); + + if (t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type) { + if (types[t->type].is_struct == 0) + return 0; + return isstruct; + } + if (t->type >= 0 && t->type <= TVisibleString) + errx(1, "types[] is not sorted"); + errx(1, "unknown der type: %d\n", t->type); + return isstruct; +} + +static const Type * +compact_tag(const Type *t) +{ + while (t->type == TTag) + t = t->subtype; + return t; +} + +static void +defval(struct templatehead *temp, Member *m) +{ + switch (m->defval->type) { + case booleanvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)(uintptr_t)%u }", + m->defval->u.booleanvalue); + break; + case nullvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)(uintptr_t)0 }"); + break; + case integervalue: { + const char *dv = "A1_DV_INTEGER"; + Type *t = m->type; + + for (;;) { + if (t->range) + break; + if (t->type == TInteger && t->members) + break; + if (t->type == TEnumerated) + break; + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + errx(1, "DEFAULT values for unconstrained INTEGER members not supported"); + } + + if (t->members) + dv = "A1_DV_INTEGER32"; /* XXX Enum size assumptions! No good! */ + else if (t->range && t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + dv = "A1_DV_INTEGER64"; + else if (t->range && t->range->min < 0) + dv = "A1_DV_INTEGER32"; + else if (t->range && t->range->max > UINT_MAX) + dv = "A1_DV_INTEGER64"; + else + dv = "A1_DV_INTEGER32"; + add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)(uintptr_t)%llu }", + dv, (long long)m->defval->u.integervalue); + break; + } + case stringvalue: { + char *quoted; + + if (rk_strasvis("ed, m->defval->u.stringvalue, + VIS_CSTYLE | VIS_NL, "\"") < 0) + err(1, "Could not quote a string"); + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)(uintptr_t)\"%s\" }", + quoted); + free(quoted); + break; + } + case objectidentifiervalue: { + struct objid *o; + size_t sz = sizeof("{ }"); + char *s, *p; + int len; + + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(0, 0, " %d", o->value)) < 0) + err(1, "Could not format integer"); + sz += len; + } + + if ((p = s = malloc(sz)) == NULL) + err(1, "Could not allocate string"); + + len = snprintf(p, sz, "{"); + sz -= len; + p += len; + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(p, sz, " %d", o->value)) < 0 || len > sz - 1) + err(1, "Could not format integer"); + sz -= len; + p += len; + } + if ((len = snprintf(p, sz, " }")) >= sz) + abort(); + sz -= len; + if (sz != 0) + abort(); + + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)(uintptr_t)\"%s\" }", s); + free(s); + break; + } + default: abort(); + } +} + +int +objid_cmp(struct objid *oida, struct objid *oidb) +{ + struct objid *p; + size_t ai, bi, alen, blen; + int avals[20]; + int bvals[20]; + int c; + + /* + * Our OID values are backwards here. Comparing them is hard. + */ + + for (p = oida, alen = 0; + p && alen < sizeof(avals)/sizeof(avals[0]); + p = p->next) + avals[alen++] = p->value; + for (p = oidb, blen = 0; + p && blen < sizeof(bvals)/sizeof(bvals[0]); + p = p->next) + bvals[blen++] = p->value; + if (alen >= sizeof(avals)/sizeof(avals[0]) || + blen >= sizeof(bvals)/sizeof(bvals[0])) + err(1, "OIDs with more components than %llu not supported", + (unsigned long long)sizeof(avals)/sizeof(avals[0])); + + for (ai = 0, bi = 0; ai < alen && bi < blen;) + if ((c = avals[(alen-1)-(ai++)] - bvals[(blen-1)-(bi++)])) + return c; + + if (ai == alen && bi == blen) + return 0; + if (ai == alen) + return 1; + return -1; +} + +int +object_cmp(const void *va, const void *vb) +{ + const IOSObject *oa = *(const IOSObject * const *)va; + const IOSObject *ob = *(const IOSObject * const *)vb; + + switch (oa->typeidf->value->type) { + case booleanvalue: + return oa->typeidf->value->u.booleanvalue - + ob->typeidf->value->u.booleanvalue; + case nullvalue: + return 0; + case integervalue: + return oa->typeidf->value->u.integervalue - + ob->typeidf->value->u.integervalue; + case stringvalue: + return strcmp(oa->typeidf->value->u.stringvalue, + ob->typeidf->value->u.stringvalue); + case objectidentifiervalue: { + return objid_cmp(oa->typeidf->value->u.objectidentifiervalue, + ob->typeidf->value->u.objectidentifiervalue); + } + default: + abort(); + return -1; + } +} + +void +sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */ + Field *typeidfield, /* Field to sort by */ + IOSObject ***objectsp, /* Output: array of objects */ + size_t *nobjsp) /* Output: count of objects */ +{ + IOSObject **objects; + IOSObject *o; + size_t i, nobjs = 0; + + *objectsp = NULL; + + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + ObjectField *typeidobjf = NULL; + ObjectField *of; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + } + if (!typeidobjf) { + warnx("Ignoring incomplete object specification of %s " + "(missing type ID field)", + o->symbol ? o->symbol->name : "<unknown>"); + continue; + } + o->typeidf = typeidobjf; + nobjs++; + } + *nobjsp = nobjs; + + if (nobjs == 0) + return; + + if ((objects = calloc(nobjs, sizeof(*objects))) == NULL) + err(1, "Out of memory"); + *objectsp = objects; + + i = 0; + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + ObjectField *typeidobjf = NULL; + ObjectField *of; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + } + if (typeidobjf) + objects[i++] = o; + } + qsort(objects, nobjs, sizeof(*objects), object_cmp); +} + +static void +template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) +{ + IOSObject **objects = NULL; + IOSObject *o; + struct tlist *tl; + size_t nobjs, i; + + if (os->symbol->emitted_template) + return; + + sort_object_set(os, typeidfield, &objects, &nobjs); + + tl = tlist_new(os->symbol->name); + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", os->symbol->name); + for (i = 0; i < nobjs; i++) { + ObjectField *typeidobjf = NULL, *opentypeobjf = NULL; + ObjectField *of; + char *s = NULL; + + o = objects[i]; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + else if (strcmp(of->name, opentypefield->name) == 0) + opentypeobjf = of; + } + if (!typeidobjf) + continue; /* We've warned about this one already when sorting */ + if (!opentypeobjf) { + warnx("Ignoring incomplete object specification of %s " + "(missing open type field)", + o->symbol ? o->symbol->name : "<unknown>"); + continue; + } + + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", o->symbol->name); + /* + * Some of this logic could stand to move into sanity checks of object + * definitions in asn1parse.y. + */ + switch (typeidobjf->value->type) { + case integervalue: + add_line(&tl->template, + "{ A1_OP_OPENTYPE_ID | A1_OTI_IS_INTEGER, 0, (void *)(uintptr_t)%lld }", + (long long)typeidobjf->value->u.integervalue); + break; + case objectidentifiervalue: + if (asprintf(&s, "oid_%s", + typeidobjf->value->s->gen_name) == -1 || !s) + err(1, "Out of memory"); + add_line_pointer_reference(&tl->template, s, "0", "A1_OP_OPENTYPE_ID"); + free(s); + s = NULL; + break; + default: + errx(1, "Only integer and OID types supported " + "for open type type-ID fields"); + } + + if (asprintf(&s, "sizeof(%s)", + opentypeobjf->type->symbol->gen_name) == -1 || !s) + err(1, "Out of memory"); + add_line_pointer_reference(&tl->template, + opentypeobjf->type->symbol->gen_name, s, + "A1_OP_OPENTYPE"); + free(s); + } + free(objects); + + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nobjs); + tlist_print(tl); + tlist_add(tl); + os->symbol->emitted_template = 1; +} + +static void +template_open_type(struct templatehead *temp, + const char *basetype, + const Type *t, + size_t typeididx, + size_t opentypeidx, + Field *typeidfield, + Field *opentypefield, + Member *m, + int is_array_of_open_type) +{ + char *s = NULL; + + if (typeididx >= 1<<10 || opentypeidx >= 1<<10) + errx(1, "SET/SEQUENCE with too many members (%s)", basetype); + + if (asprintf(&s, "offsetof(%s, _ioschoice_%s)", + basetype, m->gen_name) == -1 || !s) + err(1, "Out of memory"); + + template_object_set(t->actual_parameter, typeidfield, opentypefield); + add_line_pointer(temp, t->actual_parameter->symbol->gen_name, s, + /* + * We always sort object sets for now as we can't import + * values yet, so they must all be known. + */ + "A1_OP_OPENTYPE_OBJSET | A1_OS_IS_SORTED |%s | (%llu << 10) | %llu", + is_array_of_open_type ? "A1_OS_OT_IS_ARRAY" : "0", + (unsigned long long)opentypeidx, + (unsigned long long)typeididx); + free(s); +} + +static void +template_names(struct templatehead *temp, const char *basetype, const Type *t) +{ + Member *m; + + add_line_string(temp, basetype, "0", "A1_OP_NAME"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line_string(temp, m->name, "0", "A1_OP_NAME"); + } +} + +static void +template_members(struct templatehead *temp, + const char *basetype, + const char *name, + const Type *t, + int optional, + int defaulted, + int implicit, + int isstruct, + int need_offset) +{ + char *poffset = NULL; + + if (optional && t->type != TTag && t->type != TType) + errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name); + + poffset = partial_offset(basetype, name, need_offset, isstruct); + + switch (t->type) { + case TType: + if (use_extern(t->symbol)) { + add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s%s, %s, &asn1_extern_%s}", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : "", + poffset, t->symbol->gen_name); + } else { + add_line_pointer(temp, t->symbol->gen_name, poffset, + "A1_OP_TYPE %s%s%s", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : ""); + + } + break; + case TEnumerated: + case TInteger: { + char *varname = NULL; + char *itype = NULL; + + if (t->members) + itype = "IMEMBER"; + else if (t->range == NULL) + itype = "HEIM_INTEGER"; + else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + itype = "INTEGER64"; + else if (t->range->min < 0) + itype = "INTEGER"; + else if (t->range->max > UINT_MAX) + itype = "UNSIGNED64"; + else + itype = "UNSIGNED"; + + /* + * If `t->members' then we should generate a template for those + * members. + * + * We don't know the name of this field, and the type may not have a + * name. If it has no name, we should generate a name for it, and if + * it does have a name, use it, to name a template for its members. + * + * Then we could use that in _asn1_print() to pretty-print values of + * enumerations. + */ + if (t->members && t->symbol) { + struct tlist *tl; + Member *m; + size_t nmemb = 0; + + if (asprintf(&varname, "%s_enum_names", t->symbol->gen_name) == -1 || + varname == NULL) + err(1, "Out of memory"); + + tl = tlist_new(varname); + /* + * XXX We're going to assume that t->members is sorted in + * numerically ascending order in the module source. We should + * really sort it here. + */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > UINT32_MAX) + errx(1, "Cannot handle %s type %s with named bit %s " + "larger than 63", + t->type == TEnumerated ? "ENUMERATED" : "INTEGER", + name, m->gen_name); + add_line(&tl->template, + "{ A1_OP_NAME, %d, \"%s\" }", (int)m->val, m->name); + nmemb++; + } + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nmemb); + /* XXX Accidentally O(N^2)? */ + if (!tlist_find_dup(tl)) { + tlist_print(tl); + tlist_add(tl); + } + add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, asn1_%s }", itype, poffset, varname); + } else { + add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset); + } + break; + } + case TGeneralString: + add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset); + break; + case TTeletexString: + add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset); + break; + case TPrintableString: + add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset); + break; + case TOctetString: + add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset); + break; + case TIA5String: + add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset); + break; + case TBMPString: + add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset); + break; + case TUniversalString: + add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset); + break; + case TVisibleString: + add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset); + break; + case TUTF8String: + add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset); + break; + case TGeneralizedTime: + add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset); + break; + case TUTCTime: + add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset); + break; + case TBoolean: + add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset); + break; + case TOID: + add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset); + break; + case TNull: + break; + case TBitString: { + struct templatehead template; + struct template *q; + Member *m; + size_t count = 0, i; + char *bname = NULL; + FILE *f = get_code_file(); + static unsigned long bmember_counter = 0; + + HEIM_TAILQ_INIT(&template); + + if (HEIM_TAILQ_EMPTY(t->members)) { + add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset); + break; + } + + if (asprintf(&bname, "bmember_%s_%lu", name ? name : "", bmember_counter++) < 0 || bname == NULL) + errx(1, "malloc"); + output_name(bname); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > UINT32_MAX) + errx(1, "Cannot handle BIT STRING type %s with named bit %s " + "larger than 63", name, m->gen_name); + add_line(&template, "{ 0, %d, \"%s\" }", (int)m->val, m->gen_name); + } + + HEIM_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname); + fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)(uintptr_t)%lu) },\n", + rfc1510_bitstring ? "|A1_HBF_RFC1510" : "", + basetype, (unsigned long)count); + i = 1; + HEIM_TAILQ_FOREACH(q, &template, members) { + int last = (HEIM_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname); + + free(bname); + + break; + } + case TSet: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + size_t i = 0, typeididx = 0, opentypeidx = 0; + int is_array_of_open_type = 0; + + if (isstruct && t->actual_parameter) + get_open_type_defn_fields(t, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + + fprintf(get_code_file(), "/* tset: members isstruct: %d */\n", isstruct); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *newbasename = NULL; + + if (m->ellipsis) + continue; + + if (typeidmember == m) typeididx = i; + if (opentypemember == m) opentypeidx = i; + + if (name) { + if (asprintf(&newbasename, "%s_%s", basetype, name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + if (newbasename == NULL) + errx(1, "malloc"); + + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); + + free(newbasename); + i++; + } + + if (isstruct && t->actual_parameter) + template_open_type(temp, basetype, t, typeididx, opentypeidx, + typeidfield, opentypefield, opentypemember, + is_array_of_open_type); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + if (isstruct) + template_names(temp, basetype, t); + break; + } + case TSequence: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + size_t i = 0, typeididx = 0, opentypeidx = 0; + int is_array_of_open_type = 0; + + if (isstruct && t->actual_parameter) + get_open_type_defn_fields(t, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + + fprintf(get_code_file(), "/* tsequence: members isstruct: %d */\n", isstruct); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *newbasename = NULL; + + if (m->ellipsis) + continue; + + if (typeidmember == m) typeididx = i; + if (opentypemember == m) opentypeidx = i; + + if (name) { + if (asprintf(&newbasename, "%s_%s", basetype, name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + if (newbasename == NULL) + errx(1, "malloc"); + + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); + + free(newbasename); + i++; + } + + if (isstruct && t->actual_parameter) + template_open_type(temp, basetype, t, typeididx, opentypeidx, + typeidfield, opentypefield, opentypemember, + is_array_of_open_type); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + if (isstruct) + template_names(temp, basetype, t); + break; + } + case TTag: { + char *tname = NULL, *elname = NULL; + const char *sename, *dupname; + int subtype_is_struct = is_struct(t->subtype, isstruct); + static unsigned long tag_counter = 0; + int tagimplicit = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + + if (t->tag.tagenv == TE_IMPLICIT) { + Type *t2 = t->subtype; + + while (t2->type == TType && (t2->subtype || t2->symbol->type)) + t2 = t2->subtype ? t2->subtype : t2->symbol->type; + if (t2->type != TChoice) + tagimplicit = 1; + } + + fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp"); + + if (subtype_is_struct) + sename = basetype; + else + sename = symbol_name(basetype, t->subtype); + + if (asprintf(&tname, "tag_%s_%lu", name ? name : "", tag_counter++) < 0 || tname == NULL) + errx(1, "malloc"); + output_name(tname); + + if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL) + errx(1, "malloc"); + + generate_template_type(elname, &dupname, NULL, sename, name, + t->subtype, 0, subtype_is_struct, 0); + + add_line_pointer(temp, dupname, poffset, + "A1_TAG_T(%s,%s,%s)%s%s%s", + classname(t->tag.tagclass), + prim ? "PRIM" : "CONS", + valuename(t->tag.tagclass, t->tag.tagvalue), + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + tagimplicit ? "|A1_FLAG_IMPLICIT" : ""); + + free(tname); + free(elname); + + break; + } + case TSetOf: + case TSequenceOf: { + const char *type = NULL, *tname, *dupname; + char *sename = NULL, *elname = NULL; + int subtype_is_struct = is_struct(t->subtype, 0); + static unsigned long seof_counter = 0; + + if (name && subtype_is_struct) { + tname = "seofTstruct"; + if (asprintf(&sename, "%s_%s_val", basetype, name) < 0) + errx(1, "malloc"); + } else if (subtype_is_struct) { + tname = "seofTstruct"; + if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0) + errx(1, "malloc"); + } else { + if (name) + tname = name; + else + tname = "seofTstruct"; + sename = strdup(symbol_name(basetype, t->subtype)); + } + if (sename == NULL) + errx(1, "malloc"); + + if (t->type == TSetOf) type = "A1_OP_SETOF"; + else if (t->type == TSequenceOf) type = "A1_OP_SEQOF"; + else abort(); + + if (asprintf(&elname, "%s_%s_%lu", basetype, tname, seof_counter++) < 0 || elname == NULL) + errx(1, "malloc"); + + generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype, + 0, subtype_is_struct, need_offset); + + add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname); + free(sename); + break; + } + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + struct templatehead template; + struct template *q; + size_t count = 0, i; + char *tname = NULL; + FILE *f = get_code_file(); + Member *m; + int ellipsis = 0; + char *e; + static unsigned long choice_counter = 0; + + HEIM_TAILQ_INIT(&template); + + if (asprintf(&tname, "asn1_choice_%s_%s%lu", + basetype, name ? name : "", choice_counter++) < 0 || tname == NULL) + errx(1, "malloc"); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + const char *dupname; + char *elname = NULL; + char *newbasename = NULL; + int subtype_is_struct; + + if (m->ellipsis) { + ellipsis = 1; + continue; + } + + subtype_is_struct = is_struct(m->type, 0); + + if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL) + errx(1, "malloc"); + + if (subtype_is_struct) { + if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + + if (newbasename == NULL) + errx(1, "malloc"); + + + generate_template_type(elname, &dupname, NULL, + symbol_name(newbasename, m->type), + NULL, m->type, 0, subtype_is_struct, 1); + + add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }", + m->label, isstruct ? "struct " : "", + basetype, m->gen_name, + dupname); + + free(elname); + free(newbasename); + } + + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line(&template, "{ 0, 0, \"%s\" }", m->name); + } + + e = NULL; + if (ellipsis) { + if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL) + errx(1, "malloc"); + } + + HEIM_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template %s[] = {\n", tname); + fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)(uintptr_t)%lu) },\n", + e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count); + i = 1; + HEIM_TAILQ_FOREACH(q, &template, members) { + int last = (HEIM_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + free(e); + free(tname); + break; + } + default: + abort (); + } + if (poffset) + free(poffset); +} + +static void +gen_extern_stubs(FILE *f, const char *name) +{ + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s = {\n" + "\t(asn1_type_encode)encode_%s,\n" + "\t(asn1_type_decode)decode_%s,\n" + "\t(asn1_type_length)length_%s,\n" + "\t(asn1_type_copy)copy_%s,\n" + "\t(asn1_type_release)free_%s,\n" + "\t(asn1_type_print)print_%s,\n" + "\tsizeof(%s)\n" + "};\n", + name, name, name, name, + name, name, name, name); +} + +void +gen_template_import(const Symbol *s) +{ + FILE *f = get_code_file(); + + if (template_flag == 0) + return; + + gen_extern_stubs(f, s->gen_name); +} + +void +generate_template_type_forward(const char *name) +{ + fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", name); +} + +void +generate_template_objectset_forwards(const Symbol *s) +{ + if (!template_flag) + return; + fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", + s->gen_name); +} + +static void +generate_template_type(const char *varname, + const char **dupname, + const char *symname, + const char *basetype, + const char *name, + Type *type, + int optional, + int isstruct, + int need_offset) +{ + struct tlist *tl; + const char *d; + char *szt = NULL; + int have_ellipsis = 0; + int implicit = 0; + int n; + + tl = tlist_new(varname); + + if (type->type == TTag && type->tag.tagenv == TE_IMPLICIT) { + Type *t = type->subtype ? type->subtype : type->symbol->type; + + while (t->type == TType && (t->subtype || t->symbol->type)) + t = t->subtype ? t->subtype : t->symbol->type; + if (t->type != TChoice) + implicit = (type->tag.tagenv == TE_IMPLICIT); + } + + template_members(&tl->template, basetype, name, type, optional, 0, + implicit, isstruct, need_offset); + + /* if its a sequence or set type, check if there is a ellipsis */ + if (type->type == TSequence || type->type == TSet) { + Member *m; + HEIM_TAILQ_FOREACH(m, type->members, members) { + if (m->ellipsis) + have_ellipsis = 1; + } + } + + if (isstruct) + if (name) + n = asprintf(&szt, "struct %s_%s", basetype, name); + else + n = asprintf(&szt, "struct %s", basetype); + else + n = asprintf(&szt, "%s", basetype); + if (n < 0 || szt == NULL) + errx(1, "malloc"); + + if (HEIM_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull) + errx(1, "Tag %s...%s with no content ?", basetype, name ? name : ""); + + fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name); + + tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)(uintptr_t)%lu) }", + (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "", + have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl)); + + free(szt); + + /* XXX Accidentally O(N^2)? */ + d = tlist_find_dup(tl); + if (d) { +#if 0 + if (strcmp(d, tl->name) == 0) + errx(1, "found dup of ourself: %s", d); +#endif + *dupname = d; + } else { + *dupname = tl->name; + tlist_print(tl); + tlist_add(tl); + } +} + + +void +generate_template(const Symbol *s) +{ + FILE *f = get_code_file(); + const char *dupname; + struct decoration deco; + ssize_t more_deco = -1; + + if (use_extern(s)) { + gen_extern_stubs(f, s->gen_name); + return; + } + + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (!deco.ext) + continue; + if (deco.void_star && deco.header_name) + fprintf(f, "#include %s\n", deco.header_name); + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s_%s = {\n" + "\t(asn1_type_encode)0,\n" + "\t(asn1_type_decode)0,\n" + "\t(asn1_type_length)0,\n" + "\t(asn1_type_copy)%s,\n" + "\t(asn1_type_release)%s,\n" + "\t(asn1_type_print)0,\n" + "\tsizeof(%s)\n" + "};\n", s->gen_name, deco.field_name, + deco.copy_function_name && deco.copy_function_name[0] ? + deco.copy_function_name : "0", + deco.free_function_name && deco.free_function_name[0] ? + deco.free_function_name : "0", + deco.void_star ? "void *" : deco.field_type); + free(deco.field_type); + } + + generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n" + "{\n" + " memset(data, 0, sizeof(*data));\n" + " return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname, + support_ber ? "A1_PF_ALLOW_BER" : "0"); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n" + "{\n" + " return _asn1_encode%s(asn1_%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + fuzzer_string, + dupname); + + fprintf(f, + "\n" + "size_t ASN1CALL\n" + "length_%s(const %s *data)\n" + "{\n" + " return _asn1_length%s(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + fuzzer_string, + dupname); + + + fprintf(f, + "\n" + "void ASN1CALL\n" + "free_%s(%s *data)\n" + "{\n" + " _asn1_free_top(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "copy_%s(const %s *from, %s *to)\n" + "{\n" + " return _asn1_copy_top(asn1_%s, from, to);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "char * ASN1CALL\n" + "print_%s(const %s *data, int flags)\n" + "{\n" + " return _asn1_print_top(asn1_%s, flags, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); +} diff --git a/third_party/heimdal/lib/asn1/hash.c b/third_party/heimdal/lib/asn1/hash.c new file mode 100644 index 0000000..73b6cf9 --- /dev/null +++ b/third_party/heimdal/lib/asn1/hash.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Hash table functions + */ + +#include "gen_locl.h" + +RCSID("$Id$"); + +static Hashentry *_search(Hashtab * htab, /* The hash table */ + void *ptr); /* And key */ + +Hashtab * +hashtabnew(int sz, + int (*cmp) (void *, void *), + unsigned (*hash) (void *)) +{ + Hashtab *htab; + int i; + + assert(sz > 0); + + htab = (Hashtab *) malloc(sizeof(Hashtab) + (sz - 1) * sizeof(Hashentry *)); + if (htab == NULL) + return NULL; + + for (i = 0; i < sz; ++i) + htab->tab[i] = NULL; + + htab->cmp = cmp; + htab->hash = hash; + htab->sz = sz; + return htab; +} + +/* Intern search function */ + +static Hashentry * +_search(Hashtab * htab, void *ptr) +{ + Hashentry *hptr; + + assert(htab && ptr); + + for (hptr = htab->tab[(*htab->hash) (ptr) % htab->sz]; + hptr; + hptr = hptr->next) + if ((*htab->cmp) (ptr, hptr->ptr) == 0) + break; + return hptr; +} + +/* Search for element in hash table */ + +void * +hashtabsearch(Hashtab * htab, void *ptr) +{ + Hashentry *tmp; + + tmp = _search(htab, ptr); + return tmp ? tmp->ptr : tmp; +} + +/* add element to hash table */ +/* if already there, set new value */ +/* !NULL if succesful */ + +void * +hashtabadd(Hashtab * htab, void *ptr) +{ + Hashentry *h = _search(htab, ptr); + Hashentry **tabptr; + + assert(htab && ptr); + + if (h) + free((void *) h->ptr); + else { + h = (Hashentry *) malloc(sizeof(Hashentry)); + if (h == NULL) { + return NULL; + } + tabptr = &htab->tab[(*htab->hash) (ptr) % htab->sz]; + h->next = *tabptr; + *tabptr = h; + h->prev = tabptr; + if (h->next) + h->next->prev = &h->next; + } + h->ptr = ptr; + return h; +} + +/* delete element with key key. Iff freep, free Hashentry->ptr */ + +int +_hashtabdel(Hashtab * htab, void *ptr, int freep) +{ + Hashentry *h; + + assert(htab && ptr); + + h = _search(htab, ptr); + if (h) { + if (freep) + free(h->ptr); + if ((*(h->prev) = h->next)) + h->next->prev = h->prev; + free(h); + return 0; + } else + return -1; +} + +/* Do something for each element */ + +void +hashtabforeach(Hashtab * htab, int (*func) (void *ptr, void *arg), + void *arg) +{ + Hashentry **h, *g; + + assert(htab); + + for (h = htab->tab; h < &htab->tab[htab->sz]; ++h) + for (g = *h; g; g = g->next) + if ((*func) (g->ptr, arg)) + return; +} + +/* standard hash-functions for strings */ + +unsigned +hashadd(const char *s) +{ /* Standard hash function */ + unsigned i; + + assert(s); + + for (i = 0; *s; ++s) + i += *s; + return i; +} + +unsigned +hashcaseadd(const char *s) +{ /* Standard hash function */ + unsigned i; + + assert(s); + + for (i = 0; *s; ++s) + i += toupper((unsigned char)*s); + return i; +} + +#define TWELVE (sizeof(unsigned)) +#define SEVENTYFIVE (6*sizeof(unsigned)) +#define HIGH_BITS (~((unsigned)(~0) >> TWELVE)) + +unsigned +hashjpw(const char *ss) +{ /* another hash function */ + unsigned h = 0; + unsigned g; + const unsigned char *s = (const unsigned char *)ss; + + for (; *s; ++s) { + h = (h << TWELVE) + *s; + if ((g = h & HIGH_BITS)) + h = (h ^ (g >> SEVENTYFIVE)) & ~HIGH_BITS; + } + return h; +} diff --git a/third_party/heimdal/lib/asn1/hash.h b/third_party/heimdal/lib/asn1/hash.h new file mode 100644 index 0000000..f37bdbb --- /dev/null +++ b/third_party/heimdal/lib/asn1/hash.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * hash.h. Header file for hash table functions + */ + +/* $Id$ */ + +struct hashentry { /* Entry in bucket */ + struct hashentry **prev; + struct hashentry *next; + void *ptr; +}; + +typedef struct hashentry Hashentry; + +struct hashtab { /* Hash table */ + int (*cmp)(void *, void *); /* Compare function */ + unsigned (*hash)(void *); /* hash function */ + int sz; /* Size */ + Hashentry *tab[1]; /* The table */ +}; + +typedef struct hashtab Hashtab; + +/* prototypes */ + +Hashtab *hashtabnew(int sz, + int (*cmp)(void *, void *), + unsigned (*hash)(void *)); /* Make new hash table */ + +void *hashtabsearch(Hashtab *htab, /* The hash table */ + void *ptr); /* The key */ + + +void *hashtabadd(Hashtab *htab, /* The hash table */ + void *ptr); /* The element */ + +int _hashtabdel(Hashtab *htab, /* The table */ + void *ptr, /* Key */ + int freep); /* Free data part? */ + +void hashtabforeach(Hashtab *htab, + int (*func)(void *ptr, void *arg), + void *arg); + +unsigned hashadd(const char *s); /* Standard hash function */ +unsigned hashcaseadd(const char *s); /* Standard hash function */ +unsigned hashjpw(const char *s); /* another hash function */ + +/* macros */ + + /* Don't free space */ +#define hashtabdel(htab,key) _hashtabdel(htab,key,FALSE) + +#define hashtabfree(htab,key) _hashtabdel(htab,key,TRUE) /* Do! */ diff --git a/third_party/heimdal/lib/asn1/heim_asn1.h b/third_party/heimdal/lib/asn1/heim_asn1.h new file mode 100644 index 0000000..072ff15 --- /dev/null +++ b/third_party/heimdal/lib/asn1/heim_asn1.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2003-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __HEIM_ANY_H__ +#define __HEIM_ANY_H__ 1 + +int ASN1CALL encode_heim_any(unsigned char *, size_t, const heim_any *, size_t *); +int ASN1CALL decode_heim_any(const unsigned char *, size_t, heim_any *, size_t *); +void ASN1CALL free_heim_any(heim_any *); +char *ASN1CALL print_heim_any(const heim_any *, int); +size_t ASN1CALL length_heim_any(const heim_any *); +int ASN1CALL copy_heim_any(const heim_any *, heim_any *); + +int ASN1CALL encode_heim_any_set(unsigned char *, size_t, + const heim_any_set *, size_t *); +int ASN1CALL decode_heim_any_set(const unsigned char *, size_t, + heim_any_set *,size_t *); +void ASN1CALL free_heim_any_set(heim_any_set *); +char *ASN1CALL print_heim_any_set(const heim_any_set *, int); +size_t ASN1CALL length_heim_any_set(const heim_any_set *); +int ASN1CALL copy_heim_any_set(const heim_any_set *, heim_any_set *); +int ASN1CALL heim_any_cmp(const heim_any_set *, const heim_any_set *); + +int ASN1CALL encode_HEIM_ANY(unsigned char *, size_t, const heim_any *, size_t *); +int ASN1CALL decode_HEIM_ANY(const unsigned char *, size_t, heim_any *, size_t *); +void ASN1CALL free_HEIM_ANY(heim_any *); +char *ASN1CALL print_HEIM_ANY(const heim_any *, int); +size_t ASN1CALL length_HEIM_ANY(const heim_any *); +int ASN1CALL copy_HEIM_ANY(const heim_any *, heim_any *); + +int ASN1CALL encode_HEIM_ANY_SET(unsigned char *, size_t, + const heim_any_set *, size_t *); +int ASN1CALL decode_HEIM_ANY_SET(const unsigned char *, size_t, + heim_any_set *,size_t *); +void ASN1CALL free_HEIM_ANY_SET(heim_any_set *); +char *ASN1CALL print_HEIM_ANY_SET(const heim_any_set *, int); +size_t ASN1CALL length_HEIM_ANY_SET(const heim_any_set *); +int ASN1CALL copy_HEIM_ANY_SET(const heim_any_set *, heim_any_set *); +int ASN1CALL heim_any_cmp(const heim_any_set *, const heim_any_set *); + +#endif /* __HEIM_ANY_H__ */ diff --git a/third_party/heimdal/lib/asn1/krb5.asn1 b/third_party/heimdal/lib/asn1/krb5.asn1 new file mode 100644 index 0000000..bf279a4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/krb5.asn1 @@ -0,0 +1,1066 @@ +-- $Id$ + +KERBEROS5 DEFINITIONS ::= +BEGIN +EXPORTS + AD-AND-OR, + AD-IF-RELEVANT, + AD-KDCIssued, + AD-LoginAlias, + AP-REP, + AP-REQ, + AS-REP, + AS-REQ, + AUTHDATA-TYPE, + Authenticator, + AuthorizationData, + AuthorizationDataElement, + CKSUMTYPE, + ChangePasswdDataMS, + Checksum, + CompositePrincipal, + ENCTYPE, + ETYPE-INFO, + ETYPE-INFO-ENTRY, + ETYPE-INFO2, + ETYPE-INFO2-ENTRY, + EncAPRepPart, + EncASRepPart, + EncKDCRepPart, + EncKrbCredPart, + EncKrbPrivPart, + EncTGSRepPart, + EncTicketPart, + EncryptedData, + EncryptionKey, + EtypeList, + HostAddress, + HostAddresses, + KDC-REQ-BODY, + KDCOptions, + KDC-REP, + KRB-CRED, + KRB-ERROR, + KRB-PRIV, + KRB-SAFE, + KRB-SAFE-BODY, + KerberosString, + KerberosTime, + KrbCredInfo, + LR-TYPE, + LastReq, + METHOD-DATA, + NAME-TYPE, + PA-ClientCanonicalized, + PA-ClientCanonicalizedNames, + PA-DATA, + PA-ENC-TS-ENC, + PA-KERB-KEY-LIST-REP, + PA-KERB-KEY-LIST-REQ, + PA-PAC-OPTIONS, + PA-PAC-REQUEST, + PA-S4U2Self, + PA-S4U-X509-USER, + PA-SERVER-REFERRAL-DATA, + PA-ServerReferralData, + PA-SvrReferralData, + PADATA-TYPE, + PA-FX-FAST-REQUEST, + PA-FX-FAST-REPLY, + Principal, + PrincipalName, + Principals, + Realm, + TGS-REP, + TGS-REQ, + Ticket, + TicketFlags, + TransitedEncoding, + TypedData, + KrbFastResponse, + KrbFastFinished, + KrbFastReq, + KrbFastArmor, + KrbFastArmoredReq, + KDCFastState, + KDCFastCookie, + KDC-PROXY-MESSAGE, + KERB-AD-RESTRICTION-ENTRY, + KERB-TIMES, + KERB-CRED, + KERB-TGS-REQ-IN, + KERB-TGS-REQ-OUT, + KERB-ARMOR-SERVICE-REPLY, + KERB-ERROR-DATA + ; + +NAME-TYPE ::= INTEGER { + KRB5_NT_UNKNOWN(0), -- Name type not known + KRB5_NT_PRINCIPAL(1), -- Just the name of the principal as in + KRB5_NT_SRV_INST(2), -- Service and other unique instance (krbtgt) + KRB5_NT_SRV_HST(3), -- Service with host name as instance + KRB5_NT_SRV_XHST(4), -- Service with host as remaining components + KRB5_NT_UID(5), -- Unique ID + KRB5_NT_X500_PRINCIPAL(6), -- PKINIT + KRB5_NT_SMTP_NAME(7), -- Name in form of SMTP email name + KRB5_NT_ENTERPRISE_PRINCIPAL(10), -- Windows 2000 UPN + KRB5_NT_WELLKNOWN(11), -- Wellknown + KRB5_NT_SRV_HST_DOMAIN(12), -- Domain based service with host name as instance (RFC5179) + KRB5_NT_ENT_PRINCIPAL_AND_ID(-130), -- Windows 2000 UPN and SID + KRB5_NT_MS_PRINCIPAL(-128), -- NT 4 style name + KRB5_NT_MS_PRINCIPAL_AND_ID(-129), -- NT style name and SID + KRB5_NT_NTLM(-1200), -- NTLM name, realm is domain + KRB5_NT_X509_GENERAL_NAME(-1201), -- x509 general name (base64 encoded) + KRB5_NT_GSS_HOSTBASED_SERVICE(-1202), -- not used; remove + KRB5_NT_CACHE_UUID(-1203), -- name is actually a uuid pointing to ccache, use client name in cache + KRB5_NT_SRV_HST_NEEDS_CANON (-195894762) -- Internal: indicates that name canonicalization is needed +} + +-- message types + +MESSAGE-TYPE ::= INTEGER { + krb-as-req(10), -- Request for initial authentication + krb-as-rep(11), -- Response to KRB_AS_REQ request + krb-tgs-req(12), -- Request for authentication based on TGT + krb-tgs-rep(13), -- Response to KRB_TGS_REQ request + krb-ap-req(14), -- application request to server + krb-ap-rep(15), -- Response to KRB_AP_REQ_MUTUAL + krb-safe(20), -- Safe (checksummed) application message + krb-priv(21), -- Private (encrypted) application message + krb-cred(22), -- Private (encrypted) message to forward credentials + krb-error(30) -- Error response +} + + +-- pa-data types + +PADATA-TYPE ::= INTEGER { + KRB5-PADATA-NONE(0), + KRB5-PADATA-TGS-REQ(1), + KRB5-PADATA-AP-REQ(1), + KRB5-PADATA-ENC-TIMESTAMP(2), + KRB5-PADATA-PW-SALT(3), + KRB5-PADATA-ENC-UNIX-TIME(5), + KRB5-PADATA-SANDIA-SECUREID(6), + KRB5-PADATA-SESAME(7), + KRB5-PADATA-OSF-DCE(8), + KRB5-PADATA-CYBERSAFE-SECUREID(9), + KRB5-PADATA-AFS3-SALT(10), + KRB5-PADATA-ETYPE-INFO(11), + KRB5-PADATA-SAM-CHALLENGE(12), -- (sam/otp) + KRB5-PADATA-SAM-RESPONSE(13), -- (sam/otp) + KRB5-PADATA-PK-AS-REQ-19(14), -- (PKINIT-19) + KRB5-PADATA-PK-AS-REP-19(15), -- (PKINIT-19) + KRB5-PADATA-PK-AS-REQ-WIN(15), -- (PKINIT - old number) + KRB5-PADATA-PK-AS-REQ(16), -- (PKINIT-25) + KRB5-PADATA-PK-AS-REP(17), -- (PKINIT-25) + KRB5-PADATA-PA-PK-OCSP-RESPONSE(18), + KRB5-PADATA-ETYPE-INFO2(19), + KRB5-PADATA-USE-SPECIFIED-KVNO(20), + KRB5-PADATA-SVR-REFERRAL-INFO(20), --- old ms referral number + KRB5-PADATA-SAM-REDIRECT(21), -- (sam/otp) + KRB5-PADATA-GET-FROM-TYPED-DATA(22), + KRB5-PADATA-SAM-ETYPE-INFO(23), + KRB5-PADATA-SERVER-REFERRAL(25), + KRB5-PADATA-ALT-PRINC(24), -- (crawdad@fnal.gov) + KRB5-PADATA-SAM-CHALLENGE2(30), -- (kenh@pobox.com) + KRB5-PADATA-SAM-RESPONSE2(31), -- (kenh@pobox.com) + KRB5-PA-EXTRA-TGT(41), -- Reserved extra TGT + KRB5-PADATA-FX-FAST-ARMOR(71), -- fast armor + KRB5-PADATA-TD-KRB-PRINCIPAL(102), -- PrincipalName + KRB5-PADATA-PK-TD-TRUSTED-CERTIFIERS(104), -- PKINIT + KRB5-PADATA-PK-TD-CERTIFICATE-INDEX(105), -- PKINIT + KRB5-PADATA-TD-APP-DEFINED-ERROR(106), -- application specific + KRB5-PADATA-TD-REQ-NONCE(107), -- INTEGER + KRB5-PADATA-TD-REQ-SEQ(108), -- INTEGER + KRB5-PADATA-PA-PAC-REQUEST(128), -- jbrezak@exchange.microsoft.com + KRB5-PADATA-FOR-USER(129), -- MS-KILE + KRB5-PADATA-FOR-X509-USER(130), -- MS-KILE + KRB5-PADATA-FOR-CHECK-DUPS(131), -- MS-KILE + KRB5-PADATA-AS-CHECKSUM(132), -- MS-KILE + KRB5-PADATA-PK-AS-09-BINDING(132), -- client send this to + -- tell KDC that is supports + -- the asCheckSum in the + -- PK-AS-REP + KRB5-PADATA-FX-COOKIE(133), -- krb-wg-preauth-framework + KRB5-PADATA-AUTHENTICATION-SET(134), -- krb-wg-preauth-framework + KRB5-PADATA-AUTH-SET-SELECTED(135), -- krb-wg-preauth-framework + KRB5-PADATA-FX-FAST(136), -- krb-wg-preauth-framework + KRB5-PADATA-FX-ERROR(137), -- krb-wg-preauth-framework + KRB5-PADATA-ENCRYPTED-CHALLENGE(138), -- krb-wg-preauth-framework + KRB5-PADATA-OTP-CHALLENGE(141), -- (gareth.richards@rsa.com) + KRB5-PADATA-OTP-REQUEST(142), -- (gareth.richards@rsa.com) + KBB5-PADATA-OTP-CONFIRM(143), -- (gareth.richards@rsa.com) + KRB5-PADATA-OTP-PIN-CHANGE(144), -- (gareth.richards@rsa.com) + KRB5-PADATA-EPAK-AS-REQ(145), + KRB5-PADATA-EPAK-AS-REP(146), + KRB5-PADATA-PKINIT-KX(147), -- krb-wg-anon + KRB5-PADATA-PKU2U-NAME(148), -- zhu-pku2u + KRB5-PADATA-REQ-ENC-PA-REP(149), -- + KRB5-PADATA-AS-FRESHNESS(150), -- RFC 8070 + KER5-PADATA-KERB-KEY-LIST-REQ(161), -- MS-KILE + KER5-PADATA-KERB-PAKEY-LIST-REP(162), -- MS-KILE + KRB5-PADATA-SUPPORTED-ETYPES(165), -- MS-KILE + KRB5-PADATA-PAC-OPTIONS(167), -- MS-KILE + KRB5-PADATA-GSS(655) -- krb-wg-gss-preauth + +} + +AUTHDATA-TYPE ::= INTEGER { + KRB5-AUTHDATA-IF-RELEVANT(1), + KRB5-AUTHDATA-INTENDED-FOR_SERVER(2), + KRB5-AUTHDATA-INTENDED-FOR-APPLICATION-CLASS(3), + KRB5-AUTHDATA-KDC-ISSUED(4), + KRB5-AUTHDATA-AND-OR(5), + KRB5-AUTHDATA-MANDATORY-TICKET-EXTENSIONS(6), + KRB5-AUTHDATA-IN-TICKET-EXTENSIONS(7), + KRB5-AUTHDATA-MANDATORY-FOR-KDC(8), + KRB5-AUTHDATA-INITIAL-VERIFIED-CAS(9), + KRB5-AUTHDATA-OSF-DCE(64), + KRB5-AUTHDATA-SESAME(65), + KRB5-AUTHDATA-OSF-DCE-PKI-CERTID(66), + KRB5-AUTHDATA-AUTHENTICATION-STRENGTH(70), + KRB5-AUTHDATA-FX-FAST-ARMOR(71), + KRB5-AUTHDATA-FX-FAST-USED(72), + KRB5-AUTHDATA-WIN2K-PAC(128), + KRB5-AUTHDATA-GSS-API-ETYPE-NEGOTIATION(129), -- Authenticator only + KRB5-AUTHDATA-SIGNTICKET-OLDER(-17), + KRB5-AUTHDATA-SIGNTICKET-OLD(142), + KRB5-AUTHDATA-SIGNTICKET(512), + KRB5-AUTHDATA-SYNTHETIC-PRINC-USED(513), -- principal was synthetised + KRB5-AUTHDATA-KERB-LOCAL(141), -- MS-KILE + KRB5-AUTHDATA-TOKEN-RESTRICTIONS(142), -- MS-KILE + KRB5-AUTHDATA-AP-OPTIONS(143), -- MS-KILE + KRB5-AUTHDATA-TARGET-PRINCIPAL(144), -- MS-KILE + -- N.B. these assignments have not been confirmed yet. + -- + -- DO NOT USE in production yet! + KRB5-AUTHDATA-ON-BEHALF-OF(580), -- UTF8String princ name + KRB5-AUTHDATA-BEARER-TOKEN-JWT(581), -- JWT token + KRB5-AUTHDATA-BEARER-TOKEN-SAML(582), -- SAML token + KRB5-AUTHDATA-BEARER-TOKEN-OIDC(583), -- OIDC token + KRB5-AUTHDATA-CSR-AUTHORIZED(584), -- Proxy has authorized client + -- to requested exts in CSR + KRB5-AUTHDATA-GSS-COMPOSITE-NAME(655) -- gss_export_name_composite +} + +-- checksumtypes + +CKSUMTYPE ::= INTEGER { + CKSUMTYPE_NONE(0), + CKSUMTYPE_CRC32(1), + CKSUMTYPE_RSA_MD4(2), + CKSUMTYPE_RSA_MD4_DES(3), + CKSUMTYPE_DES_MAC(4), + CKSUMTYPE_DES_MAC_K(5), + CKSUMTYPE_RSA_MD4_DES_K(6), + CKSUMTYPE_RSA_MD5(7), + CKSUMTYPE_RSA_MD5_DES(8), + CKSUMTYPE_RSA_MD5_DES3(9), + CKSUMTYPE_SHA1_OTHER(10), + CKSUMTYPE_HMAC_SHA1_DES3(12), + CKSUMTYPE_SHA1(14), + CKSUMTYPE_HMAC_SHA1_96_AES_128(15), + CKSUMTYPE_HMAC_SHA1_96_AES_256(16), + CKSUMTYPE_HMAC_SHA256_128_AES128(19), + CKSUMTYPE_HMAC_SHA384_192_AES256(20), + CKSUMTYPE_GSSAPI(0x8003), + CKSUMTYPE_HMAC_MD5(-138), -- unofficial microsoft number + CKSUMTYPE_HMAC_MD5_ENC(-1138), -- even more unofficial + CKSUMTYPE_SHA256(-21), + CKSUMTYPE_SHA384(-22), + CKSUMTYPE_SHA512(-23) +} + +--enctypes +ENCTYPE ::= INTEGER { + KRB5_ENCTYPE_NULL(0), + KRB5_ENCTYPE_DES_CBC_CRC(1), + KRB5_ENCTYPE_DES_CBC_MD4(2), + KRB5_ENCTYPE_DES_CBC_MD5(3), + KRB5_ENCTYPE_DES3_CBC_MD5(5), + KRB5_ENCTYPE_OLD_DES3_CBC_SHA1(7), + KRB5_ENCTYPE_SIGN_DSA_GENERATE(8), + KRB5_ENCTYPE_ENCRYPT_RSA_PRIV(9), + KRB5_ENCTYPE_ENCRYPT_RSA_PUB(10), + KRB5_ENCTYPE_DES3_CBC_SHA1(16), -- with key derivation + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96(17), + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96(18), + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128(19), + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192(20), + KRB5_ENCTYPE_ARCFOUR_HMAC_MD5(23), + KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56(24), + KRB5_ENCTYPE_ENCTYPE_PK_CROSS(48), +-- some "old" windows types + KRB5_ENCTYPE_ARCFOUR_MD4(-128), + KRB5_ENCTYPE_ARCFOUR_HMAC_OLD(-133), + KRB5_ENCTYPE_ARCFOUR_HMAC_OLD_EXP(-135), +-- these are for Heimdal internal use + KRB5_ENCTYPE_DES_CBC_NONE(-0x1000), + KRB5_ENCTYPE_DES3_CBC_NONE(-0x1001), + KRB5_ENCTYPE_DES_CFB64_NONE(-0x1002), + KRB5_ENCTYPE_DES_PCBC_NONE(-0x1003), + KRB5_ENCTYPE_DIGEST_MD5_NONE(-0x1004), -- private use, lukeh@padl.com + KRB5_ENCTYPE_CRAM_MD5_NONE(-0x1005) -- private use, lukeh@padl.com +} + + + + +-- this is sugar to make something ASN1 does not have: unsigned + +Krb5UInt32 ::= INTEGER (0..4294967295) +Krb5Int32 ::= INTEGER (-2147483648..2147483647) + +KerberosString ::= GeneralString + +Realm ::= GeneralString +PrincipalName ::= SEQUENCE { + name-type[0] NAME-TYPE, + name-string[1] SEQUENCE OF GeneralString +} + +HostAddress ::= SEQUENCE { + addr-type[0] Krb5Int32, + address[1] OCTET STRING +} + +-- This is from RFC1510. +-- +-- HostAddresses ::= SEQUENCE OF SEQUENCE { +-- addr-type[0] Krb5Int32, +-- address[1] OCTET STRING +-- } + +-- This seems much better. +HostAddresses ::= SEQUENCE OF HostAddress + + +KerberosTime ::= GeneralizedTime -- Specifying UTC time zone (Z) + +AuthorizationDataElement ::= SEQUENCE { + ad-type[0] Krb5Int32, + ad-data[1] OCTET STRING +} + +AuthorizationData ::= SEQUENCE OF AuthorizationDataElement + +APOptions ::= BIT STRING { + reserved(0), + use-session-key(1), + mutual-required(2) +} + +TicketFlags ::= BIT STRING { + reserved(0), + forwardable(1), + forwarded(2), + proxiable(3), + proxy(4), + may-postdate(5), + postdated(6), + invalid(7), + renewable(8), + initial(9), + pre-authent(10), + hw-authent(11), + transited-policy-checked(12), + ok-as-delegate(13), + enc-pa-rep(15), + anonymous(16) +} + +KDCOptions ::= BIT STRING { + reserved(0), + forwardable(1), + forwarded(2), + proxiable(3), + proxy(4), + allow-postdate(5), + postdated(6), + renewable(8), + cname-in-addl-tkt(14), -- ms extension + canonicalize(15), + request-anonymous(16), + disable-transited-check(26), + renewable-ok(27), + enc-tkt-in-skey(28), + renew(30), + validate(31) +} + +LR-TYPE ::= INTEGER { + LR_NONE(0), -- no information + LR_INITIAL_TGT(1), -- last initial TGT request + LR_INITIAL(2), -- last initial request + LR_ISSUE_USE_TGT(3), -- time of newest TGT used + LR_RENEWAL(4), -- time of last renewal + LR_REQUEST(5), -- time of last request (of any type) + LR_PW_EXPTIME(6), -- expiration time of password + LR_ACCT_EXPTIME(7) -- expiration time of account +} + +LastReq ::= SEQUENCE OF SEQUENCE { + lr-type[0] LR-TYPE, + lr-value[1] KerberosTime +} + + +EncryptedData ::= SEQUENCE { + etype[0] ENCTYPE, -- EncryptionType + kvno[1] Krb5Int32 OPTIONAL, + cipher[2] OCTET STRING -- ciphertext +} + +EncryptionKey ::= SEQUENCE { + keytype[0] Krb5Int32, + keyvalue[1] OCTET STRING +} + +-- encoded Transited field +TransitedEncoding ::= SEQUENCE { + tr-type[0] Krb5Int32, -- must be registered + contents[1] OCTET STRING +} + +Ticket ::= [APPLICATION 1] SEQUENCE { + tkt-vno[0] Krb5Int32, + realm[1] Realm, + sname[2] PrincipalName, + enc-part[3] EncryptedData +} +-- Encrypted part of ticket +EncTicketPart ::= [APPLICATION 3] SEQUENCE { + flags[0] TicketFlags, + key[1] EncryptionKey, + crealm[2] Realm, + cname[3] PrincipalName, + transited[4] TransitedEncoding, + authtime[5] KerberosTime, + starttime[6] KerberosTime OPTIONAL, + endtime[7] KerberosTime, + renew-till[8] KerberosTime OPTIONAL, + caddr[9] HostAddresses OPTIONAL, + authorization-data[10] AuthorizationData OPTIONAL +} + +Checksum ::= SEQUENCE { + cksumtype[0] CKSUMTYPE, + checksum[1] OCTET STRING +} + +-- For GSS name attributes [RFC6680] we'll decorate Principal (which is not an +-- RFC4120 type, but which we use a) in HDB, b) in the API as that which +-- krb5_principal points to) with PrincipalNameAttrs. +-- +-- Attributes have three possible sources in Heimdal Kerberos at this time: +-- +-- - the EncKDCRepPart (for the client's attributes on the client side) +-- - the EncTicketPart (for the client's attributes on the server side) +-- - the Authenticator's AuthorizationData (if any; server-side) +-- +-- In principle there can be more: +-- +-- - locally-set (asserted) attributes +-- - locally-looked-up attributes (e.g., in LDAP) +-- - locally-transformed attributes (e.g., local groups, filtered SIDs from a +-- PAC, etc.) +-- +-- We could also cache "cooked" attributes as reported by the RFC6680 API given +-- the sources we have. +-- +-- For now we'll only support authenticated attributes where those come from +-- the KDC, and attributes asserted in Authenticator authz-data. +PrincipalNameAttrSrc ::= CHOICE { + enc-kdc-rep-part [0] EncKDCRepPart, -- minus session key + enc-ticket-part [1] EncTicketPart -- minus session key +} +PrincipalNameAttrs ::= SEQUENCE { + -- True if this name was authenticated via an AP-REQ or a KDC-REP + authenticated [0] BOOLEAN, + -- These are compiled from the Ticket, KDC-REP, and/or Authenticator + source [1] PrincipalNameAttrSrc OPTIONAL, + authenticator-ad [2] AuthorizationData OPTIONAL, + -- For the server on the client side we should keep track of the + -- transit path taken to reach it (if absent -> unknown). + -- + -- We don't learn much more about the server from the KDC. + peer-realm [3] Realm OPTIONAL, + transited [4] TransitedEncoding OPTIONAL, + -- True if the PAC was verified + pac-verified [5] BOOLEAN, + -- True if any AD-KDC-ISSUEDs in the Ticket were validated + kdc-issued-verified [6] BOOLEAN, + -- TODO: Add requested attributes, for gss_set_name_attribute(), which + -- should cause corresponding authz-data elements to be added to + -- any TGS-REQ or to the AP-REQ's Authenticator as appropriate. + want-ad [7] AuthorizationData OPTIONAL +} +-- This is our type for exported composite name tokens for GSS [RFC6680]. +-- It's the same as Principal (below) as decorated with (see krb5.opt file and +-- asn1_compile usage), except it's not decorated, so the name attributes are +-- encoded/decoded. +CompositePrincipal ::= [APPLICATION 48] SEQUENCE { + name[0] PrincipalName, + realm[1] Realm, + nameattrs[2] PrincipalNameAttrs OPTIONAL +} + +-- This is not part of RFC1510/RFC4120. We use this internally as our +-- krb5_principal (which is a typedef of *Principal), and in HDB entries. +Principal ::= SEQUENCE { + name[0] PrincipalName, + realm[1] Realm + -- This will be decorated with an optional nameattrs field of + -- PrincipalNameAttrs type that doesn't get encoded. Same as + -- CompositePrincipal above, except that CompositePrincipal's + -- nameattrs field does get encoded, while Principal's does not: + -- + -- nameattrs[2] PrincipalNameAttrs OPTIONAL +} + +Principals ::= SEQUENCE OF Principal + +Authenticator ::= [APPLICATION 2] SEQUENCE { + authenticator-vno[0] Krb5Int32, + crealm[1] Realm, + cname[2] PrincipalName, + cksum[3] Checksum OPTIONAL, + cusec[4] Krb5Int32, + ctime[5] KerberosTime, + subkey[6] EncryptionKey OPTIONAL, + seq-number[7] Krb5UInt32 OPTIONAL, + authorization-data[8] AuthorizationData OPTIONAL +} + +PA-DATA ::= SEQUENCE { + -- might be encoded AP-REQ + padata-type[1] PADATA-TYPE, + padata-value[2] OCTET STRING +} + +ETYPE-INFO-ENTRY ::= SEQUENCE { + etype[0] ENCTYPE, + salt[1] OCTET STRING OPTIONAL, + salttype[2] Krb5Int32 OPTIONAL +} + +ETYPE-INFO ::= SEQUENCE OF ETYPE-INFO-ENTRY + +ETYPE-INFO2-ENTRY ::= SEQUENCE { + etype[0] ENCTYPE, + salt[1] KerberosString OPTIONAL, + s2kparams[2] OCTET STRING OPTIONAL +} + +ETYPE-INFO2 ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY + +METHOD-DATA ::= SEQUENCE OF PA-DATA + +TypedData ::= SEQUENCE { + data-type[0] Krb5Int32, + data-value[1] OCTET STRING OPTIONAL +} + +TYPED-DATA ::= SEQUENCE SIZE (1..MAX) OF TypedData + +KDC-REQ-BODY ::= SEQUENCE { + kdc-options[0] KDCOptions, + cname[1] PrincipalName OPTIONAL, -- Used only in AS-REQ + realm[2] Realm, -- Server's realm + -- Also client's in AS-REQ + sname[3] PrincipalName OPTIONAL, + from[4] KerberosTime OPTIONAL, + till[5] KerberosTime OPTIONAL, + rtime[6] KerberosTime OPTIONAL, + nonce[7] Krb5Int32, + etype[8] SEQUENCE OF ENCTYPE, -- EncryptionType, + -- in preference order + addresses[9] HostAddresses OPTIONAL, + enc-authorization-data[10] EncryptedData OPTIONAL, + -- Encrypted AuthorizationData encoding + additional-tickets[11] SEQUENCE OF Ticket OPTIONAL +} + +KDC-REQ ::= SEQUENCE { + pvno[1] Krb5Int32, + msg-type[2] MESSAGE-TYPE, + padata[3] METHOD-DATA OPTIONAL, + req-body[4] KDC-REQ-BODY +} + +AS-REQ ::= [APPLICATION 10] KDC-REQ +TGS-REQ ::= [APPLICATION 12] KDC-REQ + +-- padata-type ::= PA-ENC-TIMESTAMP +-- padata-value ::= EncryptedData - PA-ENC-TS-ENC + +PA-ENC-TS-ENC ::= SEQUENCE { + patimestamp[0] KerberosTime, -- client's time + pausec[1] Krb5Int32 OPTIONAL +} + +-- draft-brezak-win2k-krb-authz-01 +PA-PAC-REQUEST ::= SEQUENCE { + include-pac[0] BOOLEAN -- Indicates whether a PAC + -- should be included or not +} + +-- MS-KILE + +KERB-ERROR-DATA ::= SEQUENCE { + data-type [1] KerbErrorDataType, + data-value [2] OCTET STRING OPTIONAL +} + +KerbErrorDataType ::= INTEGER { + kERB-AP-ERR-TYPE-SKEW-RECOVERY(2), + kERB-ERR-TYPE-EXTENDED(3) +} + +-- MS-KILE/MS-SFU +PAC-OPTIONS-FLAGS ::= BIT STRING { + claims(0), + branch-aware(1), + forward-to-full-dc(2), + resource-based-constrained-delegation(3) +} + +-- MS-KILE +PA-PAC-OPTIONS ::= SEQUENCE { + flags [0] PAC-OPTIONS-FLAGS +} + +-- MS-KILE +-- captures show that [UNIVERSAL 16] is required to parse it +KERB-AD-RESTRICTION-ENTRY ::= [UNIVERSAL 16] SEQUENCE { + restriction-type [0] Krb5Int32, + restriction [1] OCTET STRING -- LSAP_TOKEN_INFO_INTEGRITY structure +} + +-- MS-KILE Section 2.2.11 +PA-KERB-KEY-LIST-REQ ::= SEQUENCE OF ENCTYPE + +-- MS-KILE Section 2.2.12 + +PA-KERB-KEY-LIST-REP ::= SEQUENCE OF ENCTYPE -- EncryptionType, + +-- PacketCable provisioning server location, PKT-SP-SEC-I09-030728.pdf +PROV-SRV-LOCATION ::= GeneralString + +KDC-REP ::= SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + padata[2] METHOD-DATA OPTIONAL, + crealm[3] Realm, + cname[4] PrincipalName, + ticket[5] Ticket, + enc-part[6] EncryptedData +} + +AS-REP ::= [APPLICATION 11] KDC-REP +TGS-REP ::= [APPLICATION 13] KDC-REP + +EncKDCRepPart ::= SEQUENCE { + key[0] EncryptionKey, + last-req[1] LastReq, + nonce[2] Krb5Int32, + key-expiration[3] KerberosTime OPTIONAL, + flags[4] TicketFlags, + authtime[5] KerberosTime, + starttime[6] KerberosTime OPTIONAL, + endtime[7] KerberosTime, + renew-till[8] KerberosTime OPTIONAL, + srealm[9] Realm, + sname[10] PrincipalName, + caddr[11] HostAddresses OPTIONAL, + encrypted-pa-data[12] METHOD-DATA OPTIONAL +} + +EncASRepPart ::= [APPLICATION 25] EncKDCRepPart +EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart + +AP-REQ ::= [APPLICATION 14] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + ap-options[2] APOptions, + ticket[3] Ticket, + authenticator[4] EncryptedData +} + +AP-REP ::= [APPLICATION 15] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + enc-part[2] EncryptedData +} + +EncAPRepPart ::= [APPLICATION 27] SEQUENCE { + ctime[0] KerberosTime, + cusec[1] Krb5Int32, + subkey[2] EncryptionKey OPTIONAL, + seq-number[3] Krb5UInt32 OPTIONAL +} + +KRB-SAFE-BODY ::= SEQUENCE { + user-data[0] OCTET STRING, + timestamp[1] KerberosTime OPTIONAL, + usec[2] Krb5Int32 OPTIONAL, + seq-number[3] Krb5UInt32 OPTIONAL, + s-address[4] HostAddress OPTIONAL, + r-address[5] HostAddress OPTIONAL +} + +KRB-SAFE ::= [APPLICATION 20] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + safe-body[2] KRB-SAFE-BODY, + cksum[3] Checksum +} + +KRB-PRIV ::= [APPLICATION 21] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + enc-part[3] EncryptedData +} +EncKrbPrivPart ::= [APPLICATION 28] SEQUENCE { + user-data[0] OCTET STRING, + timestamp[1] KerberosTime OPTIONAL, + usec[2] Krb5Int32 OPTIONAL, + seq-number[3] Krb5UInt32 OPTIONAL, + s-address[4] HostAddress OPTIONAL, -- sender's addr + r-address[5] HostAddress OPTIONAL -- recip's addr +} + +KRB-CRED ::= [APPLICATION 22] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, -- KRB_CRED + tickets[2] SEQUENCE OF Ticket, + enc-part[3] EncryptedData +} + +KrbCredInfo ::= SEQUENCE { + key[0] EncryptionKey, + prealm[1] Realm OPTIONAL, + pname[2] PrincipalName OPTIONAL, + flags[3] TicketFlags OPTIONAL, + authtime[4] KerberosTime OPTIONAL, + starttime[5] KerberosTime OPTIONAL, + endtime[6] KerberosTime OPTIONAL, + renew-till[7] KerberosTime OPTIONAL, + srealm[8] Realm OPTIONAL, + sname[9] PrincipalName OPTIONAL, + caddr[10] HostAddresses OPTIONAL +} + +EncKrbCredPart ::= [APPLICATION 29] SEQUENCE { + ticket-info[0] SEQUENCE OF KrbCredInfo, + nonce[1] Krb5Int32 OPTIONAL, + timestamp[2] KerberosTime OPTIONAL, + usec[3] Krb5Int32 OPTIONAL, + s-address[4] HostAddress OPTIONAL, + r-address[5] HostAddress OPTIONAL +} + +KRB-ERROR ::= [APPLICATION 30] SEQUENCE { + pvno[0] Krb5Int32, + msg-type[1] MESSAGE-TYPE, + ctime[2] KerberosTime OPTIONAL, + cusec[3] Krb5Int32 OPTIONAL, + stime[4] KerberosTime, + susec[5] Krb5Int32, + error-code[6] Krb5Int32, + crealm[7] Realm OPTIONAL, + cname[8] PrincipalName OPTIONAL, + realm[9] Realm, -- Correct realm + sname[10] PrincipalName, -- Correct name + e-text[11] GeneralString OPTIONAL, + e-data[12] OCTET STRING OPTIONAL +} + +ChangePasswdDataMS ::= SEQUENCE { + newpasswd[0] OCTET STRING, + targname[1] PrincipalName OPTIONAL, + targrealm[2] Realm OPTIONAL +} + +EtypeList ::= SEQUENCE OF ENCTYPE + -- the client's proposed enctype list in + -- decreasing preference order, favorite choice first + +krb5-pvno Krb5Int32 ::= 5 -- current Kerberos protocol version number + +-- transited encodings + +domain-X500-Compress Krb5Int32 ::= 1 + +-- authorization data primitives + +AD-IF-RELEVANT ::= AuthorizationData + +AD-KDCIssued ::= SEQUENCE { + ad-checksum[0] Checksum, + i-realm[1] Realm OPTIONAL, + i-sname[2] PrincipalName OPTIONAL, + elements[3] AuthorizationData +} + +AD-AND-OR ::= SEQUENCE { + condition-count[0] Krb5Int32, + elements[1] AuthorizationData +} + +AD-MANDATORY-FOR-KDC ::= AuthorizationData + +-- PA-SAM-RESPONSE-2/PA-SAM-RESPONSE-2 + +PA-SAM-TYPE ::= INTEGER { + PA_SAM_TYPE_ENIGMA(1), -- Enigma Logic + PA_SAM_TYPE_DIGI_PATH(2), -- Digital Pathways + PA_SAM_TYPE_SKEY_K0(3), -- S/key where KDC has key 0 + PA_SAM_TYPE_SKEY(4), -- Traditional S/Key + PA_SAM_TYPE_SECURID(5), -- Security Dynamics + PA_SAM_TYPE_CRYPTOCARD(6) -- CRYPTOCard +} + +PA-SAM-REDIRECT ::= HostAddresses + +SAMFlags ::= BIT STRING { + use-sad-as-key(0), + send-encrypted-sad(1), + must-pk-encrypt-sad(2) +} + +PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE { + sam-type[0] Krb5Int32, + sam-flags[1] SAMFlags, + sam-type-name[2] GeneralString OPTIONAL, + sam-track-id[3] GeneralString OPTIONAL, + sam-challenge-label[4] GeneralString OPTIONAL, + sam-challenge[5] GeneralString OPTIONAL, + sam-response-prompt[6] GeneralString OPTIONAL, + sam-pk-for-sad[7] EncryptionKey OPTIONAL, + sam-nonce[8] Krb5Int32, + sam-etype[9] Krb5Int32, + ... +} + +PA-SAM-CHALLENGE-2 ::= SEQUENCE { + sam-body[0] PA-SAM-CHALLENGE-2-BODY, + sam-cksum[1] SEQUENCE OF Checksum, -- (1..MAX) + ... +} + +PA-SAM-RESPONSE-2 ::= SEQUENCE { + sam-type[0] Krb5Int32, + sam-flags[1] SAMFlags, + sam-track-id[2] GeneralString OPTIONAL, + sam-enc-nonce-or-sad[3] EncryptedData, -- PA-ENC-SAM-RESPONSE-ENC + sam-nonce[4] Krb5Int32, + ... +} + +PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE { + sam-nonce[0] Krb5Int32, + sam-sad[1] GeneralString OPTIONAL, + ... +} + +PA-S4U2Self ::= SEQUENCE { + name[0] PrincipalName, + realm[1] Realm, + cksum[2] Checksum, + auth[3] GeneralString +} + +PA-S4U-X509-USER::= SEQUENCE { + user-id[0] S4UUserID, + checksum[1] Checksum +} + +S4UUserID ::= SEQUENCE { + nonce [0] Krb5UInt32, -- the nonce in KDC-REQ-BODY + cname [1] PrincipalName OPTIONAL, -- Certificate mapping hints + crealm [2] Realm, + subject-certificate [3] OCTET STRING OPTIONAL, + options [4] BIT STRING OPTIONAL, + ... +} + +AD-LoginAlias ::= SEQUENCE { -- ad-type number TBD -- + login-alias [0] PrincipalName, + checksum [1] Checksum +} + +-- old ms referral +PA-SvrReferralData ::= SEQUENCE { + referred-name [1] PrincipalName OPTIONAL, + referred-realm [0] Realm +} + +PA-SERVER-REFERRAL-DATA ::= EncryptedData + +PA-ServerReferralData ::= SEQUENCE { + referred-realm [0] Realm OPTIONAL, + true-principal-name [1] PrincipalName OPTIONAL, + requested-principal-name [2] PrincipalName OPTIONAL, + referral-valid-until [3] KerberosTime OPTIONAL, + ... +} + +FastOptions ::= BIT STRING { + reserved(0), + hide-client-names(1), + critical2(2), + critical3(3), + critical4(4), + critical5(5), + critical6(6), + critical7(7), + critical8(8), + critical9(9), + critical10(10), + critical11(11), + critical12(12), + critical13(13), + critical14(14), + critical15(15), + kdc-follow-referrals(16) +} + +KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + padata [1] METHOD-DATA, + req-body [2] KDC-REQ-BODY, + ... +} + +KrbFastArmor ::= SEQUENCE { + armor-type [0] Krb5Int32, + armor-value [1] OCTET STRING, + ... +} + +KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + req-checksum [1] Checksum, + enc-fast-req [2] EncryptedData -- KrbFastReq -- +} + +PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... +} + +KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Krb5Int32, + crealm [2] Realm, + cname [3] PrincipalName, + ticket-checksum [4] Checksum, + ... +} + +KrbFastResponse ::= SEQUENCE { + padata [0] METHOD-DATA, + strengthen-key [1] EncryptionKey OPTIONAL, + finished [2] KrbFastFinished OPTIONAL, + nonce [3] Krb5UInt32, + ... +} + +KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + ... +} + +PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... +} + +KDCFastFlags ::= BIT STRING { + use-reply-key(0), + reply-key-used(1), + reply-key-replaced(2), + kdc-verified(3), + requested-hidden-names(4) +} + +-- KDCFastState is stored in FX_COOKIE +KDCFastState ::= SEQUENCE { + flags [0] KDCFastFlags, + expiration [1] GeneralizedTime, + fast-state [2] METHOD-DATA, + expected-pa-types [3] SEQUENCE OF PADATA-TYPE OPTIONAL +} + +KDCFastCookie ::= SEQUENCE { + version [0] UTF8String, + cookie [1] EncryptedData +} + +KDC-PROXY-MESSAGE ::= SEQUENCE { + kerb-message [0] OCTET STRING, + target-domain [1] Realm OPTIONAL, + dclocator-hint [2] INTEGER OPTIONAL +} + +-- these messages are used in the GSSCred communication and is not part of Kerberos propper + +KERB-TIMES ::= SEQUENCE { + authtime [0] KerberosTime, + starttime [1] KerberosTime, + endtime [2] KerberosTime, + renew_till [3] KerberosTime +} + +KERB-CRED ::= SEQUENCE { + client [0] Principal, + server [1] Principal, + keyblock [2] EncryptionKey, + times [3] KERB-TIMES, + ticket [4] OCTET STRING, + authdata [5] OCTET STRING, + addresses [6] HostAddresses, + flags [7] TicketFlags +} + +KERB-TGS-REQ-IN ::= SEQUENCE { + cache [0] OCTET STRING SIZE (16), + addrs [1] HostAddresses, + flags [2] Krb5UInt32, + imp [3] Principal OPTIONAL, + ticket [4] OCTET STRING OPTIONAL, + in_cred [5] KERB-CRED, + krbtgt [6] KERB-CRED, + padata [7] METHOD-DATA +} + +KERB-TGS-REQ-OUT ::= SEQUENCE { + subkey [0] EncryptionKey OPTIONAL, + t [1] TGS-REQ +} + + + +KERB-TGS-REP-IN ::= SEQUENCE { + cache [0] OCTET STRING SIZE (16), + subkey [1] EncryptionKey OPTIONAL, + in_cred [2] KERB-CRED, + t [3] TGS-REP +} + +KERB-TGS-REP-OUT ::= SEQUENCE { + cache [0] OCTET STRING SIZE (16), + cred [1] KERB-CRED, + subkey [2] EncryptionKey +} + +KERB-ARMOR-SERVICE-REPLY ::= SEQUENCE { + armor [0] KrbFastArmor, + armor-key [1] EncryptionKey +} + +END + +-- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1 diff --git a/third_party/heimdal/lib/asn1/krb5.opt b/third_party/heimdal/lib/asn1/krb5.opt new file mode 100644 index 0000000..a8bd85c --- /dev/null +++ b/third_party/heimdal/lib/asn1/krb5.opt @@ -0,0 +1,9 @@ +--encode-rfc1510-bit-string +--sequence=Principals +--sequence=AuthorizationData +--sequence=METHOD-DATA +--sequence=ETYPE-INFO +--sequence=ETYPE-INFO2 +--preserve-binary=KDC-REQ-BODY +--decorate=PrincipalNameAttrs:void *:pac +--decorate=Principal:PrincipalNameAttrs:nameattrs? diff --git a/third_party/heimdal/lib/asn1/kx509.asn1 b/third_party/heimdal/lib/asn1/kx509.asn1 new file mode 100644 index 0000000..af8a4d6 --- /dev/null +++ b/third_party/heimdal/lib/asn1/kx509.asn1 @@ -0,0 +1,204 @@ +-- $Id$ + +-- Version 2 of the kx509 protocol is documented in RFC6717. +-- +-- Our version here has extensions without changing the version number on the +-- wire. + +KX509 DEFINITIONS ::= BEGIN +IMPORTS Extensions FROM rfc2459 + KerberosTime FROM krb5; + +KX509-ERROR-CODE ::= INTEGER { + KX509-STATUS-GOOD(0), + KX509-STATUS-CLIENT-BAD(1), + KX509-STATUS-CLIENT-FIX(2), + KX509-STATUS-CLIENT-TEMP(3), + KX509-STATUS-SERVER-BAD(4), + KX509-STATUS-SERVER-TEMP(5), + -- 6 is used internally in the umich client, avoid that + KX509-STATUS-SERVER-KEY(7), + -- CSR use negotiation: + KX509-STATUS-CLIENT-USE-CSR(8) + -- Let us reserve 1000+ for Kebreros protocol wire error codes -Nico +} + +-- Originally kx509 requests carried only a public key. We'd like to have +-- proof of possession, and the ability to carry additional options, both, in +-- cleartext and otherwise. +-- +-- We'll use a CSR for proof of posession and desired certificate extensions. +-- +-- We'll also provide a non-CSR-based method of conveying desired certificate +-- extensions. The reason for this is simply that we may want to have a [e.g., +-- RESTful HTTP] proxy for the kx509 service, and we want clients to be able to +-- be as simple as possible -cargo-culted even- with support for attributes +-- (desired certificate extensions) as parameters outside the CSR that the +-- proxy can encode without having the private key for the CSR (naturally). +-- +-- I.e., ultimately we'll have a REST endpoint, /kx509, say, with query +-- parameters like: +-- +-- - csr=<base64-encoding-of-DER-encoded-CSR> +-- - eku=<OID> +-- - ku=<key-usage-flag-name> +-- - rfc822Name=<URL-escaped-email-address> +-- - xMPPName=<URL-escaped-jabber-address> +-- - dNSName=<URL-escaped-FQDN> +-- - dNSSrv=<URL-escaped-_service.FQDN> +-- - registeredID=<OID> +-- - principalName=<URL-escaped-RFC1964-format-Kerberos-Principal-Name> +-- +-- with exactly one CSR and zero, one, or more of the other parameters. +-- +-- We'll even have a way to convey a bearer token from the REST proxy so that +-- we may have a way to get PKIX credentials using bearer tokens. And then, +-- using PKINIT, we may have a way to get Kerberos credentials using bearer +-- tokens. +-- +-- To do this we define a Kx509CSRPlus that we can use in the `pk-key' field of +-- Kx509Request (see below): +Kx509CSRPlus ::= [APPLICATION 35] SEQUENCE { + -- PKCS#10, DER-encoded CSR, with or without meaningful attributes + csr OCTET STRING, + -- Desired certificate Extensions such as KeyUsage, ExtKeyUsage, or + -- subjectAlternativeName (SAN) + exts Extensions OPTIONAL, + -- Desired certificate lifetime + req-life KerberosTime OPTIONAL, + ... +} + +-- Version 2 +Kx509Request ::= SEQUENCE { + authenticator OCTET STRING, + pk-hash OCTET STRING, -- HMAC(ticket_session_key, pk-key) + pk-key OCTET STRING -- one of: + -- - the public key, DER-encoded (RSA, basically) + -- - a Kx509CSRPlus +} + +-- Kx509ErrorCode is a Heimdal-specific enhancement with no change on the wire, +-- and really only just so the error-code field below can fit on one line. +Kx509ErrorCode ::= INTEGER (-2147483648..2147483647) + +Kx509Response ::= SEQUENCE { + error-code[0] Kx509ErrorCode DEFAULT 0, + hash[1] OCTET STRING OPTIONAL, -- HMAC(session_key, ...) + certificate[2] OCTET STRING OPTIONAL, -- DER-encoded Certificate + -- if client sent raw RSA SPK + -- or DER-encoded Certificates + -- (i.e., SEQ. OF Certificate) + -- if client used a + -- Kx509CSRPlus + e-text[3] VisibleString OPTIONAL +} + +-- Offset for Kerberos protocol errors when error-code set to one: +kx509-krb5-error-base INTEGER ::= 1000 + +-- RFC6717 says this about error codes: +-- +-- +------------+-----------------------------+------------------------+ +-- | error-code | Condition | Example | +-- +------------+-----------------------------+------------------------+ +-- | 1 | Permanent problem with | Incompatible version | +-- | | client request | | +-- | 2 | Solvable problem with | Expired Kerberos | +-- | | client request | credentials | +-- | 3 | Temporary problem with | Packet loss | +-- | | client request | | +-- | 4 | Permanent problem with the | Internal | +-- | | server | misconfiguration | +-- | 5 | Temporary problem with the | Server overloaded | +-- | | server | | +-- +------------+-----------------------------+------------------------+ +-- +-- Looking at UMich CITI's kca (server-side of kx509) implementation, it always +-- sends 0 as the status code, and the UMich CITI kx509 client never checks it. +-- All of these error codes are local only in the UMich CITI implementation. +-- +-- Meanwhile, Heimdal used to never send error responses at all. +-- +-- As a result we can use whatever error codes we want. We'll send Kerberos +-- protocol errors + 1000. And we'll never use RFC6717 error codes at all. +-- +-- Looking at umich source... +-- +-- #define KX509_STATUS_GOOD 0 /* No problems handling client request */ +-- #define KX509_STATUS_CLNT_BAD 1 /* Client-side permanent problem */ +-- /* ex. version incompatible */ +-- #define KX509_STATUS_CLNT_FIX 2 /* Client-side solvable problem */ +-- /* ex. re-authenticate */ +-- #define KX509_STATUS_CLNT_TMP 3 /* Client-side temporary problem */ +-- /* ex. packet loss */ +-- #define KX509_STATUS_SRVR_BAD 4 /* Server-side permanent problem */ +-- /* ex. server broken */ +-- #define KX509_STATUS_SRVR_TMP 5 /* Server-side temporary problem */ +-- /* ex. server overloaded */ +-- #define KX509_STATUS_SRVR_CANT_CLNT_VERS 6 /* Server-side doesn't handle */ +-- /* existence of client_version */ +-- /* field in KX509_REQUEST */ +-- +-- The umich server uses these errors in these situations: +-- +-- - KX509_STATUS_SRVR_TMP is for: +-- - request decode errors +-- - krb5_is_ap_req() errors +-- - wrong Kerberos protocol vno in AP-REQ +-- - some ENOMEMs +-- - UDP read errors (??) +-- - LDAP issues (they use LDAP to map realm-chopped user princ names to +-- full names) +-- - pk decode errors +-- - KX509_STATUS_CLNT_TMP is for: +-- - HMAC mismatch +-- - some ENOMEMs +-- - failure to accept AP-REQ +-- - failure to unparse princ names from AP-REQ's Ticket +-- - KX509_STATUS_SRVR_BAD is for: +-- - configuration issues (missing issuer creds) +-- - serial number transaction issues (we should randomize) +-- - subjectName construction issues +-- - certificate construction issues (ENOMEM, say) +-- - failure to authenticate (never happens, since KX509_STATUS_CLNT_TMP is +-- used earlier when krb5_rd_req() fails) +-- - KX509_STATUS_CLNT_FIX is for: +-- - more than one component client principals +-- - client princ name component zero string length shorter than 3 or +-- longer than 8 (WTF) +-- - other policy issues +-- - KX509_STATUS_CLNT_BAD +-- - wrong protocol version number (version_2_0) + +-- Possible new version designs: +-- +-- - keep the protocol the same but use a CSR instead of a raw RSA public key +-- - on the server try decoding first a CSR, then a raw RSA public key +-- +-- - keep the protocol the same but use either a CSR or a self-signed cert +-- - on the server try decoding first a Certificate, then a CSR, then a raw +-- RSA public key +-- +-- CSRs are a pain to deal with. Self-signed certificates can act as a +-- CSR of a sort. Use notBefore == 1970-01-01T00:00:00Z and an EKU +-- denoting "this certificate is really a much-easier-to-work-with CSR +-- alternative". +-- +-- - keep the protocol similar, but use the checksum field of the +-- Authenticator to authenticate the request data; use a KRB-PRIV for the +-- reply +-- +-- - extend the KDC/AS/TGS protocols to support certificate issuance, either +-- at the same time as ticket acquisition, or as an alternative +-- - send a CSR as a authz-data element +-- - expect an EncryptedData with the issued Certificate inside as the +-- Ticket in the result (again, ugly hack) +-- - or maybe just add new messages, but, the thing is that the existing +-- "AP-REP + stuff" kx509 protocol is a fine design pattern, there's no +-- need to radically change it, just slightly. +-- +-- The main benefit of using an extension to the KDC/AS/TGS protocols is that +-- we could then use FAST for confidentiality protection. + +END diff --git a/third_party/heimdal/lib/asn1/lex.h b/third_party/heimdal/lib/asn1/lex.h new file mode 100644 index 0000000..1ee5341 --- /dev/null +++ b/third_party/heimdal/lib/asn1/lex.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#include <roken.h> + +void lex_error_message (const char *, ...) +__attribute__ ((format (printf, 1, 2))); +extern int error_flag; + +int yylex(void); diff --git a/third_party/heimdal/lib/asn1/lex.l b/third_party/heimdal/lib/asn1/lex.l new file mode 100644 index 0000000..4554a94 --- /dev/null +++ b/third_party/heimdal/lib/asn1/lex.l @@ -0,0 +1,310 @@ +%{ +/* + * Copyright (c) 1997 - 2017 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#undef ECHO +#include "symbol.h" +#include "asn1parse.h" +#include "lex.h" +#include "gen_locl.h" + +static unsigned lineno = 1; + +#undef ECHO + +static void unterminated(const char *, unsigned); + +%} + +/* This is for broken old lexes (solaris 10 and hpux) */ +%e 2000 +%p 5000 +%a 5000 +%n 1000 +%o 10000 + +%% +ABSENT { return kw_ABSENT; } +ABSTRACT-SYNTAX { return kw_ABSTRACT_SYNTAX; } +ALL { return kw_ALL; } +APPLICATION { return kw_APPLICATION; } +AUTOMATIC { return kw_AUTOMATIC; } +BEGIN { return kw_BEGIN; } +BIT { return kw_BIT; } +BMPString { return kw_BMPString; } +BOOLEAN { return kw_BOOLEAN; } +BY { return kw_BY; } +CHARACTER { return kw_CHARACTER; } +CHOICE { return kw_CHOICE; } +CLASS { return kw_CLASS; } +COMPONENT { return kw_COMPONENT; } +COMPONENTS { return kw_COMPONENTS; } +CONSTRAINED { return kw_CONSTRAINED; } +CONTAINING { return kw_CONTAINING; } +DEFAULT { return kw_DEFAULT; } +DEFINITIONS { return kw_DEFINITIONS; } +EMBEDDED { return kw_EMBEDDED; } +ENCODED { return kw_ENCODED; } +END { return kw_END; } +ENUMERATED { return kw_ENUMERATED; } +EXCEPT { return kw_EXCEPT; } +EXPLICIT { return kw_EXPLICIT; } +EXPORTS { return kw_EXPORTS; } +EXTENSIBILITY { return kw_EXTENSIBILITY; } +EXTERNAL { return kw_EXTERNAL; } +FALSE { return kw_FALSE; } +FROM { return kw_FROM; } +GeneralString { return kw_GeneralString; } +GeneralizedTime { return kw_GeneralizedTime; } +GraphicString { return kw_GraphicString; } +IA5String { return kw_IA5String; } +IDENTIFIER { return kw_IDENTIFIER; } +IMPLICIT { return kw_IMPLICIT; } +IMPLIED { return kw_IMPLIED; } +IMPORTS { return kw_IMPORTS; } +INCLUDES { return kw_INCLUDES; } +INSTANCE { return kw_INSTANCE; } +INTEGER { return kw_INTEGER; } +INTERSECTION { return kw_INTERSECTION; } +ISO646String { return kw_ISO646String; } +MAX { return kw_MAX; } +MIN { return kw_MIN; } +MINUS-INFINITY { return kw_MINUS_INFINITY; } +NULL { return kw_NULL; } +NumericString { return kw_NumericString; } +OBJECT { return kw_OBJECT; } +OCTET { return kw_OCTET; } +OF { return kw_OF; } +OPTIONAL { return kw_OPTIONAL; } +ObjectDescriptor { return kw_ObjectDescriptor; } +PATTERN { return kw_PATTERN; } +PDV { return kw_PDV; } +PLUS-INFINITY { return kw_PLUS_INFINITY; } +PRESENT { return kw_PRESENT; } +PRIVATE { return kw_PRIVATE; } +PrintableString { return kw_PrintableString; } +REAL { return kw_REAL; } +RELATIVE_OID { return kw_RELATIVE_OID; } +SEQUENCE { return kw_SEQUENCE; } +SET { return kw_SET; } +SIZE { return kw_SIZE; } +STRING { return kw_STRING; } +SYNTAX { return kw_SYNTAX; } +T61String { return kw_T61String; } +TAGS { return kw_TAGS; } +TRUE { return kw_TRUE; } +TYPE-IDENTIFIER { return kw_TYPE_IDENTIFIER; } +TeletexString { return kw_TeletexString; } +UNION { return kw_UNION; } +UNIQUE { return kw_UNIQUE; } +UNIVERSAL { return kw_UNIVERSAL; } +UTCTime { return kw_UTCTime; } +UTF8String { return kw_UTF8String; } +UniversalString { return kw_UniversalString; } +VideotexString { return kw_VideotexString; } +VisibleString { return kw_VisibleString; } +WITH { return kw_WITH; } +[-,;{}()|] { return *yytext; } +"[" { return *yytext; } +"]" { return *yytext; } +"&" { return *yytext; } +"." { return *yytext; } +":" { return *yytext; } +"@" { return *yytext; } +::= { return EEQUAL; } +-- { + int c, start_lineno = lineno; + int f = 0; + while((c = input()) != EOF) { + if(f && c == '-') + break; + if(c == '-') { + f = 1; + continue; + } + if(c == '\n') { + lineno++; + break; + } + f = 0; + } + if(c == EOF) + unterminated("comment", start_lineno); + } +\/\* { + int c, start_lineno = lineno; + int level = 1; + int seen_star = 0; + int seen_slash = 0; + while((c = input()) != EOF) { + if(c == '/') { + if(seen_star) { + if(--level == 0) + break; + seen_star = 0; + continue; + } + seen_slash = 1; + continue; + } + if(seen_star && c == '/') { + if(--level == 0) + break; + seen_star = 0; + continue; + } + if(c == '*') { + if(seen_slash) { + level++; + seen_star = seen_slash = 0; + continue; + } + seen_star = 1; + continue; + } + seen_star = seen_slash = 0; + if(c == '\n') { + lineno++; + continue; + } + } + if(c == EOF) + unterminated("comment", start_lineno); + } +"\"" { + int start_lineno = lineno; + int c; + char buf[1024]; + char *p = buf; + int f = 0; + int skip_ws = 0; + + while((c = input()) != EOF) { + if(isspace(c) && skip_ws) { + if(c == '\n') + lineno++; + continue; + } + skip_ws = 0; + + if(c == '"') { + if(f) { + *p++ = '"'; + f = 0; + } else + f = 1; + continue; + } + if(f == 1) { + unput(c); + break; + } + if(c == '\n') { + lineno++; + while(p > buf && isspace((unsigned char)p[-1])) + p--; + skip_ws = 1; + continue; + } + *p++ = c; + } + if(c == EOF) + unterminated("string", start_lineno); + *p++ = '\0'; + yylval.name = estrdup(buf); + return STRING; + } + +-?0x[0-9A-Fa-f]+|-?[0-9]+ { char *e, *y = yytext; + yylval.constant = strtoll((const char *)yytext, + &e, 0); + if(e == y) + lex_error_message("malformed constant (%s)", yytext); + else + return NUMBER; + } +[_][-A-Z0-9]* { + yylval.name = estrdup ((const char *)yytext); + return CLASS_IDENTIFIER; + } +[A-Z][-A-Za-z0-9_]* { + yylval.name = estrdup ((const char *)yytext); + return TYPE_IDENTIFIER; + } +[a-z][-A-Za-z0-9_]* { + yylval.name = estrdup ((const char *)yytext); + return VALUE_IDENTIFIER; + } +[ \t] ; +\n { ++lineno; } +\.\.\. { return ELLIPSIS; } +\.\. { return RANGE; } +. { lex_error_message("Ignoring char(%c)\n", *yytext); } +%% + +int +yywrap () +{ + return 1; +} + +void +lex_error_message (const char *format, ...) +{ + va_list args; + + va_start (args, format); + fprintf (stderr, "%s:%d: ", get_filename(), lineno); + vfprintf (stderr, format, args); + va_end (args); + error_flag++; +} + +static void +unterminated(const char *type, unsigned start_lineno) +{ + lex_error_message("unterminated %s, possibly started on line %d\n", type, start_lineno); +} diff --git a/third_party/heimdal/lib/asn1/libasn1-exports.def b/third_party/heimdal/lib/asn1/libasn1-exports.def new file mode 100644 index 0000000..76a568f --- /dev/null +++ b/third_party/heimdal/lib/asn1/libasn1-exports.def @@ -0,0 +1,2655 @@ +EXPORTS + _asn1_decode_top + _asn1_encode + _asn1_length + _asn1_free_top + _asn1_copy_top + _asn1_bmember_isset_bit + _asn1_bmember_put_bit + _asn1_copy + _asn1_copy_top + _asn1_decode + _asn1_decode_top + _asn1_encode + _asn1_free + _asn1_free_top + _asn1_length + _asn1_print_top + _asn1_sizeofType + add_AttributeValues + add_AuthorizationData + add_CertificatePolicies + add_Certificates + add_CRLDistributionPoints + add_DigestAlgorithmIdentifiers + add_ETYPE_INFO + add_ETYPE_INFO2 + add_Extensions + add_GeneralNames + add_METHOD_DATA + add_PolicyMappings + add_PolicyQualifierInfos + add_Principals + add_RDNSequence + APOptions2int + asn1_APOptions_units + asn1_DigestTypes_units + asn1_DistributionPointReasonFlags_units + asn1_FastOptions_units + asn1_KDCFastFlags_units + asn1_KDCOptions_units + asn1_KeyUsage_units + asn1_oid_id_aa_communityIdentifiers DATA + asn1_oid_id_aa_decryptKeyID DATA + asn1_oid_id_aa_firmwarePackageID DATA + asn1_oid_id_aa_firmwarePackageInfo DATA + asn1_oid_id_aa_implCompressAlgs DATA + asn1_oid_id_aa_implCryptoAlgs DATA + asn1_oid_id_aa_targetHardwareIDs DATA + asn1_oid_id_aa_wrappedFirmwareKey DATA + asn1_oid_id_aes_128_cbc DATA + asn1_oid_id_aes_192_cbc DATA + asn1_oid_id_aes_256_cbc DATA + asn1_oid_id_apple_system_id DATA + asn1_oid_id_at_commonName DATA + asn1_oid_id_at_countryName DATA + asn1_oid_id_at_description DATA + asn1_oid_id_at_dnQualifier DATA + asn1_oid_id_at_emailAddress DATA + asn1_oid_id_at_generationQualifier DATA + asn1_oid_id_at_givenName DATA + asn1_oid_id_at_initials DATA + asn1_oid_id_at_localityName DATA + asn1_oid_id_at_name DATA + asn1_oid_id_at_organizationalUnitName DATA + asn1_oid_id_at_organizationName DATA + asn1_oid_id_at_pseudonym DATA + asn1_oid_id_at_serialNumber DATA + asn1_oid_id_at_stateOrProvinceName DATA + asn1_oid_id_at_streetAddress DATA + asn1_oid_id_at_surname DATA + asn1_oid_id_at_title DATA + asn1_oid_id_ct_firmwareLoadError DATA + asn1_oid_id_ct_firmwareLoadReceipt DATA + asn1_oid_id_ct_firmwarePackage DATA + asn1_oid_id_dhpublicnumber DATA + asn1_oid_id_domainComponent DATA + asn1_oid_id_dsa DATA + asn1_oid_id_dsa_with_sha1 DATA + asn1_oid_id_ecDH DATA + asn1_oid_id_ecdsa_with_SHA1 DATA + asn1_oid_id_ecdsa_with_SHA224 DATA + asn1_oid_id_ecdsa_with_SHA256 DATA + asn1_oid_id_ecdsa_with_SHA384 DATA + asn1_oid_id_ecdsa_with_SHA512 DATA + asn1_oid_id_ec_group_secp160r1 DATA + asn1_oid_id_ec_group_secp160r2 DATA + asn1_oid_id_ec_group_secp224r1 DATA + asn1_oid_id_ec_group_secp256r1 DATA + asn1_oid_id_ec_group_secp384r1 DATA + asn1_oid_id_ec_group_secp521r1 DATA + asn1_oid_id_ecMQV DATA + asn1_oid_id_ecPublicKey DATA + asn1_oid_id_heim_rsa_pkcs1_x509 DATA + asn1_oid_id_ms_cert_enroll_domaincontroller DATA + asn1_oid_id_msft DATA + asn1_oid_id_msft_kp_msCodeCom DATA + asn1_oid_id_msft_kp_msCodeInd DATA + asn1_oid_id_msft_kp_msCTLSign DATA + asn1_oid_id_msft_kp_msEFS DATA + asn1_oid_id_msft_kp_msSGC DATA + asn1_oid_id_msft_kp_msSmartcardLogin DATA + asn1_oid_id_msft_kp_msUPN DATA + asn1_oid_id_netscape_cert_comment DATA + asn1_oid_id_netscape DATA + asn1_oid_id_nist_aes_algs DATA + asn1_oid_id_nistAlgorithm DATA + asn1_oid_id_nist_sha_algs DATA + asn1_oid_id_on_hardwareModuleName DATA + asn1_oid_id_pbeWithSHAAnd128BitRC2_CBC DATA + asn1_oid_id_pbeWithSHAAnd128BitRC4 DATA + asn1_oid_id_pbeWithSHAAnd2_KeyTripleDES_CBC DATA + asn1_oid_id_pbeWithSHAAnd3_KeyTripleDES_CBC DATA + asn1_oid_id_pbewithSHAAnd40BitRC2_CBC DATA + asn1_oid_id_pbeWithSHAAnd40BitRC4 DATA + asn1_oid_id_pkauthdata DATA + asn1_oid_id_pkcs12_bagtypes DATA + asn1_oid_id_pkcs12_certBag DATA + asn1_oid_id_pkcs12_crlBag DATA + asn1_oid_id_pkcs_12 DATA + asn1_oid_id_pkcs12_keyBag DATA + asn1_oid_id_pkcs_12PbeIds DATA + asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag DATA + asn1_oid_id_pkcs12_safeContentsBag DATA + asn1_oid_id_pkcs12_secretBag DATA + asn1_oid_id_pkcs_1 DATA + asn1_oid_id_pkcs1_md2WithRSAEncryption DATA + asn1_oid_id_pkcs1_md5WithRSAEncryption DATA + asn1_oid_id_pkcs1_rsaEncryption DATA + asn1_oid_id_pkcs1_sha1WithRSAEncryption DATA + asn1_oid_id_pkcs1_sha256WithRSAEncryption DATA + asn1_oid_id_pkcs1_sha384WithRSAEncryption DATA + asn1_oid_id_pkcs1_sha512WithRSAEncryption DATA + asn1_oid_id_pkcs_2 DATA + asn1_oid_id_pkcs2_md2 DATA + asn1_oid_id_pkcs2_md4 DATA + asn1_oid_id_pkcs2_md5 DATA + asn1_oid_id_pkcs_3 DATA + asn1_oid_id_pkcs3_des_ede3_cbc DATA + asn1_oid_id_pkcs3_rc2_cbc DATA + asn1_oid_id_pkcs3_rc4 DATA + asn1_oid_id_pkcs7 DATA + asn1_oid_id_pkcs7_data DATA + asn1_oid_id_pkcs7_digestedData DATA + asn1_oid_id_pkcs7_encryptedData DATA + asn1_oid_id_pkcs7_envelopedData DATA + asn1_oid_id_pkcs7_signedAndEnvelopedData DATA + asn1_oid_id_pkcs7_signedData DATA + asn1_oid_id_pkcs_9_at_certTypes DATA + asn1_oid_id_pkcs_9_at_certTypes_x509 DATA + asn1_oid_id_pkcs_9_at_friendlyName DATA + asn1_oid_id_pkcs_9_at_localKeyId DATA + asn1_oid_id_pkcs9_contentType DATA + asn1_oid_id_pkcs9_countersignature DATA + asn1_oid_id_pkcs_9 DATA + asn1_oid_id_pkcs9_emailAddress DATA + asn1_oid_id_pkcs9_extReq DATA + asn1_oid_id_pkcs9_messageDigest DATA + asn1_oid_id_pkcs9_signingTime DATA + asn1_oid_id_pkdhkeydata DATA + asn1_oid_id_pkekuoid DATA + asn1_oid_id_pkinit DATA + asn1_oid_id_pkinit_kdf_ah_sha1 DATA + asn1_oid_id_pkinit_kdf_ah_sha256 DATA + asn1_oid_id_pkinit_kdf_ah_sha512 DATA + asn1_oid_id_pkinit_kdf DATA + asn1_oid_id_pkinit_ms_eku DATA + asn1_oid_id_pkinit_ms_san DATA + asn1_oid_id_pkinit_san DATA + asn1_oid_id_pkix_ad_caIssuers DATA + asn1_oid_id_pkix_ad_caRepository DATA + asn1_oid_id_pkix_ad DATA + asn1_oid_id_pkix_ad_ocsp DATA + asn1_oid_id_pkix_ad_timeStamping DATA + asn1_oid_id_pkix DATA + asn1_oid_id_pkix_kp_bgpsec_router DATA + asn1_oid_id_pkix_kp_capwapAC DATA + asn1_oid_id_pkix_kp_capwapWTP DATA + asn1_oid_id_pkix_kp_clientAuth DATA + asn1_oid_id_pkix_kp_cmcArchive DATA + asn1_oid_id_pkix_kp_cmcCA DATA + asn1_oid_id_pkix_kp_cmcRA DATA + asn1_oid_id_pkix_kp_codeSigning DATA + asn1_oid_id_pkix_kp DATA + asn1_oid_id_pkix_kp_DVCS DATA + asn1_oid_id_pkix_kp_emailProtection DATA + asn1_oid_id_pkix_kp_ipsecEndSystem DATA + asn1_oid_id_pkix_kp_ipsecIKE DATA + asn1_oid_id_pkix_kp_ipsecTunnel DATA + asn1_oid_id_pkix_kp_ipsecUser DATA + asn1_oid_id_pkix_kp_OCSPSigning DATA + asn1_oid_id_pkix_kp_secureShellClient DATA + asn1_oid_id_pkix_kp_secureShellServer DATA + asn1_oid_id_pkix_kp_sendOwner DATA + asn1_oid_id_pkix_kp_sendProxiedOwner DATA + asn1_oid_id_pkix_kp_sendProxiedRouter DATA + asn1_oid_id_pkix_kp_sendRouter DATA + asn1_oid_id_pkix_kp_serverAuth DATA + asn1_oid_id_pkix_kp_sipDomain DATA + asn1_oid_id_pkix_kp_timeStamping DATA + asn1_oid_id_pkix_ocsp_basic DATA + asn1_oid_id_pkix_ocsp DATA + asn1_oid_id_pkix_ocsp_nonce DATA + asn1_oid_id_pkix_on DATA + asn1_oid_id_pkix_on_dnsSRV DATA + asn1_oid_id_pkix_on_hardwareModuleName DATA + asn1_oid_id_pkix_on_permanentIdentifier DATA + asn1_oid_id_pkix_on_pkinit_ms_san DATA + asn1_oid_id_pkix_on_pkinit_san DATA + asn1_oid_id_pkix_on_xmppAddr DATA + asn1_oid_id_pkix_pe_authorityInfoAccess DATA + asn1_oid_id_pkix_pe DATA + asn1_oid_id_pkix_pe_proxyCertInfo DATA + asn1_oid_id_pkix_pe_subjectInfoAccess DATA + asn1_oid_id_pkix_ppl_anyLanguage DATA + asn1_oid_id_pkix_ppl DATA + asn1_oid_id_pkix_ppl_independent DATA + asn1_oid_id_pkix_ppl_inheritAll DATA + asn1_oid_id_pkix_qt_cps DATA + asn1_oid_id_pkix_qt DATA + asn1_oid_id_pkix_qt_unotice DATA + asn1_oid_id_pkkdcekuoid DATA + asn1_oid_id_pkrkeydata DATA + asn1_oid_id_rsa_digestAlgorithm DATA + asn1_oid_id_rsa_digest_md2 DATA + asn1_oid_id_rsa_digest_md4 DATA + asn1_oid_id_rsa_digest_md5 DATA + asn1_oid_id_rsadsi_des_ede3_cbc DATA + asn1_oid_id_rsadsi_encalg DATA + asn1_oid_id_rsadsi_rc2_cbc DATA + asn1_oid_id_secsig_sha_1 DATA + asn1_oid_id_secsig_sha_1WithRSAEncryption DATA + asn1_oid_id_sha224 DATA + asn1_oid_id_sha256 DATA + asn1_oid_id_sha384 DATA + asn1_oid_id_sha512 DATA + asn1_oid_id_Userid DATA + asn1_oid_id_uspkicommon_card_id DATA + asn1_oid_id_uspkicommon_piv_interim DATA + asn1_oid_id_x509_ce_anyExtendedKeyUsage DATA + asn1_oid_id_x509_ce_authorityKeyIdentifier DATA + asn1_oid_id_x509_ce_basicConstraints DATA + asn1_oid_id_x509_ce_certificateIssuer DATA + asn1_oid_id_x509_ce_certificatePolicies_anyPolicy DATA + asn1_oid_id_x509_ce_certificatePolicies DATA + asn1_oid_id_x509_ce_cRLDistributionPoints DATA + asn1_oid_id_x509_ce_cRLNumber DATA + asn1_oid_id_x509_ce_cRLReason DATA + asn1_oid_id_x509_ce_cRLReasons DATA + asn1_oid_id_x509_ce DATA + asn1_oid_id_x509_ce_deltaCRLIndicator DATA + asn1_oid_id_x509_ce_extKeyUsage DATA + asn1_oid_id_x509_ce_freshestCRL DATA + asn1_oid_id_x509_ce_holdInstructionCode DATA + asn1_oid_id_x509_ce_inhibitAnyPolicy DATA + asn1_oid_id_x509_ce_invalidityDate DATA + asn1_oid_id_x509_ce_issuerAltName DATA + asn1_oid_id_x509_ce_issuingDistributionPoint DATA + asn1_oid_id_x509_ce_keyUsage DATA + asn1_oid_id_x509_ce_nameConstraints DATA + asn1_oid_id_x509_ce_policyConstraints DATA + asn1_oid_id_x509_ce_policyMappings DATA + asn1_oid_id_x509_ce_privateKeyUsagePeriod DATA + asn1_oid_id_x509_ce_subjectAltName DATA + asn1_oid_id_x509_ce_subjectDirectoryAttributes DATA + asn1_oid_id_x509_ce_subjectKeyIdentifier DATA + asn1_oid_id_x520_at DATA + asn1_oid_id_x9_57 DATA + asn1_oid_tcg_at_tpmManufacturer DATA + asn1_oid_tcg_at_tpmModel DATA + asn1_oid_tcg_at_tpmSecurityAssertions DATA + asn1_oid_tcg_at_tpmSpecification DATA + asn1_oid_tcg_at_tpmVersion DATA + asn1_oid_tcg_attribute DATA + asn1_oid_tcg_cap_verifiedTPMFixed DATA + asn1_oid_tcg_cap_verifiedTPMResidency DATA + asn1_oid_tcg_cap_verifiedTPMRestricted DATA + asn1_oid_tcg DATA + asn1_oid_tcg_kp DATA + asn1_oid_tcg_kp_EKCertificate DATA + asn1_oid_tcg_on_ekPermIdSha256 DATA + asn1_oid_tcg_tpm20 DATA + asn1_SAMFlags_units + asn1_TicketFlags_units + copy_AccessDescription + copy_AD_AND_OR + copy_AD_IF_RELEVANT + copy_AD_INITIAL_VERIFIED_CAS + copy_AD_KDCIssued + copy_AD_LoginAlias + copy_AD_MANDATORY_FOR_KDC + copy_AlgorithmIdentifier + copy_AliasIA5String + copy_AliasPrintableString + copy_AliasUTF8String + copy_APOptions + copy_AP_REP + copy_AP_REQ + copy_AS_REP + copy_AS_REQ + copy_Attribute + copy_AttributeSet + copy_AttributeType + copy_AttributeTypeAndValue + copy_AttributeValue + copy_AttributeValues + copy_AUTHDATA_TYPE + copy_Authenticator + copy_AuthorityInfoAccessSyntax + copy_AuthorityKeyIdentifier + copy_AuthorizationData + copy_AuthorizationDataElement + copy_AuthPack + copy_AuthPack_Win2k + copy_BaseDistance + copy_BasicConstraints + copy_Certificate + copy_CertificateList + copy_CertificatePolicies + copy_CertificateRevocationLists + copy_Certificates + copy_CertificateSerialNumber + copy_CertificateSet + copy_CertificationRequest + copy_CertificationRequestInfo + copy_CertPolicyId + copy_ChangePasswdDataMS + copy_Checksum + copy_CKSUMTYPE + copy_CMSAttributes + copy_CMSCBCParameter + copy_CMSEncryptedData + copy_CMSIdentifier + copy_CMSRC2CBCParameter + copy_CMSVersion + copy_CommonCriteriaMeasures + copy_CommunityIdentifier + copy_CommunityIdentifiers + copy_CompositePrincipal + copy_ContentEncryptionAlgorithmIdentifier + copy_ContentInfo + copy_ContentType + copy_CPSuri + copy_CRIAttributeSet + copy_CRIExtensions + copy_CRLCertificateList + copy_CRLDistributionPoints + copy_CRLReason + copy_CurrentFWConfig + copy_DecryptKeyIdentifier + copy_DHNonce + copy_DHParameter + copy_DHPublicKey + copy_DHRepInfo + copy_DigestAlgorithmIdentifier + copy_DigestAlgorithmIdentifiers + copy_DigestError + copy_DigestInfo + copy_DigestInit + copy_DigestInitReply + copy_DigestREP + copy_DigestRepInner + copy_DigestREQ + copy_DigestReqInner + copy_DigestRequest + copy_DigestResponse + copy_DigestTypes + copy_DirectoryString + copy_DisplayText + copy_DistributionPoint + copy_DistributionPointName + copy_DistributionPointReasonFlags + copy_DomainParameters + copy_DSAParams + copy_DSAPublicKey + copy_DSASigValue + copy_ECDSA_Sig_Value + copy_ECParameters + copy_ECPoint + copy_EKCertificateGenerationLocation + copy_EKGenerationLocation + copy_EKGenerationType + copy_EncAPRepPart + copy_EncapsulatedContentInfo + copy_EncASRepPart + copy_EncKDCRepPart + copy_EncKrbCredPart + copy_EncKrbPrivPart + copy_EncryptedContent + copy_EncryptedContentInfo + copy_EncryptedData + copy_EncryptedKey + copy_EncryptionKey + copy_EncTGSRepPart + copy_EncTicketPart + copy_ENCTYPE + copy_EnvelopedData + copy_ETYPE_INFO + copy_ETYPE_INFO2 + copy_ETYPE_INFO2_ENTRY + copy_ETYPE_INFO_ENTRY + copy_EtypeList + copy_EvaluationAssuranceLevel + copy_EvaluationStatus + copy_Extension + copy_Extensions + copy_ExternalPrincipalIdentifier + copy_ExternalPrincipalIdentifiers + copy_ExtKeyUsage + copy_FastOptions + copy_FIPSLevel + copy_FirmwarePackageIdentifier + copy_FirmwarePackageInfo + copy_FirmwarePackageLoadError + copy_FirmwarePackageLoadErrorCode + copy_FirmwarePackageLoadReceipt + copy_FirmwarePkgData + copy_FWErrorVersion + copy_FWReceiptVersion + copy_GeneralName + copy_GeneralNames + copy_GeneralSubtree + copy_GeneralSubtrees + copy_HardwareModuleName + copy_HardwareModules + copy_HardwareSerialEntry + copy_heim_any + copy_HEIM_ANY + copy_heim_any_set + copy_HEIM_ANY_SET + copy_HostAddress + copy_HostAddresses + copy_ImplementedCompressAlgorithms + copy_ImplementedCryptoAlgorithms + copy_IOSCertificationRequest + copy_IOSCertificationRequestInfo + copy_IssuerAndSerialNumber + copy_KDCDHKeyInfo + copy_KDCDHKeyInfo_Win2k + copy_KDCFastCookie + copy_KDCFastFlags + copy_KDCFastState + copy_KDCOptions + copy_KDC_PROXY_MESSAGE + copy_KDC_REP + copy_KDC_REQ + copy_KDC_REQ_BODY + copy_KDFAlgorithmId + copy_KERB_AD_RESTRICTION_ENTRY + copy_KERB_ARMOR_SERVICE_REPLY + copy_KERB_CRED + copy_KerberosString + copy_KerberosTime + copy_KERB_ERROR_DATA + copy_KERB_TGS_REP_IN + copy_KERB_TGS_REP_OUT + copy_KERB_TGS_REQ_IN + copy_KERB_TGS_REQ_OUT + copy_KERB_TIMES + copy_KeyEncryptionAlgorithmIdentifier + copy_KeyIdentifier + copy_KeyTransRecipientInfo + copy_KeyUsage + copy_Krb5Int32 + copy_KRB5PrincipalName + copy_Krb5UInt32 + copy_KRB_CRED + copy_KrbCredInfo + copy_KRB_ERROR + copy_KrbFastArmor + copy_KrbFastArmoredRep + copy_KrbFastArmoredReq + copy_KrbFastFinished + copy_KrbFastReq + copy_KrbFastResponse + copy_KRB_PRIV + copy_KRB_SAFE + copy_KRB_SAFE_BODY + copy_Kx509CSRPlus + copy_Kx509ErrorCode + copy_KX509_ERROR_CODE + copy_Kx509Request + copy_Kx509Response + copy_LastReq + copy_LR_TYPE + copy_MessageDigest + copy_MESSAGE_TYPE + copy_METHOD_DATA + copy_MS_UPN_SAN + copy_Name + copy_NameConstraints + copy_NAME_TYPE + copy_NoticeReference + copy_NTLMInit + copy_NTLMInitReply + copy_NTLMReply + copy_NTLMRequest + copy_NTLMRequest2 + copy_NTLMResponse + copy_OCSPBasicOCSPResponse + copy_OCSPCertID + copy_OCSPCertStatus + copy_OCSPInnerRequest + copy_OCSPKeyHash + copy_OCSPRequest + copy_OCSPResponderID + copy_OCSPResponse + copy_OCSPResponseBytes + copy_OCSPResponseData + copy_OCSPResponseStatus + copy_OCSPSignature + copy_OCSPSingleResponse + copy_OCSPTBSRequest + copy_OCSPVersion + copy_OriginatorInfo + copy_OtherName + copy_PA_DATA + copy_PADATA_TYPE + copy_PA_ENC_SAM_RESPONSE_ENC + copy_PA_ENC_TS_ENC + copy_PA_FX_FAST_REPLY + copy_PA_FX_FAST_REQUEST + copy_PA_KERB_KEY_LIST_REP + copy_PA_KERB_KEY_LIST_REQ + copy_PA_PAC_OPTIONS + copy_PA_PAC_REQUEST + copy_PA_PK_AS_REP + copy_PA_PK_AS_REP_BTMM + copy_PA_PK_AS_REP_Win2k + copy_PA_PK_AS_REQ + copy_PA_PK_AS_REQ_Win2k + copy_PA_S4U_X509_USER + copy_PA_S4U2Self + copy_PA_SAM_CHALLENGE_2 + copy_PA_SAM_CHALLENGE_2_BODY + copy_PA_SAM_REDIRECT + copy_PA_SAM_RESPONSE_2 + copy_PA_SAM_TYPE + copy_PA_ServerReferralData + copy_PA_SERVER_REFERRAL_DATA + copy_PA_SvrReferralData + copy_PermanentIdentifier + copy_PKAuthenticator + copy_PKAuthenticator_Win2k + copy_PKCS12_Attribute + copy_PKCS12_Attributes + copy_PKCS12_AuthenticatedSafe + copy_PKCS12_CertBag + copy_PKCS12_MacData + copy_PKCS12_OctetString + copy_PKCS12_PBEParams + copy_PKCS12_PFX + copy_PKCS12_SafeBag + copy_PKCS12_SafeContents + copy_PKCS8Attributes + copy_PKCS8EncryptedData + copy_PKCS8EncryptedPrivateKeyInfo + copy_PKCS8PrivateKey + copy_PKCS8PrivateKeyAlgorithmIdentifier + copy_PKCS8PrivateKeyInfo + copy_PKCS9_BMPString + copy_PKCS9_friendlyName + copy_PkinitSP80056AOtherInfo + copy_PkinitSuppPubInfo + copy_PKIXXmppAddr + copy_PolicyConstraints + copy_PolicyInformation + copy_PolicyMapping + copy_PolicyMappings + copy_PolicyQualifierId + copy_PolicyQualifierInfo + copy_PolicyQualifierInfos + copy_PreferredOrLegacyPackageIdentifier + copy_PreferredOrLegacyStalePackageIdentifier + copy_PreferredPackageIdentifier + copy_Principal + copy_PrincipalName + copy_Principals + copy_PrivateKeyUsagePeriod + copy_PROV_SRV_LOCATION + copy_ProxyCertInfo + copy_ProxyPolicy + copy_RDNSequence + copy_Realm + copy_RecipientIdentifier + copy_RecipientInfo + copy_RecipientInfos + copy_RelativeDistinguishedName + copy_ReplyKeyPack + copy_ReplyKeyPack_Win2k + copy_RSAPrivateKey + copy_RSAPublicKey + copy_SAMFlags + copy_SecurityLevel + copy_SignatureAlgorithmIdentifier + copy_SignatureValue + copy_SignedData + copy_SignerIdentifier + copy_SignerInfo + copy_SignerInfos + copy_SingleAttribute + copy_SkipCerts + copy_SRVName + copy_StrengthOfFunction + copy_SubjectDirectoryAttributes + copy_SubjectInfoAccessSyntax + copy_SubjectKeyIdentifier + copy_SubjectPublicKeyInfo + copy_TargetHardwareIdentifiers + copy_TBSCertificate + copy_TBSCRLCertList + copy_TD_DH_PARAMETERS + copy_TD_INVALID_CERTIFICATES + copy_TD_TRUSTED_CERTIFIERS + copy_TGS_REP + copy_TGS_REQ + copy_Ticket + copy_TicketFlags + copy_Time + copy_TPMSecurityAssertions + copy_TPMSpecification + copy_TPMVersion + copy_TransitedEncoding + copy_TrustedCA + copy_TrustedCA_Win2k + copy_TypedData + copy_TYPED_DATA + copy_UniqueIdentifier + copy_UnprotectedAttributes + copy_URIReference + copy_UserNotice + copy_ValidationParms + copy_Validity + copy_VendorLoadErrorCode + copy_Version + copy_WrappedFirmwareKey + copy_X520CommonName + copy_X520LocalityName + copy_X520name + copy_X520OrganizationalUnitName + copy_X520OrganizationName + copy_X520StateOrProvinceName + copy_X690SampleChildInformation + copy_X690SampleDate + copy_X690SampleEmployeeNumber + copy_X690SampleName + copy_X690SamplePersonnelRecord + decode_AccessDescription + decode_AD_AND_OR + decode_AD_IF_RELEVANT + decode_AD_INITIAL_VERIFIED_CAS + decode_AD_KDCIssued + decode_AD_LoginAlias + decode_AD_MANDATORY_FOR_KDC + decode_AlgorithmIdentifier + decode_AliasIA5String + decode_AliasPrintableString + decode_AliasUTF8String + decode_APOptions + decode_AP_REP + decode_AP_REQ + decode_AS_REP + decode_AS_REQ + decode_Attribute + decode_AttributeSet + decode_AttributeType + decode_AttributeTypeAndValue + decode_AttributeValue + decode_AttributeValues + decode_AUTHDATA_TYPE + decode_Authenticator + decode_AuthorityInfoAccessSyntax + decode_AuthorityKeyIdentifier + decode_AuthorizationData + decode_AuthorizationDataElement + decode_AuthPack + decode_AuthPack_Win2k + decode_BaseDistance + decode_BasicConstraints + decode_Certificate + decode_CertificateList + decode_CertificatePolicies + decode_CertificateRevocationLists + decode_Certificates + decode_CertificateSerialNumber + decode_CertificateSet + decode_CertificationRequest + decode_CertificationRequestInfo + decode_CertPolicyId + decode_ChangePasswdDataMS + decode_Checksum + decode_CKSUMTYPE + decode_CMSAttributes + decode_CMSCBCParameter + decode_CMSEncryptedData + decode_CMSIdentifier + decode_CMSRC2CBCParameter + decode_CMSVersion + decode_CommonCriteriaMeasures + decode_CommunityIdentifier + decode_CommunityIdentifiers + decode_CompositePrincipal + decode_ContentEncryptionAlgorithmIdentifier + decode_ContentInfo + decode_ContentType + decode_CPSuri + decode_CRIAttributeSet + decode_CRIExtensions + decode_CRIExtensions + decode_CRLCertificateList + decode_CRLDistributionPoints + decode_CRLReason + decode_CurrentFWConfig + decode_DecryptKeyIdentifier + decode_DHNonce + decode_DHParameter + decode_DHPublicKey + decode_DHRepInfo + decode_DigestAlgorithmIdentifier + decode_DigestAlgorithmIdentifiers + decode_DigestError + decode_DigestInfo + decode_DigestInit + decode_DigestInitReply + decode_DigestREP + decode_DigestRepInner + decode_DigestREQ + decode_DigestReqInner + decode_DigestRequest + decode_DigestResponse + decode_DigestTypes + decode_DirectoryString + decode_DisplayText + decode_DistributionPoint + decode_DistributionPointName + decode_DistributionPointReasonFlags + decode_DomainParameters + decode_DSAParams + decode_DSAPublicKey + decode_DSASigValue + decode_ECDSA_Sig_Value + decode_ECParameters + decode_ECPoint + decode_EKCertificateGenerationLocation + decode_EKGenerationLocation + decode_EKGenerationType + decode_EncAPRepPart + decode_EncapsulatedContentInfo + decode_EncASRepPart + decode_EncKDCRepPart + decode_EncKrbCredPart + decode_EncKrbPrivPart + decode_EncryptedContent + decode_EncryptedContentInfo + decode_EncryptedData + decode_EncryptedKey + decode_EncryptionKey + decode_EncTGSRepPart + decode_EncTicketPart + decode_ENCTYPE + decode_EnvelopedData + decode_ETYPE_INFO + decode_ETYPE_INFO2 + decode_ETYPE_INFO2_ENTRY + decode_ETYPE_INFO_ENTRY + decode_EtypeList + decode_EvaluationAssuranceLevel + decode_EvaluationStatus + decode_Extension + decode_Extensions + decode_ExternalPrincipalIdentifier + decode_ExternalPrincipalIdentifiers + decode_ExtKeyUsage + decode_FastOptions + decode_FIPSLevel + decode_FirmwarePackageIdentifier + decode_FirmwarePackageInfo + decode_FirmwarePackageLoadError + decode_FirmwarePackageLoadErrorCode + decode_FirmwarePackageLoadReceipt + decode_FirmwarePkgData + decode_FWErrorVersion + decode_FWReceiptVersion + decode_GeneralName + decode_GeneralNames + decode_GeneralSubtree + decode_GeneralSubtrees + decode_HardwareModuleName + decode_HardwareModules + decode_HardwareSerialEntry + decode_heim_any + decode_HEIM_ANY + decode_heim_any_set + decode_HEIM_ANY_SET + decode_HostAddress + decode_HostAddresses + decode_ImplementedCompressAlgorithms + decode_ImplementedCryptoAlgorithms + decode_IOSCertificationRequest + decode_IOSCertificationRequest + decode_IOSCertificationRequestInfo + decode_IOSCertificationRequestInfo + decode_IssuerAndSerialNumber + decode_KDCDHKeyInfo + decode_KDCDHKeyInfo_Win2k + decode_KDCFastCookie + decode_KDCFastFlags + decode_KDCFastState + decode_KDCOptions + decode_KDC_PROXY_MESSAGE + decode_KDC_REP + decode_KDC_REQ + decode_KDC_REQ_BODY + decode_KDFAlgorithmId + decode_KERB_AD_RESTRICTION_ENTRY + decode_KERB_ARMOR_SERVICE_REPLY + decode_KERB_CRED + decode_KerberosString + decode_KerberosTime + decode_KERB_ERROR_DATA + decode_KERB_TGS_REP_IN + decode_KERB_TGS_REP_OUT + decode_KERB_TGS_REQ_IN + decode_KERB_TGS_REQ_OUT + decode_KERB_TIMES + decode_KeyEncryptionAlgorithmIdentifier + decode_KeyIdentifier + decode_KeyTransRecipientInfo + decode_KeyUsage + decode_Krb5Int32 + decode_KRB5PrincipalName + decode_Krb5UInt32 + decode_KRB_CRED + decode_KrbCredInfo + decode_KRB_ERROR + decode_KrbFastArmor + decode_KrbFastArmoredRep + decode_KrbFastArmoredReq + decode_KrbFastFinished + decode_KrbFastReq + decode_KrbFastResponse + decode_KRB_PRIV + decode_KRB_SAFE + decode_KRB_SAFE_BODY + decode_Kx509CSRPlus + decode_Kx509ErrorCode + decode_KX509_ERROR_CODE + decode_Kx509Request + decode_Kx509Response + decode_LastReq + decode_LR_TYPE + decode_MessageDigest + decode_MESSAGE_TYPE + decode_METHOD_DATA + decode_MS_UPN_SAN + decode_Name + decode_NameConstraints + decode_NAME_TYPE + decode_NoticeReference + decode_NTLMInit + decode_NTLMInitReply + decode_NTLMReply + decode_NTLMRequest + decode_NTLMRequest2 + decode_NTLMResponse + decode_OCSPBasicOCSPResponse + decode_OCSPCertID + decode_OCSPCertStatus + decode_OCSPInnerRequest + decode_OCSPKeyHash + decode_OCSPRequest + decode_OCSPResponderID + decode_OCSPResponse + decode_OCSPResponseBytes + decode_OCSPResponseData + decode_OCSPResponseStatus + decode_OCSPSignature + decode_OCSPSingleResponse + decode_OCSPTBSRequest + decode_OCSPVersion + decode_OriginatorInfo + decode_OtherName + decode_PA_DATA + decode_PADATA_TYPE + decode_PA_ENC_SAM_RESPONSE_ENC + decode_PA_ENC_TS_ENC + decode_PA_FX_FAST_REPLY + decode_PA_FX_FAST_REQUEST + decode_PA_KERB_KEY_LIST_REP + decode_PA_KERB_KEY_LIST_REQ + decode_PA_PAC_OPTIONS + decode_PA_PAC_REQUEST + decode_PA_PK_AS_REP + decode_PA_PK_AS_REP_BTMM + decode_PA_PK_AS_REP_Win2k + decode_PA_PK_AS_REQ + decode_PA_PK_AS_REQ_Win2k + decode_PA_S4U_X509_USER + decode_PA_S4U2Self + decode_PA_SAM_CHALLENGE_2 + decode_PA_SAM_CHALLENGE_2_BODY + decode_PA_SAM_REDIRECT + decode_PA_SAM_RESPONSE_2 + decode_PA_SAM_TYPE + decode_PA_ServerReferralData + decode_PA_SERVER_REFERRAL_DATA + decode_PA_SvrReferralData + decode_PermanentIdentifier + decode_PKAuthenticator + decode_PKAuthenticator_Win2k + decode_PKCS12_Attribute + decode_PKCS12_Attributes + decode_PKCS12_AuthenticatedSafe + decode_PKCS12_CertBag + decode_PKCS12_MacData + decode_PKCS12_OctetString + decode_PKCS12_PBEParams + decode_PKCS12_PFX + decode_PKCS12_SafeBag + decode_PKCS12_SafeContents + decode_PKCS8Attributes + decode_PKCS8EncryptedData + decode_PKCS8EncryptedPrivateKeyInfo + decode_PKCS8PrivateKey + decode_PKCS8PrivateKeyAlgorithmIdentifier + decode_PKCS8PrivateKeyInfo + decode_PKCS9_BMPString + decode_PKCS9_friendlyName + decode_PkinitSP80056AOtherInfo + decode_PkinitSuppPubInfo + decode_PKIXXmppAddr + decode_PolicyConstraints + decode_PolicyInformation + decode_PolicyMapping + decode_PolicyMappings + decode_PolicyQualifierId + decode_PolicyQualifierInfo + decode_PolicyQualifierInfos + decode_PreferredOrLegacyPackageIdentifier + decode_PreferredOrLegacyStalePackageIdentifier + decode_PreferredPackageIdentifier + decode_Principal + decode_PrincipalName + decode_Principals + decode_PrivateKeyUsagePeriod + decode_PROV_SRV_LOCATION + decode_ProxyCertInfo + decode_ProxyPolicy + decode_RDNSequence + decode_Realm + decode_RecipientIdentifier + decode_RecipientInfo + decode_RecipientInfos + decode_RelativeDistinguishedName + decode_ReplyKeyPack + decode_ReplyKeyPack_Win2k + decode_RSAPrivateKey + decode_RSAPublicKey + decode_SAMFlags + decode_SecurityLevel + decode_SignatureAlgorithmIdentifier + decode_SignatureValue + decode_SignedData + decode_SignerIdentifier + decode_SignerInfo + decode_SignerInfos + decode_SingleAttribute + decode_SkipCerts + decode_SRVName + decode_StrengthOfFunction + decode_SubjectDirectoryAttributes + decode_SubjectInfoAccessSyntax + decode_SubjectKeyIdentifier + decode_SubjectPublicKeyInfo + decode_TargetHardwareIdentifiers + decode_TBSCertificate + decode_TBSCRLCertList + decode_TD_DH_PARAMETERS + decode_TD_INVALID_CERTIFICATES + decode_TD_TRUSTED_CERTIFIERS + decode_TGS_REP + decode_TGS_REQ + decode_Ticket + decode_TicketFlags + decode_Time + decode_TPMSecurityAssertions + decode_TPMSpecification + decode_TPMVersion + decode_TransitedEncoding + decode_TrustedCA + decode_TrustedCA_Win2k + decode_TypedData + decode_TYPED_DATA + decode_UniqueIdentifier + decode_UnprotectedAttributes + decode_URIReference + decode_UserNotice + decode_ValidationParms + decode_Validity + decode_VendorLoadErrorCode + decode_Version + decode_WrappedFirmwareKey + decode_X520CommonName + decode_X520LocalityName + decode_X520name + decode_X520OrganizationalUnitName + decode_X520OrganizationName + decode_X520StateOrProvinceName + decode_X690SampleChildInformation + decode_X690SampleDate + decode_X690SampleEmployeeNumber + decode_X690SampleName + decode_X690SamplePersonnelRecord + der_copy_bit_string + der_copy_bmp_string + der_copy_generalized_time + der_copy_general_string + der_copy_heim_integer + der_copy_ia5_string + der_copy_integer + der_copy_integer64 + der_copy_octet_string + der_copy_oid + der_copy_printable_string + der_copy_universal_string + der_copy_unsigned + der_copy_unsigned64 + der_copy_utctime + der_copy_utf8string + der_copy_visible_string + der_find_heim_oid_by_name + der_find_heim_oid_by_oid + der_find_or_parse_heim_oid + der_free_bit_string + der_free_bmp_string + der_free_generalized_time + der_free_general_string + der_free_heim_integer + der_free_ia5_string + der_free_integer + der_free_integer64 + der_free_octet_string + der_free_oid + der_free_printable_string + der_free_universal_string + der_free_unsigned + der_free_unsigned64 + der_free_utctime + der_free_utf8string + der_free_visible_string + der_get_bit_string + der_get_bmp_string + der_get_boolean + der_get_class_name + der_get_class_num + der_get_generalized_time + der_get_general_string + der_get_heim_integer + der_get_ia5_string + der_get_integer + der_get_integer64 + der_get_length + der_get_octet_string + der_get_octet_string_ber + der_get_oid + der_get_printable_string + der_get_tag + der_get_tag_name + der_get_tag_num + der_get_type_name + der_get_type_num + der_get_universal_string + der_get_unsigned + der_get_unsigned64 + der_get_utctime + der_get_utf8string + der_get_visible_string + _der_gmtime + der_heim_bit_string_cmp + der_heim_bmp_string_cmp + der_heim_integer_cmp + der_heim_octet_string_cmp + der_heim_oid_cmp + der_heim_universal_string_cmp + der_ia5_string_cmp + der_length_bit_string + der_length_bmp_string + der_length_boolean + der_length_enumerated + der_length_generalized_time + der_length_general_string + der_length_heim_integer + der_length_ia5_string + der_length_integer + der_length_integer64 + der_length_len + der_length_octet_string + der_length_oid + der_length_printable_string + der_length_tag + der_length_universal_string + der_length_unsigned + der_length_unsigned64 + der_length_utctime + der_length_utf8string + der_length_visible_string + der_match_heim_oid_by_name + der_match_tag + der_match_tag2 + der_match_tag_and_length + der_parse_heim_oid + der_parse_hex_heim_integer + der_printable_string_cmp + der_print_bit_string + der_print_bmp_string + der_print_boolean + der_print_generalized_time + der_print_general_string + der_print_heim_integer + der_print_heim_oid + der_print_heim_oid_sym + der_print_hex_heim_integer + der_print_ia5_string + der_print_integer + der_print_integer64 + der_print_octet_string + der_print_oid + der_print_printable_string + der_print_universal_string + der_print_unsigned + der_print_unsigned64 + der_print_utctime + der_print_utf8string + der_print_visible_string + der_put_bit_string + der_put_bmp_string + der_put_boolean + der_put_generalized_time + der_put_general_string + der_put_heim_integer + der_put_ia5_string + der_put_integer + der_put_integer64 + der_put_length + der_put_length_and_tag + der_put_octet_string + der_put_oid + der_put_printable_string + der_put_tag + der_put_universal_string + der_put_unsigned + der_put_unsigned64 + der_put_utctime + der_put_utf8string + der_put_visible_string + der_replace_tag + _der_timegm + DigestTypes2int + DistributionPointReasonFlags2int + encode_AccessDescription + encode_AD_AND_OR + encode_AD_IF_RELEVANT + encode_AD_INITIAL_VERIFIED_CAS + encode_AD_KDCIssued + encode_AD_LoginAlias + encode_AD_MANDATORY_FOR_KDC + encode_AlgorithmIdentifier + encode_AliasIA5String + encode_AliasPrintableString + encode_AliasUTF8String + encode_APOptions + encode_AP_REP + encode_AP_REQ + encode_AS_REP + encode_AS_REQ + encode_Attribute + encode_AttributeSet + encode_AttributeType + encode_AttributeTypeAndValue + encode_AttributeValue + encode_AttributeValues + encode_AUTHDATA_TYPE + encode_Authenticator + encode_AuthorityInfoAccessSyntax + encode_AuthorityKeyIdentifier + encode_AuthorizationData + encode_AuthorizationDataElement + encode_AuthPack + encode_AuthPack_Win2k + encode_BaseDistance + encode_BasicConstraints + encode_Certificate + encode_CertificateList + encode_CertificatePolicies + encode_CertificateRevocationLists + encode_Certificates + encode_CertificateSerialNumber + encode_CertificateSet + encode_CertificationRequest + encode_CertificationRequestInfo + encode_CertPolicyId + encode_ChangePasswdDataMS + encode_Checksum + encode_CKSUMTYPE + encode_CMSAttributes + encode_CMSCBCParameter + encode_CMSEncryptedData + encode_CMSIdentifier + encode_CMSRC2CBCParameter + encode_CMSVersion + encode_CommonCriteriaMeasures + encode_CommunityIdentifier + encode_CommunityIdentifiers + encode_CompositePrincipal + encode_ContentEncryptionAlgorithmIdentifier + encode_ContentInfo + encode_ContentType + encode_CPSuri + encode_CRIAttributeSet + encode_CRIExtensions + encode_CRIExtensions + encode_CRLCertificateList + encode_CRLDistributionPoints + encode_CRLReason + encode_CurrentFWConfig + encode_DecryptKeyIdentifier + encode_DHNonce + encode_DHParameter + encode_DHPublicKey + encode_DHRepInfo + encode_DigestAlgorithmIdentifier + encode_DigestAlgorithmIdentifiers + encode_DigestError + encode_DigestInfo + encode_DigestInit + encode_DigestInitReply + encode_DigestREP + encode_DigestRepInner + encode_DigestREQ + encode_DigestReqInner + encode_DigestRequest + encode_DigestResponse + encode_DigestTypes + encode_DirectoryString + encode_DisplayText + encode_DistributionPoint + encode_DistributionPointName + encode_DistributionPointReasonFlags + encode_DomainParameters + encode_DSAParams + encode_DSAPublicKey + encode_DSASigValue + encode_ECDSA_Sig_Value + encode_ECParameters + encode_ECPoint + encode_EKCertificateGenerationLocation + encode_EKGenerationLocation + encode_EKGenerationType + encode_EncAPRepPart + encode_EncapsulatedContentInfo + encode_EncASRepPart + encode_EncKDCRepPart + encode_EncKrbCredPart + encode_EncKrbPrivPart + encode_EncryptedContent + encode_EncryptedContentInfo + encode_EncryptedData + encode_EncryptedKey + encode_EncryptionKey + encode_EncTGSRepPart + encode_EncTicketPart + encode_ENCTYPE + encode_EnvelopedData + encode_ETYPE_INFO + encode_ETYPE_INFO2 + encode_ETYPE_INFO2_ENTRY + encode_ETYPE_INFO_ENTRY + encode_EtypeList + encode_EvaluationAssuranceLevel + encode_EvaluationStatus + encode_Extension + encode_Extensions + encode_ExternalPrincipalIdentifier + encode_ExternalPrincipalIdentifiers + encode_ExtKeyUsage + encode_FastOptions + encode_FIPSLevel + encode_FirmwarePackageIdentifier + encode_FirmwarePackageInfo + encode_FirmwarePackageLoadError + encode_FirmwarePackageLoadErrorCode + encode_FirmwarePackageLoadReceipt + encode_FirmwarePkgData + encode_FWErrorVersion + encode_FWReceiptVersion + encode_GeneralName + encode_GeneralNames + encode_GeneralSubtree + encode_GeneralSubtrees + encode_HardwareModuleName + encode_HardwareModules + encode_HardwareSerialEntry + encode_heim_any + encode_HEIM_ANY + encode_heim_any_set + encode_HEIM_ANY_SET + encode_HostAddress + encode_HostAddresses + encode_ImplementedCompressAlgorithms + encode_ImplementedCryptoAlgorithms + encode_IOSCertificationRequest + encode_IOSCertificationRequest + encode_IOSCertificationRequestInfo + encode_IOSCertificationRequestInfo + encode_IssuerAndSerialNumber + encode_KDCDHKeyInfo + encode_KDCDHKeyInfo_Win2k + encode_KDCFastCookie + encode_KDCFastFlags + encode_KDCFastState + encode_KDCOptions + encode_KDC_PROXY_MESSAGE + encode_KDC_REP + encode_KDC_REQ + encode_KDC_REQ_BODY + encode_KDFAlgorithmId + encode_KERB_AD_RESTRICTION_ENTRY + encode_KERB_ARMOR_SERVICE_REPLY + encode_KERB_CRED + encode_KerberosString + encode_KerberosTime + encode_KERB_ERROR_DATA + encode_KERB_TGS_REP_IN + encode_KERB_TGS_REP_OUT + encode_KERB_TGS_REQ_IN + encode_KERB_TGS_REQ_OUT + encode_KERB_TIMES + encode_KeyEncryptionAlgorithmIdentifier + encode_KeyIdentifier + encode_KeyTransRecipientInfo + encode_KeyUsage + encode_Krb5Int32 + encode_KRB5PrincipalName + encode_Krb5UInt32 + encode_KRB_CRED + encode_KrbCredInfo + encode_KRB_ERROR + encode_KrbFastArmor + encode_KrbFastArmoredRep + encode_KrbFastArmoredReq + encode_KrbFastFinished + encode_KrbFastReq + encode_KrbFastResponse + encode_KRB_PRIV + encode_KRB_SAFE + encode_KRB_SAFE_BODY + encode_Kx509CSRPlus + encode_Kx509ErrorCode + encode_KX509_ERROR_CODE + encode_Kx509Request + encode_Kx509Response + encode_LastReq + encode_LR_TYPE + encode_MessageDigest + encode_MESSAGE_TYPE + encode_METHOD_DATA + encode_MS_UPN_SAN + encode_Name + encode_NameConstraints + encode_NAME_TYPE + encode_NoticeReference + encode_NTLMInit + encode_NTLMInitReply + encode_NTLMReply + encode_NTLMRequest + encode_NTLMRequest2 + encode_NTLMResponse + encode_OCSPBasicOCSPResponse + encode_OCSPCertID + encode_OCSPCertStatus + encode_OCSPInnerRequest + encode_OCSPKeyHash + encode_OCSPRequest + encode_OCSPResponderID + encode_OCSPResponse + encode_OCSPResponseBytes + encode_OCSPResponseData + encode_OCSPResponseStatus + encode_OCSPSignature + encode_OCSPSingleResponse + encode_OCSPTBSRequest + encode_OCSPVersion + encode_OriginatorInfo + encode_OtherName + encode_PA_DATA + encode_PADATA_TYPE + encode_PA_ENC_SAM_RESPONSE_ENC + encode_PA_ENC_TS_ENC + encode_PA_FX_FAST_REPLY + encode_PA_FX_FAST_REQUEST + encode_PA_KERB_KEY_LIST_REP + encode_PA_KERB_KEY_LIST_REQ + encode_PA_PAC_OPTIONS + encode_PA_PAC_REQUEST + encode_PA_PK_AS_REP + encode_PA_PK_AS_REP_BTMM + encode_PA_PK_AS_REP_Win2k + encode_PA_PK_AS_REQ + encode_PA_PK_AS_REQ_Win2k + encode_PA_S4U_X509_USER + encode_PA_S4U2Self + encode_PA_SAM_CHALLENGE_2 + encode_PA_SAM_CHALLENGE_2_BODY + encode_PA_SAM_REDIRECT + encode_PA_SAM_RESPONSE_2 + encode_PA_SAM_TYPE + encode_PA_ServerReferralData + encode_PA_SERVER_REFERRAL_DATA + encode_PA_SvrReferralData + encode_PermanentIdentifier + encode_PKAuthenticator + encode_PKAuthenticator_Win2k + encode_PKCS12_Attribute + encode_PKCS12_Attributes + encode_PKCS12_AuthenticatedSafe + encode_PKCS12_CertBag + encode_PKCS12_MacData + encode_PKCS12_OctetString + encode_PKCS12_PBEParams + encode_PKCS12_PFX + encode_PKCS12_SafeBag + encode_PKCS12_SafeContents + encode_PKCS8Attributes + encode_PKCS8EncryptedData + encode_PKCS8EncryptedPrivateKeyInfo + encode_PKCS8PrivateKey + encode_PKCS8PrivateKeyAlgorithmIdentifier + encode_PKCS8PrivateKeyInfo + encode_PKCS9_BMPString + encode_PKCS9_friendlyName + encode_PkinitSP80056AOtherInfo + encode_PkinitSuppPubInfo + encode_PKIXXmppAddr + encode_PolicyConstraints + encode_PolicyInformation + encode_PolicyMapping + encode_PolicyMappings + encode_PolicyQualifierId + encode_PolicyQualifierInfo + encode_PolicyQualifierInfos + encode_PreferredOrLegacyPackageIdentifier + encode_PreferredOrLegacyStalePackageIdentifier + encode_PreferredPackageIdentifier + encode_Principal + encode_PrincipalName + encode_Principals + encode_PrivateKeyUsagePeriod + encode_PROV_SRV_LOCATION + encode_ProxyCertInfo + encode_ProxyPolicy + encode_RDNSequence + encode_Realm + encode_RecipientIdentifier + encode_RecipientInfo + encode_RecipientInfos + encode_RelativeDistinguishedName + encode_ReplyKeyPack + encode_ReplyKeyPack_Win2k + encode_RSAPrivateKey + encode_RSAPublicKey + encode_SAMFlags + encode_SecurityLevel + encode_SignatureAlgorithmIdentifier + encode_SignatureValue + encode_SignedData + encode_SignerIdentifier + encode_SignerInfo + encode_SignerInfos + encode_SingleAttribute + encode_SkipCerts + encode_SRVName + encode_StrengthOfFunction + encode_SubjectDirectoryAttributes + encode_SubjectInfoAccessSyntax + encode_SubjectKeyIdentifier + encode_SubjectPublicKeyInfo + encode_TargetHardwareIdentifiers + encode_TBSCertificate + encode_TBSCRLCertList + encode_TD_DH_PARAMETERS + encode_TD_INVALID_CERTIFICATES + encode_TD_TRUSTED_CERTIFIERS + encode_TGS_REP + encode_TGS_REQ + encode_Ticket + encode_TicketFlags + encode_Time + encode_TPMSecurityAssertions + encode_TPMSpecification + encode_TPMVersion + encode_TransitedEncoding + encode_TrustedCA + encode_TrustedCA_Win2k + encode_TypedData + encode_TYPED_DATA + encode_UniqueIdentifier + encode_UnprotectedAttributes + encode_URIReference + encode_UserNotice + encode_ValidationParms + encode_Validity + encode_VendorLoadErrorCode + encode_Version + encode_WrappedFirmwareKey + encode_X520CommonName + encode_X520LocalityName + encode_X520name + encode_X520OrganizationalUnitName + encode_X520OrganizationName + encode_X520StateOrProvinceName + encode_X690SampleChildInformation + encode_X690SampleDate + encode_X690SampleEmployeeNumber + encode_X690SampleName + encode_X690SamplePersonnelRecord + FastOptions2int + free_AccessDescription + free_AD_AND_OR + free_AD_IF_RELEVANT + free_AD_INITIAL_VERIFIED_CAS + free_AD_KDCIssued + free_AD_LoginAlias + free_AD_MANDATORY_FOR_KDC + free_AlgorithmIdentifier + free_AliasIA5String + free_AliasPrintableString + free_AliasUTF8String + free_APOptions + free_AP_REP + free_AP_REQ + free_AS_REP + free_AS_REQ + free_Attribute + free_AttributeSet + free_AttributeType + free_AttributeTypeAndValue + free_AttributeValue + free_AttributeValues + free_AUTHDATA_TYPE + free_Authenticator + free_AuthorityInfoAccessSyntax + free_AuthorityKeyIdentifier + free_AuthorizationData + free_AuthorizationDataElement + free_AuthPack + free_AuthPack_Win2k + free_BaseDistance + free_BasicConstraints + free_Certificate + free_CertificateList + free_CertificatePolicies + free_CertificateRevocationLists + free_Certificates + free_CertificateSerialNumber + free_CertificateSet + free_CertificationRequest + free_CertificationRequestInfo + free_CertPolicyId + free_ChangePasswdDataMS + free_Checksum + free_CKSUMTYPE + free_CMSAttributes + free_CMSCBCParameter + free_CMSEncryptedData + free_CMSIdentifier + free_CMSRC2CBCParameter + free_CMSVersion + free_CommonCriteriaMeasures + free_CommunityIdentifier + free_CommunityIdentifiers + free_CompositePrincipal + free_ContentEncryptionAlgorithmIdentifier + free_ContentInfo + free_ContentType + free_CPSuri + free_CRIAttributeSet + free_CRIExtensions + free_CRIExtensions + free_CRLCertificateList + free_CRLDistributionPoints + free_CRLReason + free_CurrentFWConfig + free_DecryptKeyIdentifier + free_DHNonce + free_DHParameter + free_DHPublicKey + free_DHRepInfo + free_DigestAlgorithmIdentifier + free_DigestAlgorithmIdentifiers + free_DigestError + free_DigestInfo + free_DigestInit + free_DigestInitReply + free_DigestREP + free_DigestRepInner + free_DigestREQ + free_DigestReqInner + free_DigestRequest + free_DigestResponse + free_DigestTypes + free_DirectoryString + free_DisplayText + free_DistributionPoint + free_DistributionPointName + free_DistributionPointReasonFlags + free_DomainParameters + free_DSAParams + free_DSAPublicKey + free_DSASigValue + free_ECDSA_Sig_Value + free_ECParameters + free_ECPoint + free_EKCertificateGenerationLocation + free_EKGenerationLocation + free_EKGenerationType + free_EncAPRepPart + free_EncapsulatedContentInfo + free_EncASRepPart + free_EncKDCRepPart + free_EncKrbCredPart + free_EncKrbPrivPart + free_EncryptedContent + free_EncryptedContentInfo + free_EncryptedData + free_EncryptedKey + free_EncryptionKey + free_EncTGSRepPart + free_EncTicketPart + free_ENCTYPE + free_EnvelopedData + free_ETYPE_INFO + free_ETYPE_INFO2 + free_ETYPE_INFO2_ENTRY + free_ETYPE_INFO_ENTRY + free_EtypeList + free_EvaluationAssuranceLevel + free_EvaluationStatus + free_Extension + free_Extensions + free_ExternalPrincipalIdentifier + free_ExternalPrincipalIdentifiers + free_ExtKeyUsage + free_FastOptions + free_FIPSLevel + free_FirmwarePackageIdentifier + free_FirmwarePackageInfo + free_FirmwarePackageLoadError + free_FirmwarePackageLoadErrorCode + free_FirmwarePackageLoadReceipt + free_FirmwarePkgData + free_FWErrorVersion + free_FWReceiptVersion + free_GeneralName + free_GeneralNames + free_GeneralSubtree + free_GeneralSubtrees + free_HardwareModuleName + free_HardwareModules + free_HardwareSerialEntry + free_heim_any + free_HEIM_ANY + free_heim_any_set + free_HEIM_ANY_SET + free_HostAddress + free_HostAddresses + free_ImplementedCompressAlgorithms + free_ImplementedCryptoAlgorithms + free_IOSCertificationRequest + free_IOSCertificationRequest + free_IOSCertificationRequestInfo + free_IOSCertificationRequestInfo + free_IssuerAndSerialNumber + free_KDCDHKeyInfo + free_KDCDHKeyInfo_Win2k + free_KDCFastCookie + free_KDCFastFlags + free_KDCFastState + free_KDCOptions + free_KDC_PROXY_MESSAGE + free_KDC_REP + free_KDC_REQ + free_KDC_REQ_BODY + free_KDFAlgorithmId + free_KERB_AD_RESTRICTION_ENTRY + free_KERB_ARMOR_SERVICE_REPLY + free_KERB_CRED + free_KerberosString + free_KerberosTime + free_KERB_ERROR_DATA + free_KERB_TGS_REP_IN + free_KERB_TGS_REP_OUT + free_KERB_TGS_REQ_IN + free_KERB_TGS_REQ_OUT + free_KERB_TIMES + free_KeyEncryptionAlgorithmIdentifier + free_KeyIdentifier + free_KeyTransRecipientInfo + free_KeyUsage + free_Krb5Int32 + free_KRB5PrincipalName + free_Krb5UInt32 + free_KRB_CRED + free_KrbCredInfo + free_KRB_ERROR + free_KrbFastArmor + free_KrbFastArmoredRep + free_KrbFastArmoredReq + free_KrbFastFinished + free_KrbFastReq + free_KrbFastResponse + free_KRB_PRIV + free_KRB_SAFE + free_KRB_SAFE_BODY + free_Kx509CSRPlus + free_Kx509ErrorCode + free_KX509_ERROR_CODE + free_Kx509Request + free_Kx509Response + free_LastReq + free_LR_TYPE + free_MessageDigest + free_MESSAGE_TYPE + free_METHOD_DATA + free_MS_UPN_SAN + free_Name + free_NameConstraints + free_NAME_TYPE + free_NoticeReference + free_NTLMInit + free_NTLMInitReply + free_NTLMReply + free_NTLMRequest + free_NTLMRequest2 + free_NTLMResponse + free_OCSPBasicOCSPResponse + free_OCSPCertID + free_OCSPCertStatus + free_OCSPInnerRequest + free_OCSPKeyHash + free_OCSPRequest + free_OCSPResponderID + free_OCSPResponse + free_OCSPResponseBytes + free_OCSPResponseData + free_OCSPResponseStatus + free_OCSPSignature + free_OCSPSingleResponse + free_OCSPTBSRequest + free_OCSPVersion + free_OriginatorInfo + free_OtherName + free_PA_DATA + free_PADATA_TYPE + free_PA_ENC_SAM_RESPONSE_ENC + free_PA_ENC_TS_ENC + free_PA_FX_FAST_REPLY + free_PA_FX_FAST_REQUEST + free_PA_KERB_KEY_LIST_REP + free_PA_KERB_KEY_LIST_REQ + free_PA_PAC_OPTIONS + free_PA_PAC_REQUEST + free_PA_PK_AS_REP + free_PA_PK_AS_REP_BTMM + free_PA_PK_AS_REP_Win2k + free_PA_PK_AS_REQ + free_PA_PK_AS_REQ_Win2k + free_PA_S4U_X509_USER + free_PA_S4U2Self + free_PA_SAM_CHALLENGE_2 + free_PA_SAM_CHALLENGE_2_BODY + free_PA_SAM_REDIRECT + free_PA_SAM_RESPONSE_2 + free_PA_SAM_TYPE + free_PA_ServerReferralData + free_PA_SERVER_REFERRAL_DATA + free_PA_SvrReferralData + free_PermanentIdentifier + free_PKAuthenticator + free_PKAuthenticator_Win2k + free_PKCS12_Attribute + free_PKCS12_Attributes + free_PKCS12_AuthenticatedSafe + free_PKCS12_CertBag + free_PKCS12_MacData + free_PKCS12_OctetString + free_PKCS12_PBEParams + free_PKCS12_PFX + free_PKCS12_SafeBag + free_PKCS12_SafeContents + free_PKCS8Attributes + free_PKCS8EncryptedData + free_PKCS8EncryptedPrivateKeyInfo + free_PKCS8PrivateKey + free_PKCS8PrivateKeyAlgorithmIdentifier + free_PKCS8PrivateKeyInfo + free_PKCS9_BMPString + free_PKCS9_friendlyName + free_PkinitSP80056AOtherInfo + free_PkinitSuppPubInfo + free_PKIXXmppAddr + free_PolicyConstraints + free_PolicyInformation + free_PolicyMapping + free_PolicyMappings + free_PolicyQualifierId + free_PolicyQualifierInfo + free_PolicyQualifierInfos + free_PreferredOrLegacyPackageIdentifier + free_PreferredOrLegacyStalePackageIdentifier + free_PreferredPackageIdentifier + free_Principal + free_PrincipalName + free_Principals + free_PrivateKeyUsagePeriod + free_PROV_SRV_LOCATION + free_ProxyCertInfo + free_ProxyPolicy + free_RDNSequence + free_Realm + free_RecipientIdentifier + free_RecipientInfo + free_RecipientInfos + free_RelativeDistinguishedName + free_ReplyKeyPack + free_ReplyKeyPack_Win2k + free_RSAPrivateKey + free_RSAPublicKey + free_SAMFlags + free_SecurityLevel + free_SignatureAlgorithmIdentifier + free_SignatureValue + free_SignedData + free_SignerIdentifier + free_SignerInfo + free_SignerInfos + free_SingleAttribute + free_SkipCerts + free_SRVName + free_StrengthOfFunction + free_SubjectDirectoryAttributes + free_SubjectInfoAccessSyntax + free_SubjectKeyIdentifier + free_SubjectPublicKeyInfo + free_TargetHardwareIdentifiers + free_TBSCertificate + free_TBSCRLCertList + free_TD_DH_PARAMETERS + free_TD_INVALID_CERTIFICATES + free_TD_TRUSTED_CERTIFIERS + free_TGS_REP + free_TGS_REQ + free_Ticket + free_TicketFlags + free_Time + free_TPMSecurityAssertions + free_TPMSpecification + free_TPMVersion + free_TransitedEncoding + free_TrustedCA + free_TrustedCA_Win2k + free_TypedData + free_TYPED_DATA + free_UniqueIdentifier + free_UnprotectedAttributes + free_URIReference + free_UserNotice + free_ValidationParms + free_Validity + free_VendorLoadErrorCode + free_Version + free_WrappedFirmwareKey + free_X520CommonName + free_X520LocalityName + free_X520name + free_X520OrganizationalUnitName + free_X520OrganizationName + free_X520StateOrProvinceName + free_X690SampleChildInformation + free_X690SampleDate + free_X690SampleEmployeeNumber + free_X690SampleName + free_X690SamplePersonnelRecord + heim_any_cmp + HEIM_ANY_cmp + _heim_der_set_sort + _heim_fix_dce + _heim_len_int + _heim_len_int64 + _heim_len_unsigned + _heim_len_unsigned64 + _heim_time2generalizedtime + initialize_asn1_error_table + initialize_asn1_error_table_r + int2APOptions + int2DigestTypes + int2DistributionPointReasonFlags + int2FastOptions + int2KDCFastFlags + int2KDCOptions + int2KeyUsage + int2SAMFlags + int2TicketFlags + KDCFastFlags2int + KDCOptions2int + KeyUsage2int + length_AccessDescription + length_AD_AND_OR + length_AD_IF_RELEVANT + length_AD_INITIAL_VERIFIED_CAS + length_AD_KDCIssued + length_AD_LoginAlias + length_AD_MANDATORY_FOR_KDC + length_AlgorithmIdentifier + length_AliasIA5String + length_AliasPrintableString + length_AliasUTF8String + length_APOptions + length_AP_REP + length_AP_REQ + length_AS_REP + length_AS_REQ + length_Attribute + length_AttributeSet + length_AttributeType + length_AttributeTypeAndValue + length_AttributeValue + length_AttributeValues + length_AUTHDATA_TYPE + length_Authenticator + length_AuthorityInfoAccessSyntax + length_AuthorityKeyIdentifier + length_AuthorizationData + length_AuthorizationDataElement + length_AuthPack + length_AuthPack_Win2k + length_BaseDistance + length_BasicConstraints + length_Certificate + length_CertificateList + length_CertificatePolicies + length_CertificateRevocationLists + length_Certificates + length_CertificateSerialNumber + length_CertificateSet + length_CertificationRequest + length_CertificationRequestInfo + length_CertPolicyId + length_ChangePasswdDataMS + length_Checksum + length_CKSUMTYPE + length_CMSAttributes + length_CMSCBCParameter + length_CMSEncryptedData + length_CMSIdentifier + length_CMSRC2CBCParameter + length_CMSVersion + length_CommonCriteriaMeasures + length_CommunityIdentifier + length_CommunityIdentifiers + length_CompositePrincipal + length_ContentEncryptionAlgorithmIdentifier + length_ContentInfo + length_ContentType + length_CPSuri + length_CRIAttributeSet + length_CRIExtensions + length_CRLCertificateList + length_CRLDistributionPoints + length_CRLReason + length_CurrentFWConfig + length_DecryptKeyIdentifier + length_DHNonce + length_DHParameter + length_DHPublicKey + length_DHRepInfo + length_DigestAlgorithmIdentifier + length_DigestAlgorithmIdentifiers + length_DigestError + length_DigestInfo + length_DigestInit + length_DigestInitReply + length_DigestREP + length_DigestRepInner + length_DigestREQ + length_DigestReqInner + length_DigestRequest + length_DigestResponse + length_DigestTypes + length_DirectoryString + length_DisplayText + length_DistributionPoint + length_DistributionPointName + length_DistributionPointReasonFlags + length_DomainParameters + length_DSAParams + length_DSAPublicKey + length_DSASigValue + length_ECDSA_Sig_Value + length_ECParameters + length_ECPoint + length_EKCertificateGenerationLocation + length_EKGenerationLocation + length_EKGenerationType + length_EncAPRepPart + length_EncapsulatedContentInfo + length_EncASRepPart + length_EncKDCRepPart + length_EncKrbCredPart + length_EncKrbPrivPart + length_EncryptedContent + length_EncryptedContentInfo + length_EncryptedData + length_EncryptedKey + length_EncryptionKey + length_EncTGSRepPart + length_EncTicketPart + length_ENCTYPE + length_EnvelopedData + length_ETYPE_INFO + length_ETYPE_INFO2 + length_ETYPE_INFO2_ENTRY + length_ETYPE_INFO_ENTRY + length_EtypeList + length_EvaluationAssuranceLevel + length_EvaluationStatus + length_Extension + length_Extensions + length_ExternalPrincipalIdentifier + length_ExternalPrincipalIdentifiers + length_ExtKeyUsage + length_FastOptions + length_FIPSLevel + length_FirmwarePackageIdentifier + length_FirmwarePackageInfo + length_FirmwarePackageLoadError + length_FirmwarePackageLoadErrorCode + length_FirmwarePackageLoadReceipt + length_FirmwarePkgData + length_FWErrorVersion + length_FWReceiptVersion + length_GeneralName + length_GeneralNames + length_GeneralSubtree + length_GeneralSubtrees + length_HardwareModuleName + length_HardwareModules + length_HardwareSerialEntry + length_heim_any + length_HEIM_ANY + length_heim_any_set + length_HEIM_ANY_SET + length_HostAddress + length_HostAddresses + length_ImplementedCompressAlgorithms + length_ImplementedCryptoAlgorithms + length_IOSCertificationRequest + length_IOSCertificationRequestInfo + length_IssuerAndSerialNumber + length_KDCDHKeyInfo + length_KDCDHKeyInfo_Win2k + length_KDCFastCookie + length_KDCFastFlags + length_KDCFastState + length_KDCOptions + length_KDC_PROXY_MESSAGE + length_KDC_REP + length_KDC_REQ + length_KDC_REQ_BODY + length_KDFAlgorithmId + length_KERB_AD_RESTRICTION_ENTRY + length_KERB_ARMOR_SERVICE_REPLY + length_KERB_CRED + length_KerberosString + length_KerberosTime + length_KERB_ERROR_DATA + length_KERB_TGS_REP_IN + length_KERB_TGS_REP_OUT + length_KERB_TGS_REQ_IN + length_KERB_TGS_REQ_OUT + length_KERB_TIMES + length_KeyEncryptionAlgorithmIdentifier + length_KeyIdentifier + length_KeyTransRecipientInfo + length_KeyUsage + length_Krb5Int32 + length_KRB5PrincipalName + length_Krb5UInt32 + length_KRB_CRED + length_KrbCredInfo + length_KRB_ERROR + length_KrbFastArmor + length_KrbFastArmoredRep + length_KrbFastArmoredReq + length_KrbFastFinished + length_KrbFastReq + length_KrbFastResponse + length_KRB_PRIV + length_KRB_SAFE + length_KRB_SAFE_BODY + length_Kx509CSRPlus + length_Kx509ErrorCode + length_KX509_ERROR_CODE + length_Kx509Request + length_Kx509Response + length_LastReq + length_LR_TYPE + length_MessageDigest + length_MESSAGE_TYPE + length_METHOD_DATA + length_MS_UPN_SAN + length_Name + length_NameConstraints + length_NAME_TYPE + length_NoticeReference + length_NTLMInit + length_NTLMInitReply + length_NTLMReply + length_NTLMRequest + length_NTLMRequest2 + length_NTLMResponse + length_OCSPBasicOCSPResponse + length_OCSPCertID + length_OCSPCertStatus + length_OCSPInnerRequest + length_OCSPKeyHash + length_OCSPRequest + length_OCSPResponderID + length_OCSPResponse + length_OCSPResponseBytes + length_OCSPResponseData + length_OCSPResponseStatus + length_OCSPSignature + length_OCSPSingleResponse + length_OCSPTBSRequest + length_OCSPVersion + length_OriginatorInfo + length_OtherName + length_PA_DATA + length_PADATA_TYPE + length_PA_ENC_SAM_RESPONSE_ENC + length_PA_ENC_TS_ENC + length_PA_FX_FAST_REPLY + length_PA_FX_FAST_REQUEST + length_PA_KERB_KEY_LIST_REP + length_PA_KERB_KEY_LIST_REQ + length_PA_PAC_OPTIONS + length_PA_PAC_REQUEST + length_PA_PK_AS_REP + length_PA_PK_AS_REP_BTMM + length_PA_PK_AS_REP_Win2k + length_PA_PK_AS_REQ + length_PA_PK_AS_REQ_Win2k + length_PA_S4U_X509_USER + length_PA_S4U2Self + length_PA_SAM_CHALLENGE_2 + length_PA_SAM_CHALLENGE_2_BODY + length_PA_SAM_REDIRECT + length_PA_SAM_RESPONSE_2 + length_PA_SAM_TYPE + length_PA_ServerReferralData + length_PA_SERVER_REFERRAL_DATA + length_PA_SvrReferralData + length_PermanentIdentifier + length_PKAuthenticator + length_PKAuthenticator_Win2k + length_PKCS12_Attribute + length_PKCS12_Attributes + length_PKCS12_AuthenticatedSafe + length_PKCS12_CertBag + length_PKCS12_MacData + length_PKCS12_OctetString + length_PKCS12_PBEParams + length_PKCS12_PFX + length_PKCS12_SafeBag + length_PKCS12_SafeContents + length_PKCS8Attributes + length_PKCS8EncryptedData + length_PKCS8EncryptedPrivateKeyInfo + length_PKCS8PrivateKey + length_PKCS8PrivateKeyAlgorithmIdentifier + length_PKCS8PrivateKeyInfo + length_PKCS9_BMPString + length_PKCS9_friendlyName + length_PkinitSP80056AOtherInfo + length_PkinitSuppPubInfo + length_PKIXXmppAddr + length_PolicyConstraints + length_PolicyInformation + length_PolicyMapping + length_PolicyMappings + length_PolicyQualifierId + length_PolicyQualifierInfo + length_PolicyQualifierInfos + length_PreferredOrLegacyPackageIdentifier + length_PreferredOrLegacyStalePackageIdentifier + length_PreferredPackageIdentifier + length_Principal + length_PrincipalName + length_Principals + length_PrivateKeyUsagePeriod + length_PROV_SRV_LOCATION + length_ProxyCertInfo + length_ProxyPolicy + length_RDNSequence + length_Realm + length_RecipientIdentifier + length_RecipientInfo + length_RecipientInfos + length_RelativeDistinguishedName + length_ReplyKeyPack + length_ReplyKeyPack_Win2k + length_RSAPrivateKey + length_RSAPublicKey + length_SAMFlags + length_SecurityLevel + length_SignatureAlgorithmIdentifier + length_SignatureValue + length_SignedData + length_SignerIdentifier + length_SignerInfo + length_SignerInfos + length_SingleAttribute + length_SkipCerts + length_SRVName + length_StrengthOfFunction + length_SubjectDirectoryAttributes + length_SubjectInfoAccessSyntax + length_SubjectKeyIdentifier + length_SubjectPublicKeyInfo + length_TargetHardwareIdentifiers + length_TBSCertificate + length_TBSCRLCertList + length_TD_DH_PARAMETERS + length_TD_INVALID_CERTIFICATES + length_TD_TRUSTED_CERTIFIERS + length_TGS_REP + length_TGS_REQ + length_Ticket + length_TicketFlags + length_Time + length_TPMSecurityAssertions + length_TPMSpecification + length_TPMVersion + length_TransitedEncoding + length_TrustedCA + length_TrustedCA_Win2k + length_TypedData + length_TYPED_DATA + length_UniqueIdentifier + length_UnprotectedAttributes + length_URIReference + length_UserNotice + length_ValidationParms + length_Validity + length_VendorLoadErrorCode + length_Version + length_WrappedFirmwareKey + length_X520CommonName + length_X520LocalityName + length_X520name + length_X520OrganizationalUnitName + length_X520OrganizationName + length_X520StateOrProvinceName + length_X690SampleChildInformation + length_X690SampleDate + length_X690SampleEmployeeNumber + length_X690SampleName + length_X690SamplePersonnelRecord + print_AccessDescription + print_AD_AND_OR + print_AD_IF_RELEVANT + print_AD_INITIAL_VERIFIED_CAS + print_AD_KDCIssued + print_AD_LoginAlias + print_AD_MANDATORY_FOR_KDC + print_AlgorithmIdentifier + print_AliasIA5String + print_AliasPrintableString + print_AliasUTF8String + print_APOptions + print_AP_REP + print_AP_REQ + print_AS_REP + print_AS_REQ + print_Attribute + print_AttributeSet + print_AttributeType + print_AttributeTypeAndValue + print_AttributeValue + print_AttributeValues + print_AUTHDATA_TYPE + print_Authenticator + print_AuthorityInfoAccessSyntax + print_AuthorityKeyIdentifier + print_AuthorizationData + print_AuthorizationDataElement + print_AuthPack + print_AuthPack_Win2k + print_BaseDistance + print_BasicConstraints + print_Certificate + print_CertificateList + print_CertificatePolicies + print_CertificateRevocationLists + print_Certificates + print_CertificateSerialNumber + print_CertificateSet + print_CertificationRequest + print_CertificationRequestInfo + print_CertPolicyId + print_ChangePasswdDataMS + print_Checksum + print_CKSUMTYPE + print_CMSAttributes + print_CMSCBCParameter + print_CMSEncryptedData + print_CMSIdentifier + print_CMSRC2CBCParameter + print_CMSVersion + print_CommonCriteriaMeasures + print_CommunityIdentifier + print_CommunityIdentifiers + print_CompositePrincipal + print_ContentEncryptionAlgorithmIdentifier + print_ContentInfo + print_ContentType + print_CPSuri + print_CRIAttributeSet + print_CRIExtensions + print_CRIExtensions + print_CRLCertificateList + print_CRLDistributionPoints + print_CRLReason + print_CurrentFWConfig + print_DecryptKeyIdentifier + print_DHNonce + print_DHParameter + print_DHPublicKey + print_DHRepInfo + print_DigestAlgorithmIdentifier + print_DigestAlgorithmIdentifiers + print_DigestError + print_DigestInfo + print_DigestInit + print_DigestInitReply + print_DigestREP + print_DigestRepInner + print_DigestREQ + print_DigestReqInner + print_DigestRequest + print_DigestResponse + print_DigestTypes + print_DirectoryString + print_DisplayText + print_DistributionPoint + print_DistributionPointName + print_DistributionPointReasonFlags + print_DomainParameters + print_DSAParams + print_DSAPublicKey + print_DSASigValue + print_ECDSA_Sig_Value + print_ECParameters + print_ECPoint + print_EKCertificateGenerationLocation + print_EKGenerationLocation + print_EKGenerationType + print_EncAPRepPart + print_EncapsulatedContentInfo + print_EncASRepPart + print_EncKDCRepPart + print_EncKrbCredPart + print_EncKrbPrivPart + print_EncryptedContent + print_EncryptedContentInfo + print_EncryptedData + print_EncryptedKey + print_EncryptionKey + print_EncTGSRepPart + print_EncTicketPart + print_ENCTYPE + print_EnvelopedData + print_ETYPE_INFO + print_ETYPE_INFO2 + print_ETYPE_INFO2_ENTRY + print_ETYPE_INFO_ENTRY + print_EtypeList + print_EvaluationAssuranceLevel + print_EvaluationStatus + print_Extension + print_Extensions + print_ExternalPrincipalIdentifier + print_ExternalPrincipalIdentifiers + print_ExtKeyUsage + print_FastOptions + print_FIPSLevel + print_FirmwarePackageIdentifier + print_FirmwarePackageInfo + print_FirmwarePackageLoadError + print_FirmwarePackageLoadErrorCode + print_FirmwarePackageLoadReceipt + print_FirmwarePkgData + print_FWErrorVersion + print_FWReceiptVersion + print_GeneralName + print_GeneralNames + print_GeneralSubtree + print_GeneralSubtrees + print_HardwareModuleName + print_HardwareModules + print_HardwareSerialEntry + print_heim_any + print_HEIM_ANY + print_heim_any_set + print_HEIM_ANY_SET + print_HostAddress + print_HostAddresses + print_ImplementedCompressAlgorithms + print_ImplementedCryptoAlgorithms + print_IOSCertificationRequest + print_IOSCertificationRequest + print_IOSCertificationRequestInfo + print_IOSCertificationRequestInfo + print_IssuerAndSerialNumber + print_KDCDHKeyInfo + print_KDCDHKeyInfo_Win2k + print_KDCFastCookie + print_KDCFastFlags + print_KDCFastState + print_KDCOptions + print_KDC_PROXY_MESSAGE + print_KDC_REP + print_KDC_REQ + print_KDC_REQ_BODY + print_KDFAlgorithmId + print_KERB_ARMOR_SERVICE_REPLY + print_KERB_CRED + print_KerberosString + print_KerberosTime + print_KERB_ERROR_DATA + print_KERB_TGS_REP_IN + print_KERB_TGS_REP_OUT + print_KERB_TGS_REQ_IN + print_KERB_TGS_REQ_OUT + print_KERB_TIMES + print_KeyEncryptionAlgorithmIdentifier + print_KeyIdentifier + print_KeyTransRecipientInfo + print_KeyUsage + print_Krb5Int32 + print_KRB5PrincipalName + print_Krb5UInt32 + print_KRB_CRED + print_KrbCredInfo + print_KRB_ERROR + print_KrbFastArmor + print_KrbFastArmoredRep + print_KrbFastArmoredReq + print_KrbFastFinished + print_KrbFastReq + print_KrbFastResponse + print_KRB_PRIV + print_KRB_SAFE + print_KRB_SAFE_BODY + print_Kx509CSRPlus + print_Kx509ErrorCode + print_KX509_ERROR_CODE + print_Kx509Request + print_Kx509Response + print_LastReq + print_LR_TYPE + print_MessageDigest + print_MESSAGE_TYPE + print_METHOD_DATA + print_MS_UPN_SAN + print_Name + print_NameConstraints + print_NAME_TYPE + print_NoticeReference + print_NTLMInit + print_NTLMInitReply + print_NTLMReply + print_NTLMRequest + print_NTLMRequest2 + print_NTLMResponse + print_OCSPBasicOCSPResponse + print_OCSPCertID + print_OCSPCertStatus + print_OCSPInnerRequest + print_OCSPKeyHash + print_OCSPRequest + print_OCSPResponderID + print_OCSPResponse + print_OCSPResponseBytes + print_OCSPResponseData + print_OCSPResponseStatus + print_OCSPSignature + print_OCSPSingleResponse + print_OCSPTBSRequest + print_OCSPVersion + print_OriginatorInfo + print_OtherName + print_PA_DATA + print_PADATA_TYPE + print_PA_ENC_SAM_RESPONSE_ENC + print_PA_ENC_TS_ENC + print_PA_FX_FAST_REPLY + print_PA_FX_FAST_REQUEST + print_PA_PAC_REQUEST + print_PA_PK_AS_REP + print_PA_PK_AS_REP_BTMM + print_PA_PK_AS_REP_Win2k + print_PA_PK_AS_REQ + print_PA_PK_AS_REQ_Win2k + print_PA_S4U2Self + print_PA_SAM_CHALLENGE_2 + print_PA_SAM_CHALLENGE_2_BODY + print_PA_SAM_REDIRECT + print_PA_SAM_RESPONSE_2 + print_PA_SAM_TYPE + print_PA_ServerReferralData + print_PA_SERVER_REFERRAL_DATA + print_PA_SvrReferralData + print_PermanentIdentifier + print_PKAuthenticator + print_PKAuthenticator_Win2k + print_PKCS12_Attribute + print_PKCS12_Attributes + print_PKCS12_AuthenticatedSafe + print_PKCS12_CertBag + print_PKCS12_MacData + print_PKCS12_OctetString + print_PKCS12_PBEParams + print_PKCS12_PFX + print_PKCS12_SafeBag + print_PKCS12_SafeContents + print_PKCS8Attributes + print_PKCS8EncryptedData + print_PKCS8EncryptedPrivateKeyInfo + print_PKCS8PrivateKey + print_PKCS8PrivateKeyAlgorithmIdentifier + print_PKCS8PrivateKeyInfo + print_PKCS9_BMPString + print_PKCS9_friendlyName + print_PkinitSP80056AOtherInfo + print_PkinitSuppPubInfo + print_PKIXXmppAddr + print_PolicyConstraints + print_PolicyInformation + print_PolicyMapping + print_PolicyMappings + print_PolicyQualifierId + print_PolicyQualifierInfo + print_PolicyQualifierInfos + print_PreferredOrLegacyPackageIdentifier + print_PreferredOrLegacyStalePackageIdentifier + print_PreferredPackageIdentifier + print_Principal + print_PrincipalName + print_Principals + print_PrivateKeyUsagePeriod + print_PROV_SRV_LOCATION + print_ProxyCertInfo + print_ProxyPolicy + print_RDNSequence + print_Realm + print_RecipientIdentifier + print_RecipientInfo + print_RecipientInfos + print_RelativeDistinguishedName + print_ReplyKeyPack + print_ReplyKeyPack_Win2k + print_RSAPrivateKey + print_RSAPublicKey + print_SAMFlags + print_SecurityLevel + print_SignatureAlgorithmIdentifier + print_SignatureValue + print_SignedData + print_SignerIdentifier + print_SignerInfo + print_SignerInfos + print_SingleAttribute + print_SkipCerts + print_SRVName + print_StrengthOfFunction + print_SubjectDirectoryAttributes + print_SubjectInfoAccessSyntax + print_SubjectKeyIdentifier + print_SubjectPublicKeyInfo + print_TargetHardwareIdentifiers + print_TBSCertificate + print_TBSCRLCertList + print_TD_DH_PARAMETERS + print_TD_INVALID_CERTIFICATES + print_TD_TRUSTED_CERTIFIERS + print_TGS_REP + print_TGS_REQ + print_Ticket + print_TicketFlags + print_Time + print_TPMSecurityAssertions + print_TPMSpecification + print_TPMVersion + print_TransitedEncoding + print_TrustedCA + print_TrustedCA_Win2k + print_TypedData + print_TYPED_DATA + print_UniqueIdentifier + print_UnprotectedAttributes + print_URIReference + print_UserNotice + print_ValidationParms + print_Validity + print_VendorLoadErrorCode + print_Version + print_WrappedFirmwareKey + print_X520CommonName + print_X520LocalityName + print_X520name + print_X520OrganizationalUnitName + print_X520OrganizationName + print_X520StateOrProvinceName + print_X690SampleChildInformation + print_X690SampleDate + print_X690SampleEmployeeNumber + print_X690SampleName + print_X690SamplePersonnelRecord + remove_AttributeValues + remove_AuthorizationData + remove_CertificatePolicies + remove_Certificates + remove_CRLDistributionPoints + remove_DigestAlgorithmIdentifiers + remove_ETYPE_INFO + remove_ETYPE_INFO2 + remove_Extensions + remove_GeneralNames + remove_METHOD_DATA + remove_PolicyMappings + remove_PolicyQualifierInfos + remove_Principals + remove_RDNSequence + SAMFlags2int + TicketFlags2int diff --git a/third_party/heimdal/lib/asn1/main.c b/third_party/heimdal/lib/asn1/main.c new file mode 100644 index 0000000..babcc00 --- /dev/null +++ b/third_party/heimdal/lib/asn1/main.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" +#include <getarg.h> +#include "lex.h" + +extern FILE *yyin; + +static getarg_strings preserve; +static getarg_strings seq; +static getarg_strings decorate; + +static int +strcmp4mergesort_r(const void *ap, const void *bp, void *d) +{ + const char *a = *(const char **)ap; + const char *b = *(const char **)bp; + char sep = *(const char *)d; + int cmp; + + if (sep) { + const char *sepa = strchr(a, sep); + const char *sepb = strchr(b, sep); + size_t alen, blen; + + if (sepa == NULL) sepa = a + strlen(a); + if (sepb == NULL) sepb = b + strlen(b); + alen = sepa - a; + blen = sepb - b; + cmp = strncmp(a, b, alen > blen ? alen : blen); + if (cmp == 0) + cmp = alen - blen; + } else + cmp = strcmp(a, b); + if (cmp == 0) + return (uintptr_t)ap - (uintptr_t)bp; /* stable sort */ + return cmp; +} + +static int +prefix_check(const char *s, const char *p, size_t plen, char sep, int *cmp) +{ + if ((*cmp = strncmp(p, s, plen)) == 0 && s[plen] == sep) + return 1; + if (*cmp == 0) + *cmp = 1; + return 0; +} + +static ssize_t +bsearch_strings(struct getarg_strings *strs, const char *p, + char sep, ssize_t *more) +{ + ssize_t right = (ssize_t)strs->num_strings - 1; + ssize_t left = 0; + ssize_t plen = 0; + int cmp; + + if (sep) + plen = strlen(p); + + if (strs->num_strings == 0) + return -1; + + if (sep && more && *more > -1) { + /* If *more > -1 we're continuing an iteration */ + if (*more > right) + return -1; + if (prefix_check(strs->strings[*more], p, plen, sep, &cmp)) + return (*more)++; + (*more)++; + return -1; + } + + while (left <= right) { + ssize_t mid = left + (right - left) / 2; + + if (sep) { + int cmp2; + + while (prefix_check(strs->strings[mid], p, plen, sep, &cmp) && + mid > 0 && + prefix_check(strs->strings[mid - 1], p, plen, sep, &cmp2)) + mid--; + } else + cmp = strcmp(p, strs->strings[mid]); + if (cmp == 0) { + if (more) + *more = mid + 1; + return mid; + } + if (cmp < 0) + right = mid - 1; /* -1 if `p' is smaller than smallest in strs */ + else + left = mid + 1; + } + return -1; +} + +int +preserve_type(const char *p) +{ + return bsearch_strings(&preserve, p, '\0', 0) > -1; +} + +int +seq_type(const char *p) +{ + return bsearch_strings(&seq, p, '\0', 0) > -1; +} + +/* + * Split `s' on `sep' and fill fs[] with pointers to the substrings. + * + * Only the first substring is to be freed -- the rest share the same + * allocation. + * + * The last element may contain `sep' chars if there are more fields in `s' + * than output locations in `fs[]'. + */ +static void +split_str(const char *s, char sep, char ***fs) +{ + size_t i; + + fs[0][0] = estrdup(s); + for (i = 1; fs[i]; i++) { + char *q; + + if ((q = strchr(fs[i-1][0], sep)) == NULL) + break; + *(q++) = '\0'; + fs[i][0] = q; + } + for (; fs[i]; i++) + fs[i][0] = NULL; +} + +/* + * If `p' is "decorated" with a not-to-be-encoded-or-decoded field, + * output the field's typename and fieldname, whether it's optional, whether + * it's an ASN.1 type or an "external" type, and if external the names of + * functions to copy and free values of that type. + */ +int +decorate_type(const char *p, struct decoration *deco, ssize_t *more) +{ + ssize_t i; + char **s[7]; + char *junk = NULL; + char *cp; + + deco->first = *more == -1; + deco->decorated = 0; + deco->field_type = NULL; + if ((i = bsearch_strings(&decorate, p, ':', more)) == -1) + return 0; + + deco->decorated = 1; + deco->opt = deco->ext = deco->ptr = 0; + deco->void_star = deco->struct_star = 0; + deco->field_name = deco->copy_function_name = deco->free_function_name = + deco->header_name = NULL; + + s[0] = &deco->field_type; + s[1] = &deco->field_name; + s[2] = &deco->copy_function_name; + s[3] = &deco->free_function_name; + s[4] = &deco->header_name; + s[5] = &junk; + s[6] = NULL; + split_str(decorate.strings[i] + strlen(p) + 1, ':', s); + + if (junk || deco->field_type[0] == '\0' || !deco->field_name || + deco->field_name[0] == '\0' || deco->field_name[0] == '?') { + errx(1, "Invalidate type decoration specification: --decorate=\"%s\"", + decorate.strings[i]); + } + if ((cp = strchr(deco->field_name, '?'))) { + deco->opt = 1; + *cp = '\0'; + } + if (strcmp(deco->field_type, "void*") == 0 || + strcmp(deco->field_type, "void *") == 0) { + deco->ext = deco->ptr = deco->void_star = 1; + deco->opt = 1; + deco->header_name = NULL; + } else if (strncmp(deco->field_type, "struct ", sizeof("struct ") - 1) == 0 && + deco->field_type[strlen(deco->field_type) - 1] == '*') + deco->ptr = deco->struct_star = 1; + if (deco->ptr || deco->copy_function_name) + deco->ext = 1; + if (deco->ext && deco->copy_function_name && !deco->copy_function_name[0]) + deco->copy_function_name = NULL; + if (deco->ext && deco->free_function_name && !deco->free_function_name[0]) + deco->free_function_name = NULL; + if (deco->header_name && !deco->header_name[0]) + deco->header_name = NULL; + if (deco->ptr) + deco->opt = 0; + return 1; +} + +static const char * +my_basename(const char *fn) +{ + const char *base, *p; + + for (p = base = fn; *p; p++) { +#ifdef WIN32 + if (*p == '/' || *p == '\\') + base = p + 1; +#else + if (*p == '/') + base = p + 1; +#endif + } + return base; +} + +const char *fuzzer_string = ""; +const char *enum_prefix; +const char *name; +int prefix_enum; +int fuzzer_flag; +int support_ber; +int template_flag; +int rfc1510_bitstring; +int one_code_file; +char *option_file; +int parse_units_flag = 1; +char *type_file_string = "krb5-types.h"; +int original_order; +int version_flag; +int help_flag; +struct getargs args[] = { + { "fuzzer", 0, arg_flag, &fuzzer_flag, NULL, NULL }, + { "template", 0, arg_flag, &template_flag, NULL, NULL }, + { "prefix-enum", 0, arg_flag, &prefix_enum, + "prefix C enum labels for ENUMERATED types and INTEGER types with the " + "type's name", NULL }, + { "enum-prefix", 0, arg_string, &enum_prefix, + "prefix for C enum labels for ENUMERATED types and INTEGER types with " + "enumerated values", "PREFIX" }, + { "encode-rfc1510-bit-string", 0, arg_flag, &rfc1510_bitstring, + "Use RFC1510 incorrect BIT STRING handling for all BIT STRING types " + "in the module", NULL }, + { "decode-dce-ber", 0, arg_flag, &support_ber, + "Allow DCE-style BER on decode", NULL }, + { "support-ber", 0, arg_flag, &support_ber, "Allow BER on decode", NULL }, + { "preserve-binary", 0, arg_strings, &preserve, + "Names of types for which to generate _save fields, saving original " + "encoding, in containing structures (useful for signature " + "verification)", "TYPE" }, + { "sequence", 0, arg_strings, &seq, + "Generate add/remove functions for SEQUENCE OF types", "TYPE" }, + { "decorate", 0, arg_strings, &decorate, + "Generate private field for SEQUENCE/SET type", "DECORATION" }, + { "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL }, + { "gen-name", 0, arg_string, &name, + "Name of generated module", "NAME" }, + { "option-file", 0, arg_string, &option_file, + "File with additional compiler CLI options", "FILE" }, + { "original-order", 0, arg_flag, &original_order, + "Define C types and functions in the order in which they appear in " + "the ASN.1 module instead of topologically sorting types. This " + "is useful for comparing output to earlier compiler versions.", + NULL }, + { "parse-units", 0, arg_negative_flag, &parse_units_flag, + "Do not generate roken-style units", NULL }, + { "type-file", 0, arg_string, &type_file_string, + "Name of a C header file to generate includes of for base types", + "FILE" }, + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 0, arg_flag, &help_flag, NULL, NULL } +}; +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int code) +{ + if (code) + dup2(STDERR_FILENO, STDOUT_FILENO); + else + dup2(STDOUT_FILENO, STDERR_FILENO); + arg_printusage(args, num_args, NULL, "[asn1-file [name]]"); + fprintf(stderr, + "\nA DECORATION is one of:\n\n" + "\tTYPE:FTYPE:fname[?]\n" + "\tTYPE:FTYPE:fname[?]:[copy_function]:[free_function]:header\n" + "\tTYPE:void:fname:::\n" + "\nSee the manual page.\n"); + exit(code); +} + +int error_flag; + +int +main(int argc, char **argv) +{ + int ret; + const char *file; + FILE *opt = NULL; + int optidx = 0; + char **arg = NULL; + size_t len = 0; + size_t sz = 0; + int i; + + setprogname(argv[0]); + if (getarg(args, num_args, argc, argv, &optidx)) + usage(1); + if (help_flag) + usage(0); + if (version_flag) { + print_version(NULL); + exit(0); + } + if (argc == optidx) { + /* Compile the module on stdin */ + file = "stdin"; + name = "stdin"; + yyin = stdin; + } else { + /* Compile a named module */ + file = argv[optidx]; + + /* + * If the .asn1 stem is not given, then assume it, and also assume + * --option-file was given if the .opt file exists + */ + if (strchr(file, '.') == NULL) { + char *s = NULL; + + if (asprintf(&s, "%s.opt", file) == -1 || s == NULL) + err(1, "Out of memory"); + if ((opt = fopen(s, "r"))) + option_file = s; + else + free(s); + if (asprintf(&s, "%s.asn1", file) == -1 || s == NULL) + err(1, "Out of memory"); + file = s; + } + yyin = fopen (file, "r"); + if (yyin == NULL) + err (1, "open %s", file); + if (argc == optidx + 1) { + char *p; + + /* C module name substring not given; derive from file name */ + name = my_basename(estrdup(file)); + p = strrchr(name, '.'); + if (p) + *p = '\0'; + } else + name = argv[optidx + 1]; + } + + /* + * Parse extra options file + */ + if (option_file) { + char buf[1024]; + + if (opt == NULL && + (opt = fopen(option_file, "r")) == NULL) + err(1, "Could not open given option file %s", option_file); + + arg = calloc(2, sizeof(arg[0])); + if (arg == NULL) { + perror("calloc"); + exit(1); + } + arg[0] = option_file; + arg[1] = NULL; + len = 1; + sz = 2; + + while (fgets(buf, sizeof(buf), opt) != NULL) { + size_t buflen, ws; + + buf[strcspn(buf, "\n\r")] = '\0'; + + buflen = strlen(buf); + if ((ws = strspn(buf, " \t"))) + memmove(buf, buf + ws, buflen - ws); + if (buf[0] == '\0' || buf[0] == '#') + continue; + + if (len + 1 >= sz) { + arg = realloc(arg, (sz + (sz>>1) + 2) * sizeof(arg[0])); + if (arg == NULL) { + perror("malloc"); + exit(1); + } + sz += (sz>>1) + 2; + } + arg[len] = strdup(buf); + if (arg[len] == NULL) { + perror("strdup"); + exit(1); + } + arg[len + 1] = NULL; + len++; + } + fclose(opt); + + optidx = 0; + if(getarg(args, num_args, len, arg, &optidx)) + usage(1); + + if (len != optidx) { + fprintf(stderr, "extra args"); + exit(1); + } + } + + if (fuzzer_flag) { + if (!template_flag) { + printf("can't do fuzzer w/o --template"); + exit(1); + } +#ifdef ASN1_FUZZER + fuzzer_string = "_fuzzer"; +#endif + } + + if (preserve.num_strings) + mergesort_r(preserve.strings, preserve.num_strings, + sizeof(preserve.strings[0]), strcmp4mergesort_r, ""); + if (seq.num_strings) + mergesort_r(seq.strings, seq.num_strings, sizeof(seq.strings[0]), + strcmp4mergesort_r, ""); + if (decorate.num_strings) + mergesort_r(decorate.strings, decorate.num_strings, + sizeof(decorate.strings[0]), strcmp4mergesort_r, ":"); + + init_generate(file, name); + + if (one_code_file) + generate_header_of_codefile(name); + + initsym (); + ret = yyparse (); + if(ret != 0 || error_flag != 0) + exit(1); + if (!original_order) + generate_types(); + if (argc != optidx) + fclose(yyin); + + if (one_code_file) + close_codefile(); + close_generate(); + + if (arg) { + for (i = 1; i < len; i++) + free(arg[i]); + free(arg); + } + + return 0; +} diff --git a/third_party/heimdal/lib/asn1/ocsp.asn1 b/third_party/heimdal/lib/asn1/ocsp.asn1 new file mode 100644 index 0000000..eb090a4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/ocsp.asn1 @@ -0,0 +1,113 @@ +-- From rfc2560 +-- $Id$ +OCSP DEFINITIONS EXPLICIT TAGS::= + +BEGIN + +IMPORTS + Certificate, AlgorithmIdentifier, CRLReason, + Name, GeneralName, CertificateSerialNumber, Extensions + FROM rfc2459; + +OCSPVersion ::= INTEGER { ocsp-v1(0) } + +OCSPCertStatus ::= CHOICE { + good [0] IMPLICIT NULL, + revoked [1] IMPLICIT -- OCSPRevokedInfo -- SEQUENCE { + revocationTime GeneralizedTime, + revocationReason[0] EXPLICIT CRLReason OPTIONAL + }, + unknown [2] IMPLICIT NULL } + +OCSPCertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, -- Hash of Issuer's DN + issuerKeyHash OCTET STRING, -- Hash of Issuers public key + serialNumber CertificateSerialNumber } + +OCSPSingleResponse ::= SEQUENCE { + certID OCSPCertID, + certStatus OCSPCertStatus, + thisUpdate GeneralizedTime, + nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + singleExtensions [1] EXPLICIT Extensions OPTIONAL } + +OCSPInnerRequest ::= SEQUENCE { + reqCert OCSPCertID, + singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + +OCSPTBSRequest ::= SEQUENCE { + version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL, + requestorName [1] EXPLICIT GeneralName OPTIONAL, + requestList SEQUENCE OF OCSPInnerRequest, + requestExtensions [2] EXPLICIT Extensions OPTIONAL } + +OCSPSignature ::= SEQUENCE { + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +OCSPRequest ::= SEQUENCE { + tbsRequest OCSPTBSRequest, + optionalSignature [0] EXPLICIT OCSPSignature OPTIONAL } + +OCSPResponseBytes ::= SEQUENCE { + responseType OBJECT IDENTIFIER, + response OCTET STRING } + +OCSPResponseStatus ::= ENUMERATED { + successful (0), --Response has valid confirmations + malformedRequest (1), --Illegal confirmation request + internalError (2), --Internal error in issuer + tryLater (3), --Try again later + --(4) is not used + sigRequired (5), --Must sign the request + unauthorized (6) --Request unauthorized +} + +OCSPResponse ::= SEQUENCE { + responseStatus OCSPResponseStatus, + responseBytes [0] EXPLICIT OCSPResponseBytes OPTIONAL } + +OCSPKeyHash ::= OCTET STRING --SHA-1 hash of responder's public key + --(excluding the tag and length fields) + +OCSPResponderID ::= CHOICE { + byName [1] Name, + byKey [2] OCSPKeyHash } + +OCSPResponseData ::= SEQUENCE { + version [0] EXPLICIT OCSPVersion -- DEFAULT v1 -- OPTIONAL, + responderID OCSPResponderID, + producedAt GeneralizedTime, + responses SEQUENCE OF OCSPSingleResponse, + responseExtensions [1] EXPLICIT Extensions OPTIONAL } + +OCSPBasicOCSPResponse ::= SEQUENCE { + tbsResponseData OCSPResponseData, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +-- ArchiveCutoff ::= GeneralizedTime + +-- AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER + +-- Object Identifiers + +id-pkix-ocsp OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) pkix-ad(48) 1 +} + +id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 } +id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 } +-- id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 } +-- id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 } +-- id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 } +-- id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 } +-- id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 } + + +END + diff --git a/third_party/heimdal/lib/asn1/ocsp.opt b/third_party/heimdal/lib/asn1/ocsp.opt new file mode 100644 index 0000000..697aa03 --- /dev/null +++ b/third_party/heimdal/lib/asn1/ocsp.opt @@ -0,0 +1,2 @@ +--preserve-binary=OCSPTBSRequest +--preserve-binary=OCSPResponseData diff --git a/third_party/heimdal/lib/asn1/oid_resolution.c b/third_party/heimdal/lib/asn1/oid_resolution.c new file mode 100644 index 0000000..db11b11 --- /dev/null +++ b/third_party/heimdal/lib/asn1/oid_resolution.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2019 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <hex.h> + +#include "cms_asn1.h" +#include "crmf_asn1.h" +#include "digest_asn1.h" +#include "krb5_asn1.h" +#include "kx509_asn1.h" +#include "ocsp_asn1.h" +#include "pkcs10_asn1.h" +#include "pkcs12_asn1.h" +#include "pkcs8_asn1.h" +#include "pkcs9_asn1.h" +#include "pkinit_asn1.h" +#include "rfc2459_asn1.h" +#include "rfc4108_asn1.h" + + +struct sym_oid { + const char *sym; + const heim_oid *oid; +}; + +#ifndef WIN32 +#define DEFINE_OID_WITH_NAME(sym) \ + { #sym, &asn1_oid_ ## sym }, + +static const struct sym_oid sym_oids[] = { +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" +#include "rfc4108_asn1_oids.c" +}; + +static size_t num_sym_oids = sizeof(sym_oids) / sizeof(sym_oids[0]); + +#undef DEFINE_OID_WITH_NAME + +#define init_sym_oids() + +#else + +/* + * We can't use C99 non-literal initializers for static objects in the Windows + * build... + */ + +static struct sym_oid *sym_oids; +static size_t num_sym_oids; + +#define DEFINE_OID_WITH_NAME(sym) (c++); +static size_t +count_sym_oids(void) +{ + size_t c = 0; +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" + return c; +} +#undef DEFINE_OID_WITH_NAME + +#define DEFINE_OID_WITH_NAME(s) \ + tmp[i].sym = #s; \ + tmp[i++].oid = &asn1_oid_ ## s; + +static void +init_sym_oids(void) +{ + static struct sym_oid *tmp; + size_t i = 0; + size_t c; + + if (!sym_oids && + (c = count_sym_oids()) && + (tmp = calloc(c, sizeof(tmp[0])))) { +#include "cms_asn1_oids.c" +#include "crmf_asn1_oids.c" +#include "digest_asn1_oids.c" +#include "krb5_asn1_oids.c" +#include "kx509_asn1_oids.c" +#include "ocsp_asn1_oids.c" +#include "pkcs10_asn1_oids.c" +#include "pkcs12_asn1_oids.c" +#include "pkcs8_asn1_oids.c" +#include "pkcs9_asn1_oids.c" +#include "pkinit_asn1_oids.c" +#include "rfc2459_asn1_oids.c" + num_sym_oids = c; + sym_oids = tmp; + } +} +#undef DEFINE_OID_WITH_NAME + +#endif + +static struct sym_oid *sym_oids_sorted_by_name; +static struct sym_oid *sym_oids_sorted_by_oid; + +static int +sym_cmp_name(const void *va, const void *vb) +{ + const struct sym_oid *a = va; + const struct sym_oid *b = vb; + + return (strcmp(a->sym, b->sym)); +} + +static int +sym_cmp_oid(const void *va, const void *vb) +{ + const struct sym_oid *a = va; + const struct sym_oid *b = vb; + + return der_heim_oid_cmp(a->oid, b->oid); +} + +static struct sym_oid * +sort_sym_oids(int (*cmp)(const void *, const void *)) +{ + struct sym_oid *tmp; + + init_sym_oids(); + if ((tmp = calloc(num_sym_oids, sizeof(tmp[0]))) == NULL) + return NULL; + + memcpy(tmp, sym_oids, num_sym_oids * sizeof(tmp[0])); + qsort(tmp, num_sym_oids, sizeof(struct sym_oid), cmp); + return tmp; +} + +static int +fix_oid_name(const char **namep, char **freeme) +{ + char *dash = strchr(*namep, '-'); + + *freeme = NULL; + if (dash == NULL) + return 0; + if ((*freeme = strdup(*namep)) == NULL) + return ENOMEM; + *namep = *freeme; + for (dash = strchr(*namep, '-'); dash; dash = strchr(dash, '-')) + *dash = '_'; + return 0; +} + +int ASN1CALL +der_find_heim_oid_by_name(const char *str, const heim_oid **oid) +{ + size_t right = num_sym_oids - 1; + size_t left = 0; + char *s = NULL; + int ret; + + *oid = NULL; + if (sym_oids_sorted_by_name == NULL && + (sym_oids_sorted_by_name = sort_sym_oids(sym_cmp_name)) == NULL) + return ENOMEM; + + if ((ret = fix_oid_name(&str, &s))) + return ret; + + while (left <= right) { + size_t mid = left + (right - left) / 2; + int cmp; + + cmp = strcmp(str, sym_oids_sorted_by_name[mid].sym); + if (cmp == 0) { + *oid = sym_oids_sorted_by_name[mid].oid; + free(s); + return 0; + } + if (cmp < 0 && mid > 0) {/* avoid underflow */ + right = mid - 1; + } else if (cmp < 0) { + free(s); + return -1; + } else { + left = mid + 1; + } + } + free(s); + return -1; +} + +int ASN1CALL +der_find_or_parse_heim_oid(const char *str, const char *sep, heim_oid *oid) +{ + const heim_oid *found = NULL; + + switch (der_find_heim_oid_by_name(str, &found)) { + case 0: return der_copy_oid(found, oid); + case -1: return der_parse_heim_oid(str, sep, oid); + default: return ENOMEM; + } +} + +int ASN1CALL +der_find_heim_oid_by_oid(const heim_oid *oid, const char **name) +{ + size_t right = num_sym_oids; + size_t left = 0; + + *name = NULL; + if (sym_oids_sorted_by_oid == NULL && + (sym_oids_sorted_by_oid = sort_sym_oids(sym_cmp_oid)) == NULL) + return ENOMEM; + + while (left <= right) { + size_t mid = (left + right) >> 1; + int cmp; + + cmp = der_heim_oid_cmp(oid, sym_oids_sorted_by_oid[mid].oid); + if (cmp == 0) { + *name = sym_oids_sorted_by_oid[mid].sym; + return 0; + } + if (cmp < 0 && mid) + right = mid - 1; + else if (cmp < 0) + return -1; + else if (mid < num_sym_oids - 1) + left = mid + 1; + else + return -1; + } + return -1; +} + +int ASN1CALL +der_match_heim_oid_by_name(const char *str, int *c, const heim_oid **oid) +{ + size_t i; + char *s = NULL; + int ret; + + if ((ret = fix_oid_name(&str, &s))) + return ret; + + if (*c < 0) + *c = 0; + + init_sym_oids(); + for (i = (size_t)*c; i < num_sym_oids; i++) { + /* + * XXX We need a lib/roken strcasestr(), or maybe we should support + * globbing here. + */ + if (strstr(sym_oids[i].sym, str)) { + *oid = sym_oids[i].oid; + free(s); + if (i >= INT_MAX) + return -1; + *c = i + 1; /* num_sym_oids is much less than INT_MAX */ + return 0; + } + } + free(s); + return -1; +} + +/* Warning: der_print_heim_oid_sym() will not round-trip */ + +int ASN1CALL +der_print_heim_oid_sym(const heim_oid *oid, char delim, char **strp) +{ + const char *sym; + char *s1 = NULL; + char *s2 = NULL; + char *p; + int ret; + + if (der_find_heim_oid_by_oid(oid, &sym)) + return der_print_heim_oid(oid, delim, strp); + + if ((ret = der_print_heim_oid(oid, delim, &s1))) + return ret; + if (asprintf(&s2, "%s (%s)", s1, sym) == -1 || s2 == NULL) { + *strp = s1; + return 0; + } + for (p = s2 + strlen(s1) + 1; *p; p++) { + if (*p == '_') + *p = '-'; + } + *strp = s2; + free(s1); + return 0; +} diff --git a/third_party/heimdal/lib/asn1/pkcs10.asn1 b/third_party/heimdal/lib/asn1/pkcs10.asn1 new file mode 100644 index 0000000..04cda4e --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs10.asn1 @@ -0,0 +1,64 @@ +-- $Id$ +PKCS10 DEFINITIONS ::= + +BEGIN + +IMPORTS + Name, SubjectPublicKeyInfo, AlgorithmIdentifier, Attribute, Extensions + FROM rfc2459 + HEIM_ANY FROM heim; + +PKCS10-Version ::= INTEGER { pkcs10-v1(0) } + +CertificationRequestInfo ::= SEQUENCE { + version PKCS10-Version, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] IMPLICIT SET OF Attribute OPTIONAL +} + +CertificationRequest ::= SEQUENCE { + certificationRequestInfo CertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +IOSCertificationRequestInfo ::= SEQUENCE { + version PKCS10-Version, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] IMPLICIT SET OF CRIAttributeSet OPTIONAL +} + +IOSCertificationRequest ::= SEQUENCE { + certificationRequestInfo IOSCertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +-- Copied from rfc2459.asn1 because we can't IMPORT classes and parameterized +-- types yet. +_ATTRIBUTE ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type OPTIONAL, + &minCount INTEGER DEFAULT 1, + &maxCount INTEGER OPTIONAL +} + +id-pkcs9-extReq-copy OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 14 +} + +-- Workaround compiler limitation: +CRIExtensions ::= Extensions + +at-extReq _ATTRIBUTE ::= { &Type CRIExtensions, &id id-pkcs9-extReq-copy } +CRIAttributes _ATTRIBUTE ::= { at-extReq } +CRIAttributeSet{_ATTRIBUTE:AttrSet} ::= SEQUENCE { + type _ATTRIBUTE.&id({AttrSet}), + values SET --SIZE (1..MAX)-- OF _ATTRIBUTE.&Type({AttrSet}{@type}) +} +CRIAttributeSet ::= CRIAttributeSet{CRIAttributes} + +END + diff --git a/third_party/heimdal/lib/asn1/pkcs10.opt b/third_party/heimdal/lib/asn1/pkcs10.opt new file mode 100644 index 0000000..499fab2 --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs10.opt @@ -0,0 +1 @@ +--preserve-binary=CertificationRequestInfo diff --git a/third_party/heimdal/lib/asn1/pkcs12.asn1 b/third_party/heimdal/lib/asn1/pkcs12.asn1 new file mode 100644 index 0000000..61d3e2c --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs12.asn1 @@ -0,0 +1,81 @@ +-- $Id$ -- + +PKCS12 DEFINITIONS ::= + +BEGIN + +IMPORTS ContentInfo FROM cms + DigestInfo FROM rfc2459 + HEIM_ANY, HEIM_ANY_SET FROM heim; + +-- The PFX PDU + +id-pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) pkcs-12(12) } + +id-pkcs-12PbeIds OBJECT IDENTIFIER ::= { id-pkcs-12 1} +id-pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 1} +id-pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 2} +id-pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 3} +id-pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 4} +id-pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 5} +id-pbewithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= { id-pkcs-12PbeIds 6} + +id-pkcs12-bagtypes OBJECT IDENTIFIER ::= { id-pkcs-12 10 1} + +id-pkcs12-keyBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 1 } +id-pkcs12-pkcs8ShroudedKeyBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 2 } +id-pkcs12-certBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 3 } +id-pkcs12-crlBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 4 } +id-pkcs12-secretBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 5 } +id-pkcs12-safeContentsBag OBJECT IDENTIFIER ::= { id-pkcs12-bagtypes 6 } + + +PKCS12-MacData ::= SEQUENCE { + mac DigestInfo, + macSalt OCTET STRING, + iterations INTEGER OPTIONAL +} + +PKCS12-PFX ::= SEQUENCE { + version INTEGER, + authSafe ContentInfo, + macData PKCS12-MacData OPTIONAL +} + +PKCS12-AuthenticatedSafe ::= SEQUENCE OF ContentInfo + -- Data if unencrypted + -- EncryptedData if password-encrypted + -- EnvelopedData if public key-encrypted + +PKCS12-Attribute ::= SEQUENCE { + attrId OBJECT IDENTIFIER, + attrValues -- SET OF -- HEIM_ANY_SET +} + +PKCS12-Attributes ::= SET OF PKCS12-Attribute + +PKCS12-SafeBag ::= SEQUENCE { + bagId OBJECT IDENTIFIER, + bagValue [0] HEIM_ANY, + bagAttributes PKCS12-Attributes OPTIONAL +} + +PKCS12-SafeContents ::= SEQUENCE OF PKCS12-SafeBag + +PKCS12-CertBag ::= SEQUENCE { + certType OBJECT IDENTIFIER, + certValue [0] HEIM_ANY +} + +PKCS12-PBEParams ::= SEQUENCE { + salt OCTET STRING, + iterations INTEGER (0..4294967295) OPTIONAL +} + +PKCS12-OctetString ::= OCTET STRING + +-- KeyBag ::= PrivateKeyInfo +-- PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo + +END diff --git a/third_party/heimdal/lib/asn1/pkcs8.asn1 b/third_party/heimdal/lib/asn1/pkcs8.asn1 new file mode 100644 index 0000000..6227033 --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs8.asn1 @@ -0,0 +1,29 @@ +-- $Id$ -- + +PKCS8 DEFINITIONS ::= + +BEGIN + +IMPORTS Attribute, AlgorithmIdentifier FROM rfc2459; + +PKCS8PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + +PKCS8PrivateKey ::= OCTET STRING + +PKCS8Attributes ::= SET OF Attribute + +PKCS8PrivateKeyInfo ::= SEQUENCE { + version INTEGER, + privateKeyAlgorithm PKCS8PrivateKeyAlgorithmIdentifier, + privateKey PKCS8PrivateKey, + attributes [0] IMPLICIT SET OF Attribute OPTIONAL +} + +PKCS8EncryptedData ::= OCTET STRING + +PKCS8EncryptedPrivateKeyInfo ::= SEQUENCE { + encryptionAlgorithm AlgorithmIdentifier, + encryptedData PKCS8EncryptedData +} + +END diff --git a/third_party/heimdal/lib/asn1/pkcs9.asn1 b/third_party/heimdal/lib/asn1/pkcs9.asn1 new file mode 100644 index 0000000..43b4a9d --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkcs9.asn1 @@ -0,0 +1,29 @@ +-- $Id$ -- + +PKCS9 DEFINITIONS ::= + +BEGIN + +-- The PFX PDU + +id-pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) pkcs-9(9) } + +id-pkcs9-emailAddress OBJECT IDENTIFIER ::= {id-pkcs-9 1 } +id-pkcs9-contentType OBJECT IDENTIFIER ::= {id-pkcs-9 3 } +id-pkcs9-messageDigest OBJECT IDENTIFIER ::= {id-pkcs-9 4 } +id-pkcs9-signingTime OBJECT IDENTIFIER ::= {id-pkcs-9 5 } +id-pkcs9-countersignature OBJECT IDENTIFIER ::= {id-pkcs-9 6 } +id-pkcs9-extReq OBJECT IDENTIFIER ::= {id-pkcs-9 14} + +id-pkcs-9-at-friendlyName OBJECT IDENTIFIER ::= {id-pkcs-9 20} +id-pkcs-9-at-localKeyId OBJECT IDENTIFIER ::= {id-pkcs-9 21} +id-pkcs-9-at-certTypes OBJECT IDENTIFIER ::= {id-pkcs-9 22} +id-pkcs-9-at-certTypes-x509 OBJECT IDENTIFIER ::= {id-pkcs-9-at-certTypes 1} + +PKCS9-BMPString ::= BMPString + +PKCS9-friendlyName ::= SET OF PKCS9-BMPString + +END + diff --git a/third_party/heimdal/lib/asn1/pkinit.asn1 b/third_party/heimdal/lib/asn1/pkinit.asn1 new file mode 100644 index 0000000..99dda00 --- /dev/null +++ b/third_party/heimdal/lib/asn1/pkinit.asn1 @@ -0,0 +1,201 @@ +-- $Id$ -- + +PKINIT DEFINITIONS ::= BEGIN + +IMPORTS EncryptionKey, PrincipalName, Realm, KerberosTime, Checksum, Ticket FROM krb5 + IssuerAndSerialNumber FROM cms + SubjectPublicKeyInfo, AlgorithmIdentifier FROM rfc2459 + HEIM_ANY FROM heim; + +id-pkinit OBJECT IDENTIFIER ::= + { iso (1) org (3) dod (6) internet (1) security (5) + kerberosv5 (2) pkinit (3) } + +id-pkauthdata OBJECT IDENTIFIER ::= { id-pkinit 1 } +id-pkdhkeydata OBJECT IDENTIFIER ::= { id-pkinit 2 } +id-pkrkeydata OBJECT IDENTIFIER ::= { id-pkinit 3 } +id-pkekuoid OBJECT IDENTIFIER ::= { id-pkinit 4 } +id-pkkdcekuoid OBJECT IDENTIFIER ::= { id-pkinit 5 } + +id-heim-eku-pkinit-certlife-is-max-life OBJECT IDENTIFIER ::= + { iso(1) member-body(2) se(752) su(43) heim-pkix(16) 3 } + +id-apple-system-id OBJECT IDENTIFIER ::= { 1 2 840 113635 100 4 4 } + +id-pkinit-kdf OBJECT IDENTIFIER ::= { id-pkinit 6 } +id-pkinit-kdf-ah-sha1 OBJECT IDENTIFIER ::= { id-pkinit-kdf 1 } +id-pkinit-kdf-ah-sha256 OBJECT IDENTIFIER ::= { id-pkinit-kdf 2 } +id-pkinit-kdf-ah-sha512 OBJECT IDENTIFIER ::= { id-pkinit-kdf 3 } + +id-pkinit-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) security(5) kerberosv5(2) + x509-sanan(2) } + +id-pkinit-ms-eku OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) private(4) + enterprise(1) microsoft(311) 20 2 2 } + +id-pkinit-ms-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) private(4) + enterprise(1) microsoft(311) 20 2 3 } + +MS-UPN-SAN ::= UTF8String + +pa-pk-as-req INTEGER ::= 16 +pa-pk-as-rep INTEGER ::= 17 + +td-trusted-certifiers INTEGER ::= 104 +td-invalid-certificates INTEGER ::= 105 +td-dh-parameters INTEGER ::= 109 + +DHNonce ::= OCTET STRING + +KDFAlgorithmId ::= SEQUENCE { + kdf-id [0] OBJECT IDENTIFIER, + ... +} + +TrustedCA ::= SEQUENCE { + caName [0] IMPLICIT OCTET STRING, + certificateSerialNumber [1] INTEGER OPTIONAL, + subjectKeyIdentifier [2] OCTET STRING OPTIONAL, + ... +} + +ExternalPrincipalIdentifier ::= SEQUENCE { + subjectName [0] IMPLICIT OCTET STRING OPTIONAL, + issuerAndSerialNumber [1] IMPLICIT OCTET STRING OPTIONAL, + subjectKeyIdentifier [2] IMPLICIT OCTET STRING OPTIONAL, + ... +} + +ExternalPrincipalIdentifiers ::= SEQUENCE OF ExternalPrincipalIdentifier + +PA-PK-AS-REQ ::= SEQUENCE { + signedAuthPack [0] IMPLICIT OCTET STRING, + trustedCertifiers [1] ExternalPrincipalIdentifiers OPTIONAL, + kdcPkId [2] IMPLICIT OCTET STRING OPTIONAL, + ... +} + +PKAuthenticator ::= SEQUENCE { + cusec [0] INTEGER -- (0..999999) --, + ctime [1] KerberosTime, + nonce [2] INTEGER (0..4294967295), + paChecksum [3] OCTET STRING OPTIONAL, + freshnessToken [4] OCTET STRING OPTIONAL, + ... +} + +AuthPack ::= SEQUENCE { + pkAuthenticator [0] PKAuthenticator, + clientPublicValue [1] SubjectPublicKeyInfo OPTIONAL, + supportedCMSTypes [2] SEQUENCE OF AlgorithmIdentifier OPTIONAL, + clientDHNonce [3] DHNonce OPTIONAL, + ..., + supportedKDFs [4] SEQUENCE OF KDFAlgorithmId OPTIONAL, + ... +} + +TD-TRUSTED-CERTIFIERS ::= ExternalPrincipalIdentifiers +TD-INVALID-CERTIFICATES ::= ExternalPrincipalIdentifiers + +AD-INITIAL-VERIFIED-CAS ::= SEQUENCE OF ExternalPrincipalIdentifier + +DHRepInfo ::= SEQUENCE { + dhSignedData [0] IMPLICIT OCTET STRING, + serverDHNonce [1] DHNonce OPTIONAL, + ..., + kdf [2] KDFAlgorithmId OPTIONAL, + ... +} + +PA-PK-AS-REP ::= CHOICE { + dhInfo [0] DHRepInfo, + encKeyPack [1] IMPLICIT OCTET STRING, + ... +} + +KDCDHKeyInfo ::= SEQUENCE { + subjectPublicKey [0] BIT STRING, + nonce [1] INTEGER (0..4294967295), + dhKeyExpiration [2] KerberosTime OPTIONAL, + ... +} + +ReplyKeyPack ::= SEQUENCE { + replyKey [0] EncryptionKey, + asChecksum [1] Checksum, + ... +} + +TD-DH-PARAMETERS ::= SEQUENCE OF AlgorithmIdentifier + + +-- Windows compat glue -- + +PKAuthenticator-Win2k ::= SEQUENCE { + kdcName [0] PrincipalName, + kdcRealm [1] Realm, + cusec [2] INTEGER (0..4294967295), + ctime [3] KerberosTime, + nonce [4] INTEGER (-2147483648..2147483647) +} + +AuthPack-Win2k ::= SEQUENCE { + pkAuthenticator [0] PKAuthenticator-Win2k, + clientPublicValue [1] SubjectPublicKeyInfo OPTIONAL +} + + +TrustedCA-Win2k ::= CHOICE { + caName [1] HEIM_ANY, + issuerAndSerial [2] IssuerAndSerialNumber +} + +PA-PK-AS-REQ-Win2k ::= SEQUENCE { + signed-auth-pack [0] IMPLICIT OCTET STRING, + trusted-certifiers [2] SEQUENCE OF TrustedCA-Win2k OPTIONAL, + kdc-cert [3] IMPLICIT OCTET STRING OPTIONAL, + encryption-cert [4] IMPLICIT OCTET STRING OPTIONAL +} + +PA-PK-AS-REP-Win2k ::= CHOICE { + dhSignedData [0] IMPLICIT OCTET STRING, + encKeyPack [1] IMPLICIT OCTET STRING +} + +KDCDHKeyInfo-Win2k ::= SEQUENCE { + nonce [0] INTEGER (-2147483648..2147483647), + subjectPublicKey [2] BIT STRING +} + +ReplyKeyPack-Win2k ::= SEQUENCE { + replyKey [0] EncryptionKey, + nonce [1] INTEGER (-2147483648..2147483647), + ... +} + +PA-PK-AS-REP-BTMM ::= SEQUENCE { + dhSignedData [0] HEIM_ANY OPTIONAL, + encKeyPack [1] HEIM_ANY OPTIONAL +} + + +PkinitSP80056AOtherInfo ::= SEQUENCE { + algorithmID AlgorithmIdentifier, + partyUInfo [0] OCTET STRING, + partyVInfo [1] OCTET STRING, + suppPubInfo [2] OCTET STRING OPTIONAL, + suppPrivInfo [3] OCTET STRING OPTIONAL +} + +PkinitSuppPubInfo ::= SEQUENCE { + enctype [0] INTEGER (-2147483648..2147483647), + as-REQ [1] OCTET STRING, + pk-as-rep [2] OCTET STRING, + ticket [3] Ticket, + ... +} + +END diff --git a/third_party/heimdal/lib/asn1/pku2u.asn1 b/third_party/heimdal/lib/asn1/pku2u.asn1 new file mode 100644 index 0000000..ca3a91f --- /dev/null +++ b/third_party/heimdal/lib/asn1/pku2u.asn1 @@ -0,0 +1,30 @@ +-- $Id$ + +PKU2U DEFINITIONS ::= BEGIN + +IMPORTS Checksum FROM krb5 + GeneralName FROM rfc2459; + +GSS_KRB5_FINISHED ::= SEQUENCE { + gss-mic [1] Checksum, + ... +} + +InitiatorName ::= CHOICE { + sanIndex INTEGER (-2147483648..2147483647), + nameNotInCert [0] GeneralName, + ... +} + +TargetName ::= CHOICE { + exportedTargName OCTET STRING, + generalName [0] GeneralName, + ... +} + +InitiatorNameAssertion ::= SEQUENCE { + initiatorName [0] InitiatorName OPTIONAL, + targetName [1] TargetName OPTIONAL +} + +END diff --git a/third_party/heimdal/lib/asn1/rfc2459.asn1 b/third_party/heimdal/lib/asn1/rfc2459.asn1 new file mode 100644 index 0000000..7ceefe3 --- /dev/null +++ b/third_party/heimdal/lib/asn1/rfc2459.asn1 @@ -0,0 +1,1210 @@ +-- $Id$ -- +-- Definitions from RFCs 2459, 3280, 5280 +-- +-- Note that those RFCs come with *two* ASN.1 modules, one being a default- +-- EXPLICIT tagged module, and the other being default-IMPLICIT. Some types +-- are in one module, while others are in the other. Here the two modules +-- are merged into a single default-EXPLICIT tagged module, with IMPLICIT added +-- for all tags for types in the default-IMPLICIT module. + +RFC2459 DEFINITIONS ::= BEGIN + +IMPORTS HEIM_ANY FROM heim + PrincipalName, Realm FROM krb5; + -- For OtherName we really want to also import: + -- KRB5PrincipalName FROM pkinit + -- PermanentIdentifier FROM rfc4043 + -- HardwareModuleName FROM rfc4108; + -- But we can't because that creates circular dependencies. + +Version ::= INTEGER { + rfc3280_version_1(0), + rfc3280_version_2(1), + rfc3280_version_3(2) +} + +id-pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) 1 } +id-pkcs1-rsaEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 1 } +id-pkcs1-md2WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 2 } +id-pkcs1-md5WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 4 } +id-pkcs1-sha1WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 5 } +id-pkcs1-sha256WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 11 } +id-pkcs1-sha384WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 12 } +id-pkcs1-sha512WithRSAEncryption OBJECT IDENTIFIER ::= { id-pkcs-1 13 } + +id-heim-rsa-pkcs1-x509 OBJECT IDENTIFIER ::= { 1 2 752 43 16 1 } + +id-pkcs-2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) 2 } +id-pkcs2-md2 OBJECT IDENTIFIER ::= { id-pkcs-2 2 } +id-pkcs2-md4 OBJECT IDENTIFIER ::= { id-pkcs-2 4 } +id-pkcs2-md5 OBJECT IDENTIFIER ::= { id-pkcs-2 5 } + +id-rsa-digestAlgorithm OBJECT IDENTIFIER ::= +{ iso(1) member-body(2) us(840) rsadsi(113549) 2 } + +id-rsa-digest-md2 OBJECT IDENTIFIER ::= { id-rsa-digestAlgorithm 2 } +id-rsa-digest-md4 OBJECT IDENTIFIER ::= { id-rsa-digestAlgorithm 4 } +id-rsa-digest-md5 OBJECT IDENTIFIER ::= { id-rsa-digestAlgorithm 5 } + +id-pkcs-3 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) 3 } + +id-pkcs3-rc2-cbc OBJECT IDENTIFIER ::= { id-pkcs-3 2 } +id-pkcs3-rc4 OBJECT IDENTIFIER ::= { id-pkcs-3 4 } +id-pkcs3-des-ede3-cbc OBJECT IDENTIFIER ::= { id-pkcs-3 7 } + +id-rsadsi-encalg OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) 3 } + +id-rsadsi-rc2-cbc OBJECT IDENTIFIER ::= { id-rsadsi-encalg 2 } +id-rsadsi-des-ede3-cbc OBJECT IDENTIFIER ::= { id-rsadsi-encalg 7 } + +id-secsig-sha-1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + oiw(14) secsig(3) algorithm(2) 26 } + +id-secsig-sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + oiw(14) secsig(3) algorithm(2) 29 } + +id-nistAlgorithm OBJECT IDENTIFIER ::= { + joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) 4 } + +id-nist-aes-algs OBJECT IDENTIFIER ::= { id-nistAlgorithm 1 } + +id-aes-128-cbc OBJECT IDENTIFIER ::= { id-nist-aes-algs 2 } +id-aes-192-cbc OBJECT IDENTIFIER ::= { id-nist-aes-algs 22 } +id-aes-256-cbc OBJECT IDENTIFIER ::= { id-nist-aes-algs 42 } + +id-nist-sha-algs OBJECT IDENTIFIER ::= { id-nistAlgorithm 2 } + +id-sha256 OBJECT IDENTIFIER ::= { id-nist-sha-algs 1 } +id-sha224 OBJECT IDENTIFIER ::= { id-nist-sha-algs 4 } +id-sha384 OBJECT IDENTIFIER ::= { id-nist-sha-algs 2 } +id-sha512 OBJECT IDENTIFIER ::= { id-nist-sha-algs 3 } + +id-dhpublicnumber OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-x942(10046) + number-type(2) 1 } + +-- ECC + +id-ecPublicKey OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } + +id-ecDH OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) schemes(1) + ecdh(12) } + +id-ecMQV OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) schemes(1) + ecmqv(13) } + +id-ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 4 } + +id-ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 3 } + +id-ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 2 } + +id-ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + ecdsa-with-SHA2(3) 1 } + +id-ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } + +-- some EC group ids + +id-ec-group-secp256r1 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) + prime(1) 7 } + +id-ec-group-secp160r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 8 } + +id-ec-group-secp160r2 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 30 } + +id-ec-group-secp224r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 33 } + +id-ec-group-secp384r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 34 } + +id-ec-group-secp521r1 OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) certicom(132) 0 35 } + +-- DSA + +id-x9-57 OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) ansi-x942(10046) 4 } + +id-dsa OBJECT IDENTIFIER ::= { id-x9-57 1 } +id-dsa-with-sha1 OBJECT IDENTIFIER ::= { id-x9-57 3 } + +-- x.520 names types + +id-x520-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 } + +id-at-commonName OBJECT IDENTIFIER ::= { id-x520-at 3 } +id-at-surname OBJECT IDENTIFIER ::= { id-x520-at 4 } +id-at-serialNumber OBJECT IDENTIFIER ::= { id-x520-at 5 } +id-at-countryName OBJECT IDENTIFIER ::= { id-x520-at 6 } +id-at-localityName OBJECT IDENTIFIER ::= { id-x520-at 7 } +id-at-stateOrProvinceName OBJECT IDENTIFIER ::= { id-x520-at 8 } +id-at-streetAddress OBJECT IDENTIFIER ::= { id-x520-at 9 } +id-at-organizationName OBJECT IDENTIFIER ::= { id-x520-at 10 } +id-at-organizationalUnitName OBJECT IDENTIFIER ::= { id-x520-at 11 } +id-at-title OBJECT IDENTIFIER ::= { id-x520-at 12 } +id-at-description OBJECT IDENTIFIER ::= { id-x520-at 13 } +id-at-name OBJECT IDENTIFIER ::= { id-x520-at 41 } +id-at-givenName OBJECT IDENTIFIER ::= { id-x520-at 42 } +id-at-initials OBJECT IDENTIFIER ::= { id-x520-at 43 } +id-at-generationQualifier OBJECT IDENTIFIER ::= { id-x520-at 44 } +id-at-dnQualifier OBJECT IDENTIFIER ::= { id-x520-at 46 } +id-at-pseudonym OBJECT IDENTIFIER ::= { id-x520-at 65 } +-- RFC 2247 +id-Userid OBJECT IDENTIFIER ::= + { 0 9 2342 19200300 100 1 1 } +id-domainComponent OBJECT IDENTIFIER ::= + { 0 9 2342 19200300 100 1 25 } + +id-at-emailAddress AttributeType ::= + { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 1 } + + + +-- rfc3280 + +id-x509-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters HEIM_ANY OPTIONAL +} + +AttributeType ::= OBJECT IDENTIFIER + +AttributeValue ::= HEIM_ANY + +DirectoryString ::= CHOICE { + ia5String IA5String, + teletexString TeletexString, + printableString PrintableString, + universalString UniversalString, + utf8String UTF8String, + bmpString BMPString +} + +AttributeValues ::= SET OF AttributeValue + +Attribute ::= SEQUENCE { + type AttributeType, + value AttributeValues +} + +AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value DirectoryString +} + +-- RDNs really should be SET OF SingleAttribute per the RFCs, but making that +-- change will affect lib/hx509 code, so we'll wait. The issue is that there +-- is code in lib/hx509 and in lib/asn1/check-gen.c that assumes that the +-- `value` of an rdn is a `DirectoryString` and not an open type. +-- +-- Also, it's really not worth making this change, as a) it will increase the +-- amount of code needed in lib/hx509, and b) it really is useful to be able to +-- assume RDN values are ultimately only strings, c) we don't have any attrs +-- for RDNs that aren't strings, and d) the non-string attributes from TCG that +-- are used in SubjectDirectoryAttributes will never be used here (so we hope). +-- +-- Until we fix this lib/hx509 cannot support name attributes whose type isn't +-- DirectoryString. For example, the UID attribute is broken at this time, as +-- that wants NumericString. +-- +RelativeDistinguishedName ::= SET OF AttributeTypeAndValue -- XXX SingleAttribute + +RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +Name ::= CHOICE { + rdnSequence RDNSequence +} + +CertificateSerialNumber ::= INTEGER + +Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime +} + +Validity ::= SEQUENCE { + notBefore Time, + notAfter Time +} + +UniqueIdentifier ::= BIT STRING + +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING +} + +-- XXX Should be _OTHER-NAME ::= _TYPE-IDENTIFIER +_OTHER-NAME ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type +} + +OtherName{_OTHER-NAME:OtherNameSet} ::= SEQUENCE { + type-id _OTHER-NAME.&id({OtherNameSet}), + value [0] _OTHER-NAME.&Type({OtherNameSet}{@type-id}) +} + +_ATTRIBUTE ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &Type OPTIONAL, + -- &equality-match MATCHING-RULE OPTIONAL, + &minCount INTEGER DEFAULT 1, + &maxCount INTEGER OPTIONAL +} + +SingleAttribute{_ATTRIBUTE:AttrSet} ::= SEQUENCE { + type _ATTRIBUTE.&id({AttrSet}), + value _ATTRIBUTE.&Type({AttrSet}{@type}) +} + +AttributeSet{_ATTRIBUTE:AttrSet} ::= SEQUENCE { + type _ATTRIBUTE.&id({AttrSet}), + values SET --SIZE (1..MAX)-- OF _ATTRIBUTE.&Type({AttrSet}{@type}) +} + +_EXTENSION ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &ExtnType, + &Critical BOOLEAN DEFAULT FALSE +} + +Extension{_EXTENSION:ExtensionSet} ::= SEQUENCE { + extnID _EXTENSION.&id({ExtensionSet}), + critical BOOLEAN +-- (EXTENSION.&Critical({ExtensionSet}{@extnID})) + DEFAULT FALSE, + extnValue OCTET STRING (CONTAINING + _EXTENSION.&ExtnType({ExtensionSet}{@extnID})) +} + +Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + +TBSCertificate ::= SEQUENCE { + version [0] Version OPTIONAL, -- EXPLICIT nnn DEFAULT 1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT BIT STRING -- UniqueIdentifier -- OPTIONAL, + -- If present, version shall be v2 or v3 + subjectUniqueID [2] IMPLICIT BIT STRING -- UniqueIdentifier -- OPTIONAL, + -- If present, version shall be v2 or v3 + extensions [3] EXPLICIT Extensions OPTIONAL + -- If present, version shall be v3 +} + +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING +} + +Certificates ::= SEQUENCE OF Certificate + +ValidationParms ::= SEQUENCE { + seed BIT STRING, + pgenCounter INTEGER +} + +DomainParameters ::= SEQUENCE { + p INTEGER, -- odd prime, p=jq +1 + g INTEGER, -- generator, g + q INTEGER OPTIONAL, -- factor of p-1 + j INTEGER OPTIONAL, -- subgroup factor + validationParms ValidationParms OPTIONAL -- ValidationParms +} + +-- As defined by PKCS3 +DHParameter ::= SEQUENCE { + prime INTEGER, -- odd prime, p=jq +1 + base INTEGER, -- generator, g + privateValueLength INTEGER OPTIONAL +} + +DHPublicKey ::= INTEGER + +GeneralName ::= CHOICE { + otherName [0] IMPLICIT OtherName, + rfc822Name [1] IMPLICIT IA5String, + dNSName [2] IMPLICIT IA5String, +-- x400Address [3] IMPLICIT ORAddress,-- + directoryName [4] IMPLICIT Name, +-- ediPartyName [5] IMPLICIT EDIPartyName, -- + uniformResourceIdentifier [6] IMPLICIT IA5String, + iPAddress [7] IMPLICIT OCTET STRING, + registeredID [8] IMPLICIT OBJECT IDENTIFIER +} + +GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + +id-x509-ce-keyUsage OBJECT IDENTIFIER ::= { id-x509-ce 15 } + +KeyUsage ::= BIT STRING { + digitalSignature (0), + nonRepudiation (1), + keyEncipherment (2), + dataEncipherment (3), + keyAgreement (4), + keyCertSign (5), + cRLSign (6), + encipherOnly (7), + decipherOnly (8) +} + +-- private key usage period extension OID and syntax + +PrivateKeyUsagePeriod ::= SEQUENCE { + notBefore [0] IMPLICIT GeneralizedTime OPTIONAL, + notAfter [1] IMPLICIT GeneralizedTime OPTIONAL + -- either notBefore or notAfter MUST be present +} + +-- certificate policies extension OID and syntax + +_POLICYQUALIFIERINFO ::= CLASS { -- Heimdal extension + &id OBJECT IDENTIFIER UNIQUE, + &Type +} + +CertPolicyId ::= OBJECT IDENTIFIER +PolicyQualifierId ::= OBJECT IDENTIFIER -- ( id-qt-cps | id-qt-unotice ) + +PolicyQualifierInfo{_POLICYQUALIFIERINFO:PolicyQualifierSet} ::= SEQUENCE { + policyQualifierId _POLICYQUALIFIERINFO.&id({PolicyQualifierSet}), + qualifier _POLICYQUALIFIERINFO.&Type({PolicyQualifierSet}{@policyQualifierId}) +} + +PolicyQualifierInfos ::= SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo + +PolicyInformation ::= SEQUENCE { + policyIdentifier CertPolicyId, + policyQualifiers PolicyQualifierInfos OPTIONAL +} + +CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + +-- CPS pointer qualifier + +CPSuri ::= IA5String + +-- user notice qualifier + +DisplayText ::= CHOICE { + ia5String IA5String, --(SIZE (1..200)) + visibleString VisibleString, --(SIZE (1..200)) + bmpString BMPString, --(SIZE (1..200)) + utf8String UTF8String --(SIZE (1..200)) +} + +NoticeReference ::= SEQUENCE { + organization DisplayText, + noticeNumbers SEQUENCE OF INTEGER +} + +UserNotice ::= SEQUENCE { + noticeRef NoticeReference OPTIONAL, + explicitText DisplayText OPTIONAL +} + +-- policy mapping extension OID and syntax + +PolicyMapping ::= SEQUENCE { + issuerDomainPolicy CertPolicyId, + subjectDomainPolicy CertPolicyId +} + +PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF PolicyMapping + +-- subject key identifier OID and syntax + +id-x509-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-x509-ce 35 } + +KeyIdentifier ::= OCTET STRING + +AuthorityKeyIdentifier ::= SEQUENCE { + keyIdentifier [0] IMPLICIT OCTET STRING OPTIONAL, + authorityCertIssuer [1] IMPLICIT -- GeneralName -- + SEQUENCE -- SIZE (1..MAX) -- OF GeneralName OPTIONAL, + authorityCertSerialNumber [2] IMPLICIT INTEGER OPTIONAL +} + +id-x509-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-x509-ce 14 } + +SubjectKeyIdentifier ::= KeyIdentifier + +id-x509-ce-basicConstraints OBJECT IDENTIFIER ::= { id-x509-ce 19 } + +BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..4294967295) OPTIONAL +} + +id-x509-ce-nameConstraints OBJECT IDENTIFIER ::= { id-x509-ce 30 } + +BaseDistance ::= INTEGER (0..4294967295) + +GeneralSubtree ::= SEQUENCE { + base GeneralName, + minimum [0] IMPLICIT BaseDistance DEFAULT 0, + maximum [1] IMPLICIT BaseDistance OPTIONAL +} + +GeneralSubtrees ::= SEQUENCE -- SIZE (1..MAX) -- OF GeneralSubtree + +NameConstraints ::= SEQUENCE { + permittedSubtrees [0] IMPLICIT -- GeneralSubtrees -- SEQUENCE OF GeneralSubtree OPTIONAL, + excludedSubtrees [1] IMPLICIT -- GeneralSubtrees -- SEQUENCE OF GeneralSubtree OPTIONAL +} + +id-x509-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::= { id-x509-ce 16 } +id-x509-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-x509-ce 32 } +id-x509-ce-certificatePolicies-anyPolicy OBJECT IDENTIFIER ::= { id-x509-ce-certificatePolicies 0 } +id-x509-ce-policyMappings OBJECT IDENTIFIER ::= { id-x509-ce 33 } +id-x509-ce-subjectAltName OBJECT IDENTIFIER ::= { id-x509-ce 17 } +id-x509-ce-issuerAltName OBJECT IDENTIFIER ::= { id-x509-ce 18 } +id-x509-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-x509-ce 9 } +id-x509-ce-policyConstraints OBJECT IDENTIFIER ::= { id-x509-ce 36 } + +id-x509-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-x509-ce 37} +id-x509-ce-anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-x509-ce-extKeyUsage 0 } + +ExtKeyUsage ::= SEQUENCE OF OBJECT IDENTIFIER + +id-x509-ce-cRLReasons OBJECT IDENTIFIER ::= { id-x509-ce 21 } +id-x509-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-x509-ce 31 } +id-x509-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-x509-ce 27 } +id-x509-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-x509-ce 28 } +id-x509-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-x509-ce 23 } +id-x509-ce-invalidityDate OBJECT IDENTIFIER ::= { id-x509-ce 24 } +id-x509-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-x509-ce 29 } +id-x509-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-x509-ce 54 } + +-- Heimdal extension +id-heim-ce-pkinit-princ-max-life OBJECT IDENTIFIER ::= + { iso(1) member-body(2) se(752) su(43) heim-pkix(16) 4 } + + +DistributionPointReasonFlags ::= BIT STRING { + unused (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + privilegeWithdrawn (7), + aACompromise (8) +} + +DistributionPointName ::= CHOICE { + fullName [0] IMPLICIT -- GeneralNames -- SEQUENCE SIZE (1..MAX) OF GeneralName, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName +} + +DistributionPoint ::= SEQUENCE { + distributionPoint [0] IMPLICIT DistributionPointName OPTIONAL, + reasons [1] IMPLICIT DistributionPointReasonFlags OPTIONAL, + cRLIssuer [2] IMPLICIT GeneralNames OPTIONAL +} + +CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + + +-- rfc3279 + +DSASigValue ::= SEQUENCE { + r INTEGER, + s INTEGER +} + +DSAPublicKey ::= INTEGER + +DSAParams ::= SEQUENCE { + p INTEGER, + q INTEGER, + g INTEGER +} + +-- draft-ietf-pkix-ecc-subpubkeyinfo-11 + +ECPoint ::= OCTET STRING + +ECParameters ::= CHOICE { + namedCurve OBJECT IDENTIFIER + -- implicitCurve NULL + -- specifiedCurve SpecifiedECDomain +} + +ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} + +-- really pkcs1 + +RSAPublicKey ::= SEQUENCE { + modulus INTEGER, -- n + publicExponent INTEGER -- e +} + +RSAPrivateKey ::= SEQUENCE { + version INTEGER (0..4294967295), + modulus INTEGER, -- n + publicExponent INTEGER, -- e + privateExponent INTEGER, -- d + prime1 INTEGER, -- p + prime2 INTEGER, -- q + exponent1 INTEGER, -- d mod (p-1) + exponent2 INTEGER, -- d mod (q-1) + coefficient INTEGER -- (inverse of q) mod p +} + +DigestInfo ::= SEQUENCE { + digestAlgorithm AlgorithmIdentifier, + digest OCTET STRING +} + +-- some ms ext + +-- szOID_ENROLL_CERTTYPE_EXTENSION "1.3.6.1.4.1.311.20.2" is Encoded as a + +-- UNICODESTRING (0x1E tag) + +-- szOID_CERTIFICATE_TEMPLATE "1.3.6.1.4.1.311.21.7" is Encoded as: + +-- TemplateVersion ::= INTEGER (0..4294967295) + +-- CertificateTemplate ::= SEQUENCE { +-- templateID OBJECT IDENTIFIER, +-- templateMajorVersion TemplateVersion, +-- templateMinorVersion TemplateVersion OPTIONAL +-- } + + +-- +-- CRL +-- + +TBSCRLCertList ::= SEQUENCE { + version Version OPTIONAL, -- if present, MUST be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, MUST be v2 + } OPTIONAL, + crlExtensions [0] EXPLICIT Extensions OPTIONAL + -- if present, MUST be v2 +} + + +CRLCertificateList ::= SEQUENCE { + tbsCertList TBSCRLCertList, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING +} + +id-x509-ce-cRLNumber OBJECT IDENTIFIER ::= { id-x509-ce 20 } +id-x509-ce-freshestCRL OBJECT IDENTIFIER ::= { id-x509-ce 46 } +id-x509-ce-cRLReason OBJECT IDENTIFIER ::= { id-x509-ce 21 } + +CRLReason ::= ENUMERATED { + unspecified (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + removeFromCRL (8), + privilegeWithdrawn (9), + aACompromise (10) +} + +PKIXXmppAddr ::= UTF8String + +SRVName ::= IA5String -- (SIZE (1..MAX)), but our compiler doesn't do that + +id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + dod(6) internet(1) security(5) mechanisms(5) pkix(7) } + +id-pkix-on OBJECT IDENTIFIER ::= { id-pkix 8 } +id-pkix-on-xmppAddr OBJECT IDENTIFIER ::= { id-pkix-on 5 } +id-pkix-on-dnsSRV OBJECT IDENTIFIER ::= { id-pkix-on 7 } + +-- From RFC4108 +id-pkix-on-hardwareModuleName OBJECT IDENTIFIER ::= { id-pkix-on 4 } +HardwareModuleName ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING +} + +-- XXX Not really the right name +id-pkix-on-pkinit-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) security(5) kerberosv5(2) + x509-sanan(2) } +KRB5PrincipalName ::= SEQUENCE { + realm [0] Realm, + principalName [1] PrincipalName +} + +-- From RFC4043: +-- Permanent identifier Object Identifier and Syntax +id-pkix-on-permanentIdentifier OBJECT IDENTIFIER ::= { id-pkix-on 3 } + +PermanentIdentifier ::= SEQUENCE { + identifierValue UTF8String OPTIONAL, + -- if absent, use the serialNumber attribute + -- if there is a single such attribute present + -- in the subject DN + assigner OBJECT IDENTIFIER OPTIONAL + -- if absent, the assigner is + -- the certificate issuer +} + +-- EKUs +id-pkix-kp OBJECT IDENTIFIER ::= { id-pkix 3 } +id-pkix-kp-serverAuth OBJECT IDENTIFIER ::= { id-pkix-kp 1 } +id-pkix-kp-clientAuth OBJECT IDENTIFIER ::= { id-pkix-kp 2 } +id-pkix-kp-codeSigning OBJECT IDENTIFIER ::= { id-pkix-kp 3 } +id-pkix-kp-emailProtection OBJECT IDENTIFIER ::= { id-pkix-kp 4 } +id-pkix-kp-ipsecEndSystem OBJECT IDENTIFIER ::= { id-pkix-kp 5 } +id-pkix-kp-ipsecTunnel OBJECT IDENTIFIER ::= { id-pkix-kp 6 } +id-pkix-kp-ipsecUser OBJECT IDENTIFIER ::= { id-pkix-kp 7 } +id-pkix-kp-timeStamping OBJECT IDENTIFIER ::= { id-pkix-kp 8 } +id-pkix-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-pkix-kp 9 } +-- The following are taken from RFC7299 and others +id-pkix-kp-DVCS OBJECT IDENTIFIER ::= { id-pkix-kp 10 } +id-pkix-kp-ipsecIKE OBJECT IDENTIFIER ::= { id-pkix-kp 17 } +id-pkix-kp-capwapAC OBJECT IDENTIFIER ::= { id-pkix-kp 18 } +id-pkix-kp-capwapWTP OBJECT IDENTIFIER ::= { id-pkix-kp 19 } +id-pkix-kp-sipDomain OBJECT IDENTIFIER ::= { id-pkix-kp 20 } -- RFC5924 +id-pkix-kp-secureShellClient OBJECT IDENTIFIER ::= { id-pkix-kp 21 } +id-pkix-kp-secureShellServer OBJECT IDENTIFIER ::= { id-pkix-kp 22 } +id-pkix-kp-sendRouter OBJECT IDENTIFIER ::= { id-pkix-kp 23 } +id-pkix-kp-sendProxiedRouter OBJECT IDENTIFIER ::= { id-pkix-kp 24 } +id-pkix-kp-sendOwner OBJECT IDENTIFIER ::= { id-pkix-kp 25 } +id-pkix-kp-sendProxiedOwner OBJECT IDENTIFIER ::= { id-pkix-kp 26 } +id-pkix-kp-cmcCA OBJECT IDENTIFIER ::= { id-pkix-kp 27 } -- RFC6402 +id-pkix-kp-cmcRA OBJECT IDENTIFIER ::= { id-pkix-kp 28 } -- RFC6402 +id-pkix-kp-cmcArchive OBJECT IDENTIFIER ::= { id-pkix-kp 29 } -- RFC6402 +id-pkix-kp-bgpsec-router OBJECT IDENTIFIER ::= { id-pkix-kp 30 } -- RFC8209 +-- The following are MSFT EKUs taken from OpenSSL +id-msft OBJECT IDENTIFIER ::= { 1 3 6 1 4 1 311 } +id-msft-kp-msCodeInd OBJECT IDENTIFIER ::= { id-msft 2 1 21 } +id-msft-kp-msCodeCom OBJECT IDENTIFIER ::= { id-msft 2 1 22 } +id-msft-kp-msCTLSign OBJECT IDENTIFIER ::= { id-msft 10 3 1 } +id-msft-kp-msSGC OBJECT IDENTIFIER ::= { id-msft 10 3 3 } +id-msft-kp-msEFS OBJECT IDENTIFIER ::= { id-msft 10 3 4 } +id-msft-kp-msSmartcardLogin OBJECT IDENTIFIER ::= { id-msft 20 2 2 } +id-msft-kp-msUPN OBJECT IDENTIFIER ::= { id-msft 20 2 3 } + +id-pkix-pe OBJECT IDENTIFIER ::= { id-pkix 1 } +id-pkix-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pkix-pe 1 } + +AccessDescription ::= SEQUENCE { + accessMethod OBJECT IDENTIFIER, + accessLocation GeneralName +} + +AuthorityInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF AccessDescription + +-- RFC 3820 Proxy Certificate Profile + +id-pkix-pe-proxyCertInfo OBJECT IDENTIFIER ::= { id-pkix-pe 14 } + +id-pkix-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pkix-pe 11 } + +SubjectInfoAccessSyntax ::= + SEQUENCE SIZE (1..MAX) OF AccessDescription + +id-pkix-ppl OBJECT IDENTIFIER ::= { id-pkix 21 } + +id-pkix-ppl-anyLanguage OBJECT IDENTIFIER ::= { id-pkix-ppl 0 } +id-pkix-ppl-inheritAll OBJECT IDENTIFIER ::= { id-pkix-ppl 1 } +id-pkix-ppl-independent OBJECT IDENTIFIER ::= { id-pkix-ppl 2 } + +ProxyPolicy ::= SEQUENCE { + policyLanguage OBJECT IDENTIFIER, + policy OCTET STRING OPTIONAL +} + +ProxyCertInfo ::= SEQUENCE { + pCPathLenConstraint INTEGER (0..4294967295) OPTIONAL, -- really MAX + proxyPolicy ProxyPolicy +} + +-- TCG contents: + +-- See tcg.asn1 for commentary. + +--TCG specific OIDs +tcg OBJECT IDENTIFIER ::= {joint-iso-itu-t(2) international-organizations(23) tcg(133)} +tcg-attribute OBJECT IDENTIFIER ::= {tcg 2} +tcg-kp OBJECT IDENTIFIER ::= {tcg 8} + +--TCG Attribute OIDs +tcg-at-tpmManufacturer OBJECT IDENTIFIER ::= {tcg-attribute 1} +tcg-at-tpmModel OBJECT IDENTIFIER ::= {tcg-attribute 2} +tcg-at-tpmVersion OBJECT IDENTIFIER ::= {tcg-attribute 3} +tcg-at-tpmSpecification OBJECT IDENTIFIER ::= {tcg-attribute 16} +tcg-at-tpmSecurityAssertions OBJECT IDENTIFIER ::= {tcg-attribute 18} + +--TCG Attribute objects +at-TPMSecurityAssertions _ATTRIBUTE ::= { &Type TPMSecurityAssertions, &id tcg-at-tpmSecurityAssertions } +at-TPMManufacturer _ATTRIBUTE ::= { &Type AliasUTF8String, --(SIZE (1..STRMAX))-- &id tcg-at-tpmManufacturer } +at-TPMModel _ATTRIBUTE ::= { &Type AliasUTF8String, --(SIZE (1..STRMAX))-- &id tcg-at-tpmModel } +at-TPMVersion _ATTRIBUTE ::= { &Type AliasUTF8String, --(SIZE (1..STRMAX))-- &id tcg-at-tpmVersion } +at-TPMSpecification _ATTRIBUTE ::= { &Type TPMSpecification, &id tcg-at-tpmSpecification } + +--TCG Extended Key Usage OIDs +tcg-kp-EKCertificate OBJECT IDENTIFIER ::= {tcg-kp 1} + +-- OIDs not in the module in TCG_IWG_EKCredentialProfile_v2p3_r2_pub but in +-- TCG_IWG_DevID_v1r2_02dec2020 (missing arc names not mentioned in the TCG +-- specs): +tcg-tpm20 OBJECT IDENTIFIER ::= {tcg 1 2} -- this OID is not named in the TCG specs +tcg-on-ekPermIdSha256 OBJECT IDENTIFIER ::= {tcg 12 1} -- assigner value for PermanentIdentifier SAN +tcg-cap-verifiedTPMResidency OBJECT IDENTIFIER ::= {tcg 11 1 1} -- policy OID +tcg-cap-verifiedTPMFixed OBJECT IDENTIFIER ::= {tcg 11 1 2} -- policy OID +tcg-cap-verifiedTPMRestricted OBJECT IDENTIFIER ::= {tcg 11 1 3} -- policy OID + +EKGenerationType ::= ENUMERATED { + ekgt-internal (0), + ekgt-injected (1), + ekgt-internalRevocable(2), + ekgt-injectedRevocable(3) +} +EKGenerationLocation ::= ENUMERATED { + tpmManufacturer (0), + platformManufacturer (1), + ekCertSigner (2) +} +EKCertificateGenerationLocation ::= EKGenerationLocation -- XXX +EvaluationAssuranceLevel ::= ENUMERATED { + ealevell (1), + ealevel2 (2), + ealevel3 (3), + ealevel4 (4), + ealevel5 (5), + ealevel6 (6), + ealevel7 (7) +} +SecurityLevel ::= ENUMERATED { + sllevel1 (1), + sllevel2 (2), + sllevel3 (3), + sllevel4 (4) +} +StrengthOfFunction ::= ENUMERATED { + sof-basic (0), + sof-medium (1), + sof-high (2) +} +URIReference ::= SEQUENCE { + uniformResourceIdentifier IA5String, -- (SIZE (1..URIMAX)) + hashAlgorithm AlgorithmIdentifier OPTIONAL, + hashValue BIT STRING OPTIONAL +} +EvaluationStatus ::= ENUMERATED { + designedToMeet (0), + evaluationInProgress (1), + evaluationCompleted (2) +} + +--tcg specification attributes for tpm +TPMSpecification ::= SEQUENCE { + family UTF8String, -- (SIZE (1..STRMAX)) + level INTEGER (0..4294967295), + revision INTEGER (0..4294967295), + ... +} + + +--common criteria evaluation +CommonCriteriaMeasures ::= SEQUENCE { + version IA5String, -- (SIZE (1..STRMAX)) “2.2” or “3.1”;future syntax defined by CC + assurancelevel EvaluationAssuranceLevel, + evaluationStatus EvaluationStatus, + plus BOOLEAN DEFAULT FALSE, + strengthOfFunction [0] IMPLICIT StrengthOfFunction OPTIONAL, + profileOid [1] IMPLICIT OBJECT IDENTIFIER OPTIONAL, + profileUri [2] IMPLICIT URIReference OPTIONAL, + targetOid [3] IMPLICIT OBJECT IDENTIFIER OPTIONAL, + targetUri [4] IMPLICIT URIReference OPTIONAL, + ... +} + +--fips evaluation +FIPSLevel ::= SEQUENCE { + version IA5String, -- (SIZE (1..STRMAX)) “140-1” or “140-2” + level SecurityLevel, + plus BOOLEAN DEFAULT FALSE, + ... +} + +--tpm security assertions +TPMVersion ::= INTEGER { tpm-v1(0) } +TPMSecurityAssertions ::= SEQUENCE { + version TPMVersion DEFAULT 0, -- v1 + fieldUpgradable BOOLEAN DEFAULT FALSE, + -- The TCG EK cert profile spec says all these context tags are IMPLICIT, + -- but samples in the field have them as EXPLICIT. + ekGenerationType [0] EXPLICIT EKGenerationType OPTIONAL, + ekGenerationLocation [1] EXPLICIT EKGenerationLocation OPTIONAL, + ekCertificateGenerationLocation [2] EXPLICIT EKCertificateGenerationLocation OPTIONAL, + ccInfo [3] EXPLICIT CommonCriteriaMeasures OPTIONAL, + fipsLevel [4] EXPLICIT FIPSLevel OPTIONAL, + iso9000Certified [5] EXPLICIT BOOLEAN DEFAULT FALSE, + iso9000Uri IA5String OPTIONAL, -- (SIZE (1..URIMAX)) + ... +} + +-- Back to OtherName, SingleAttribute, AttributeSet, and Extension + +-- XXX Not really the right name for this OID: +id-pkix-on-pkinit-ms-san OBJECT IDENTIFIER ::= + { iso(1) org(3) dod(6) internet(1) private(4) + enterprise(1) microsoft(311) 20 2 3 } + +-- XXX Work around bug (where we don't know the names of universal types in the +-- template backend) by creating aliases for universal types we use in IOS +-- objects. +AliasUTF8String ::= UTF8String +AliasIA5String ::= UTF8String +AliasPrintableString ::= PrintableString +on-xmppAddr _OTHER-NAME ::= { &id id-pkix-on-xmppAddr, &Type AliasUTF8String } +on-dnsSRV _OTHER-NAME ::= { &id id-pkix-on-dnsSRV, &Type AliasIA5String } +on-hardwareModuleName _OTHER-NAME ::= { + &id id-pkix-on-hardwareModuleName, + &Type HardwareModuleName +} +on-permanentIdentifier _OTHER-NAME ::= { + &id id-pkix-on-permanentIdentifier, + &Type PermanentIdentifier +} +on-krb5PrincipalName _OTHER-NAME ::= { + &id id-pkix-on-pkinit-san, + &Type KRB5PrincipalName +} +on-pkinit-ms-san _OTHER-NAME ::= { + &id id-pkix-on-pkinit-ms-san, + &Type AliasUTF8String +} + +KnownOtherNameTypes _OTHER-NAME ::= { + on-xmppAddr + | on-dnsSRV + | on-hardwareModuleName + | on-permanentIdentifier + | on-krb5PrincipalName + | on-pkinit-ms-san +} + +OtherName ::= OtherName{KnownOtherNameTypes} + +X520name ::= DirectoryString --{ub-name} +X520CommonName ::= DirectoryString --{ub-common-name} +X520LocalityName ::= DirectoryString --{ub-locality-name} +X520OrganizationName ::= DirectoryString --{ub-organization-name} +X520StateOrProvinceName ::= DirectoryString --{ub-state-name} +X520OrganizationalUnitName ::= DirectoryString --{ub-organizational-unit-name} + +at-name _ATTRIBUTE ::= { &Type X520name, &id id-at-name } +at-surname _ATTRIBUTE ::= { &Type X520name, &id id-at-surname } +at-givenName _ATTRIBUTE ::= { &Type X520name, &id id-at-givenName } +at-initials _ATTRIBUTE ::= { &Type X520name, &id id-at-initials } +at-generationQualifier _ATTRIBUTE ::= { &Type X520name, &id id-at-generationQualifier } +at-x520CommonName _ATTRIBUTE ::= {&Type X520CommonName, &id id-at-commonName } +at-x520LocalityName _ATTRIBUTE ::= { &Type X520LocalityName, &id id-at-localityName } +at-x520StateOrProvinceName _ATTRIBUTE ::= { &Type DirectoryString --{ub-state-name}--, &id id-at-stateOrProvinceName } +at-x520OrganizationName _ATTRIBUTE ::= { &Type DirectoryString --{ub-organization-name}--, &id id-at-organizationName } +at-x520OrganizationalUnitName _ATTRIBUTE ::= { &Type DirectoryString --{ub-organizational-unit-name}--, &id id-at-organizationalUnitName } +at-x520Title _ATTRIBUTE ::= { &Type DirectoryString --{ub-title}--, &id id-at-title } +at-x520dnQualifier _ATTRIBUTE ::= { &Type AliasPrintableString, &id id-at-dnQualifier } +at-x520countryName _ATTRIBUTE ::= { &Type AliasPrintableString --(SIZE (2))--, &id id-at-countryName } +at-x520SerialNumber _ATTRIBUTE ::= {&Type AliasPrintableString --(SIZE (1..ub-serial-number))--, &id id-at-serialNumber } +at-x520Pseudonym _ATTRIBUTE ::= { &Type DirectoryString --{ub-pseudonym}--, &id id-at-pseudonym } +at-domainComponent _ATTRIBUTE ::= { &Type AliasIA5String, &id id-domainComponent } +at-emailAddress _ATTRIBUTE ::= { &Type AliasIA5String --(SIZE (1..ub-emailaddress-length))--, &id id-at-emailAddress } + +SupportedAttributes _ATTRIBUTE ::= { + at-name + | at-surname + | at-givenName + | at-initials + | at-generationQualifier + | at-x520CommonName + | at-x520LocalityName + | at-x520StateOrProvinceName + | at-x520OrganizationName + | at-x520OrganizationalUnitName + | at-x520Title + | at-x520dnQualifier + | at-x520countryName + | at-x520SerialNumber + | at-x520Pseudonym + | at-domainComponent + | at-emailAddress + | at-TPMSecurityAssertions + | at-TPMManufacturer + | at-TPMModel + | at-TPMVersion + | at-TPMSpecification +} + +SingleAttribute ::= SingleAttribute{SupportedAttributes} +AttributeSet ::= AttributeSet{SupportedAttributes} +SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF AttributeSet + +ext-AuthorityKeyIdentifier _EXTENSION ::= { + &id id-x509-ce-authorityKeyIdentifier, + &Critical FALSE, + &ExtnType AuthorityKeyIdentifier +} +ext-KeyUsage _EXTENSION ::= { + &id id-x509-ce-keyUsage, + &Critical FALSE, + &ExtnType KeyUsage +} +ext-SubjectKeyIdentifier _EXTENSION ::= { + &id id-x509-ce-subjectKeyIdentifier, + &Critical FALSE, + &ExtnType SubjectKeyIdentifier +} +ext-PrivateKeyUsagePeriod _EXTENSION ::= { + &id id-x509-ce-privateKeyUsagePeriod, + &Critical FALSE, + &ExtnType PrivateKeyUsagePeriod +} +ext-CertificatePolicies _EXTENSION ::= { + &id id-x509-ce-certificatePolicies, + &Critical FALSE, + &ExtnType CertificatePolicies +} +ext-PolicyMappings _EXTENSION ::= { + &id id-x509-ce-policyMappings, + &Critical FALSE, + &ExtnType PolicyMappings +} +ext-SubjectAltName _EXTENSION ::= { + &id id-x509-ce-subjectAltName, + &Critical FALSE, + &ExtnType GeneralNames +} +ext-IssuerAltName _EXTENSION ::= { + &id id-x509-ce-issuerAltName, + &Critical FALSE, + &ExtnType GeneralNames +} +ext-SubjectDirectoryAttributes _EXTENSION ::= { + &id id-x509-ce-subjectDirectoryAttributes, + &Critical FALSE, + &ExtnType SubjectDirectoryAttributes +} +ext-BasicConstraints _EXTENSION ::= { + &id id-x509-ce-basicConstraints, + &Critical FALSE, + &ExtnType BasicConstraints +} +ext-NameConstraints _EXTENSION ::= { + &id id-x509-ce-nameConstraints, + &Critical FALSE, + &ExtnType NameConstraints +} +SkipCerts ::= INTEGER (0..4294967295) +PolicyConstraints ::= SEQUENCE { + requireExplicitPolicy [0] IMPLICIT SkipCerts OPTIONAL, + inhibitPolicyMapping [1] IMPLICIT SkipCerts OPTIONAL +} +ext-PolicyConstraints _EXTENSION ::= { + &id id-x509-ce-policyConstraints, + &Critical FALSE, + &ExtnType PolicyConstraints +} +ext-ExtKeyUsage _EXTENSION ::= { + &id id-x509-ce-extKeyUsage, + &Critical FALSE, + &ExtnType ExtKeyUsage +} +ext-CRLDistributionPoints _EXTENSION ::= { + &id id-x509-ce-cRLDistributionPoints, + &Critical FALSE, + &ExtnType CRLDistributionPoints +} +ext-InhibitAnyPolicy _EXTENSION ::= { + &id id-x509-ce-inhibitAnyPolicy, + &Critical FALSE, + &ExtnType SkipCerts +} +ext-FreshestCRL _EXTENSION ::= { + &id id-x509-ce-freshestCRL, + &Critical FALSE, + &ExtnType CRLDistributionPoints +} +ext-AuthorityInfoAccess _EXTENSION ::= { + &id id-pkix-pe-authorityInfoAccess, + &Critical FALSE, + &ExtnType AuthorityInfoAccessSyntax +} +ext-SubjectInfoAccessSyntax _EXTENSION ::= { + &id id-pkix-pe-subjectInfoAccess, + &Critical FALSE, + &ExtnType SubjectInfoAccessSyntax +} +ext-ProxyCertInfo _EXTENSION ::= { + &id id-pkix-pe-proxyCertInfo, + &Critical FALSE, + &ExtnType ProxyCertInfo +} +HeimPkinitPrincMaxLifeSecs ::= INTEGER (0..4294967295) +ext-HeimPkinitPrincMaxLife _EXTENSION ::= { + &id id-heim-ce-pkinit-princ-max-life, + &Critical FALSE, + &ExtnType HeimPkinitPrincMaxLifeSecs +} +CertExtensions _EXTENSION ::= { + ext-AuthorityKeyIdentifier + | ext-SubjectKeyIdentifier + | ext-KeyUsage + | ext-PrivateKeyUsagePeriod + | ext-CertificatePolicies + | ext-PolicyMappings + | ext-SubjectAltName + | ext-IssuerAltName + | ext-SubjectDirectoryAttributes + | ext-BasicConstraints + | ext-NameConstraints + | ext-PolicyConstraints + | ext-ExtKeyUsage + | ext-CRLDistributionPoints + | ext-InhibitAnyPolicy + | ext-FreshestCRL + | ext-AuthorityInfoAccess + | ext-SubjectInfoAccessSyntax + | ext-ProxyCertInfo + | ext-HeimPkinitPrincMaxLife +} + +Extension ::= Extension { CertExtensions } + +--- U.S. Federal PKI Common Policy Framework +-- Card Authentication key +id-uspkicommon-card-id OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 6 6 } +id-uspkicommon-piv-interim OBJECT IDENTIFIER ::= { 2 16 840 1 101 3 6 9 1 } + +--- Netscape extensions + +id-netscape OBJECT IDENTIFIER ::= + { joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730) } +id-netscape-cert-comment OBJECT IDENTIFIER ::= { id-netscape 1 13 } + +--- MS extensions + +id-ms-cert-enroll-domaincontroller OBJECT IDENTIFIER ::= + { 1 3 6 1 4 1 311 20 2 } + +-- This is a duplicate of id-pkix-kp-clientAuth +-- id-ms-client-authentication OBJECT IDENTIFIER ::= +-- { 1 3 6 1 5 5 7 3 2 } + +-- DER:1e:20:00:44:00:6f:00:6d:00:61:00:69:00:6e:00:43:00:6f:00:6e:00:74:00:72:00:6f:00:6c:00:6c:00:65:00:72 + +-- Upper bounds: + +ub-name INTEGER ::= 32768 +ub-common-name INTEGER ::= 64 +ub-locality-name INTEGER ::= 128 +ub-state-name INTEGER ::= 128 +ub-organization-name INTEGER ::= 64 +ub-organizational-unit-name INTEGER ::= 64 +ub-title INTEGER ::= 64 +ub-serial-number INTEGER ::= 64 +ub-match INTEGER ::= 128 +ub-emailaddress-length INTEGER ::= 255 +ub-common-name-length INTEGER ::= 64 +ub-country-name-alpha-length INTEGER ::= 2 +ub-country-name-numeric-length INTEGER ::= 3 +ub-domain-defined-attributes INTEGER ::= 4 +ub-domain-defined-attribute-type-length INTEGER ::= 8 +ub-domain-defined-attribute-value-length INTEGER ::= 128 +ub-domain-name-length INTEGER ::= 16 +ub-extension-attributes INTEGER ::= 256 +ub-e163-4-number-length INTEGER ::= 15 +ub-e163-4-sub-address-length INTEGER ::= 40 +ub-generation-qualifier-length INTEGER ::= 3 +ub-given-name-length INTEGER ::= 16 +ub-initials-length INTEGER ::= 5 +ub-integer-options INTEGER ::= 256 +ub-numeric-user-id-length INTEGER ::= 32 +ub-organization-name-length INTEGER ::= 64 +ub-organizational-unit-name-length INTEGER ::= 32 +ub-organizational-units INTEGER ::= 4 +ub-pds-name-length INTEGER ::= 16 +ub-pds-parameter-length INTEGER ::= 30 +ub-pds-physical-address-lines INTEGER ::= 6 +ub-postal-code-length INTEGER ::= 16 +ub-pseudonym INTEGER ::= 128 +ub-surname-length INTEGER ::= 40 +ub-terminal-id-length INTEGER ::= 24 +ub-unformatted-address-length INTEGER ::= 180 +ub-x121-address-length INTEGER ::= 16 + +-- Misc OIDs from RFC5280. We should add related types as well. + +-- Policy qualifiers +id-pkix-qt OBJECT IDENTIFIER ::= { id-pkix 2 } +id-pkix-qt-cps OBJECT IDENTIFIER ::= { id-pkix-qt 1 } +id-pkix-qt-unotice OBJECT IDENTIFIER ::= { id-pkix-qt 2 } + +-- Access description +id-pkix-ad OBJECT IDENTIFIER ::= { id-pkix 48 } +id-pkix-ad-ocsp OBJECT IDENTIFIER ::= { id-pkix-ad 1 } +id-pkix-ad-caIssuers OBJECT IDENTIFIER ::= { id-pkix-ad 2 } +id-pkix-ad-timeStamping OBJECT IDENTIFIER ::= { id-pkix-ad 3 } +id-pkix-ad-caRepository OBJECT IDENTIFIER ::= { id-pkix-ad 5 } + +pq-CPS _POLICYQUALIFIERINFO ::= { + &id id-pkix-qt-cps, + &Type AliasIA5String +} +pq-UserNotice _POLICYQUALIFIERINFO ::= { + &id id-pkix-qt-unotice, + &Type UserNotice +} +KnownPolicyQualifiers _POLICYQUALIFIERINFO ::= { + pq-CPS + | pq-UserNotice +} +PolicyQualifierInfo ::= PolicyQualifierInfo{KnownPolicyQualifiers} + +END diff --git a/third_party/heimdal/lib/asn1/rfc2459.opt b/third_party/heimdal/lib/asn1/rfc2459.opt new file mode 100644 index 0000000..2070568 --- /dev/null +++ b/third_party/heimdal/lib/asn1/rfc2459.opt @@ -0,0 +1,12 @@ +--preserve-binary=Name +--preserve-binary=TBSCertificate +--preserve-binary=TBSCRLCertList +--sequence=AttributeValues +--sequence=CRLDistributionPoints +--sequence=Extensions +--sequence=GeneralNames +--sequence=RDNSequence +--sequence=Certificates +--sequence=CertificatePolicies +--sequence=PolicyQualifierInfos +--sequence=PolicyMappings diff --git a/third_party/heimdal/lib/asn1/rfc4108.asn1 b/third_party/heimdal/lib/asn1/rfc4108.asn1 new file mode 100644 index 0000000..34f9396 --- /dev/null +++ b/third_party/heimdal/lib/asn1/rfc4108.asn1 @@ -0,0 +1,207 @@ +CMSFirmwareWrapper + { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) + pkcs-9(9) smime(16) modules(0) cms-firmware-wrap(22) } + +DEFINITIONS IMPLICIT TAGS ::= BEGIN + +IMPORTS + -- We moved HardwareModuleName to avoid circular dependencies if + -- we have to have rfc2459 import it from here so we can define an + -- object set of OTHER-NAME class. + EnvelopedData + FROM cms -- [CMS] + { iso(1) member-body(2) us(840) rsadsi(113549) + pkcs(1) pkcs-9(9) smime(16) modules(0) cms-2004(24) }; + + +-- Firmware Package Content Type and Object Identifier + +id-ct-firmwarePackage OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 16 } + +FirmwarePkgData ::= OCTET STRING + + +-- Firmware Package Signed Attributes and Object Identifiers + +id-aa-firmwarePackageID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 35 } + +PreferredPackageIdentifier ::= SEQUENCE { + fwPkgID OBJECT IDENTIFIER, + verNum INTEGER (0..MAX) } + +PreferredOrLegacyPackageIdentifier ::= CHOICE { + preferred PreferredPackageIdentifier, + legacy OCTET STRING } + +PreferredOrLegacyStalePackageIdentifier ::= CHOICE { + preferredStaleVerNum INTEGER (0..MAX), + legacyStaleVersion OCTET STRING } + +FirmwarePackageIdentifier ::= SEQUENCE { + name PreferredOrLegacyPackageIdentifier, + stale PreferredOrLegacyStalePackageIdentifier OPTIONAL } + + +id-aa-targetHardwareIDs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 36 } + +TargetHardwareIdentifiers ::= SEQUENCE OF OBJECT IDENTIFIER + + +id-aa-decryptKeyID OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 37 } + +DecryptKeyIdentifier ::= OCTET STRING + + +id-aa-implCryptoAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 38 } + +ImplementedCryptoAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + +id-aa-implCompressAlgs OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 43 } + +ImplementedCompressAlgorithms ::= SEQUENCE OF OBJECT IDENTIFIER + + +id-aa-communityIdentifiers OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 40 } + +HardwareSerialEntry ::= CHOICE { + all NULL, + single OCTET STRING, + block SEQUENCE { + low OCTET STRING, + high OCTET STRING } } + +HardwareModules ::= SEQUENCE { + hwType OBJECT IDENTIFIER, + hwSerialEntries SEQUENCE OF HardwareSerialEntry } + +CommunityIdentifier ::= CHOICE { + communityOID OBJECT IDENTIFIER, + hwModuleList HardwareModules } + +CommunityIdentifiers ::= SEQUENCE OF CommunityIdentifier + +id-aa-firmwarePackageInfo OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 42 } + +FirmwarePackageInfo ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + dependencies SEQUENCE OF + PreferredOrLegacyPackageIdentifier OPTIONAL } + + +-- Firmware Package Unsigned Attributes and Object Identifiers + +id-aa-wrappedFirmwareKey OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) aa(2) 39 } + +WrappedFirmwareKey ::= EnvelopedData + + +-- Firmware Package Load Receipt Content Type and Object Identifier + +id-ct-firmwareLoadReceipt OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 17 } + +FWReceiptVersion ::= INTEGER { rfc4108-v1(1) } + +FirmwarePackageLoadReceipt ::= SEQUENCE { + version FWReceiptVersion DEFAULT 1, -- v1, but asn1_compile doesn't handle this + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + fwPkgName PreferredOrLegacyPackageIdentifier, + trustAnchorKeyID OCTET STRING OPTIONAL, + decryptKeyID [1] OCTET STRING OPTIONAL } + +-- Firmware Package Load Error Report Content Type +-- and Object Identifier + +id-ct-firmwareLoadError OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + smime(16) ct(1) 18 } + +FWErrorVersion ::= FWReceiptVersion + +FirmwarePackageLoadErrorCode ::= ENUMERATED { + decodeFailure (1), + badContentInfo (2), + badSignedData (3), + badEncapContent (4), + badCertificate (5), + badSignerInfo (6), + badSignedAttrs (7), + badUnsignedAttrs (8), + missingContent (9), + noTrustAnchor (10), + notAuthorized (11), + badDigestAlgorithm (12), + badSignatureAlgorithm (13), + unsupportedKeySize (14), + signatureFailure (15), + contentTypeMismatch (16), + badEncryptedData (17), + unprotectedAttrsPresent (18), + badEncryptContent (19), + badEncryptAlgorithm (20), + missingCiphertext (21), + noDecryptKey (22), + decryptFailure (23), + badCompressAlgorithm (24), + missingCompressedContent (25), + decompressFailure (26), + wrongHardware (27), + stalePackage (28), + notInCommunity (29), + unsupportedPackageType (30), + missingDependency (31), + wrongDependencyVersion (32), + insufficientMemory (33), + badFirmware (34), + unsupportedParameters (35), + breaksDependency (36), + otherError (99) } + +VendorLoadErrorCode ::= INTEGER + +CurrentFWConfig ::= SEQUENCE { + fwPkgType INTEGER OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier } + +FirmwarePackageLoadError ::= SEQUENCE { + version FWErrorVersion DEFAULT 1, -- v1, but see above + hwType OBJECT IDENTIFIER, + hwSerialNum OCTET STRING, + errorCode FirmwarePackageLoadErrorCode, + vendorErrorCode VendorLoadErrorCode OPTIONAL, + fwPkgName PreferredOrLegacyPackageIdentifier OPTIONAL, + config [1] SEQUENCE OF CurrentFWConfig OPTIONAL } + +-- Other Name syntax for Hardware Module Name + +id-on-hardwareModuleName OBJECT IDENTIFIER ::= { + iso(1) identified-organization(3) dod(6) internet(1) security(5) + mechanisms(5) pkix(7) on(8) 4 } + +-- Moved to rfc2459.asn1 so we can have the OtherName type decode it +-- automatically: +--HardwareModuleName ::= SEQUENCE { +-- hwType OBJECT IDENTIFIER, +-- hwSerialNum OCTET STRING } + +END diff --git a/third_party/heimdal/lib/asn1/roken_rename.h b/third_party/heimdal/lib/asn1/roken_rename.h new file mode 100644 index 0000000..76e108a --- /dev/null +++ b/third_party/heimdal/lib/asn1/roken_rename.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef __roken_rename_h__ +#define __roken_rename_h__ + +#ifndef HAVE_STRTOLL +#define strtoll rk_strtoll +#endif +#ifndef HAVE_STRTOULL +#define strtoull rk_strtoull +#endif + +#endif /* __roken_rename_h__ */ diff --git a/third_party/heimdal/lib/asn1/setchgpw2.asn1 b/third_party/heimdal/lib/asn1/setchgpw2.asn1 new file mode 100644 index 0000000..2f52cb1 --- /dev/null +++ b/third_party/heimdal/lib/asn1/setchgpw2.asn1 @@ -0,0 +1,193 @@ +-- $Id$ + +SETCHGPW2 DEFINITIONS ::= +BEGIN + +IMPORTS PrincipalName, Realm, ENCTYPE FROM krb5; + +ProtocolErrorCode ::= ENUMERATED { + generic-error(0), + unsupported-major-version(1), + unsupported-minor-version(2), + unsupported-operation(3), + authorization-failed(4), + initial-ticket-required(5), + target-principal-unknown(6), + ... +} + +Key ::= SEQUENCE { + enc-type[0] INTEGER, + key[1] OCTET STRING, + ... +} + +Language-Tag ::= UTF8String -- Constrained by RFC3066 + +LangTaggedText ::= SEQUENCE { + language[0] Language-Tag OPTIONAL, + text[1] UTF8String, + ... +} + +-- NULL Op + +Req-null ::= NULL +Rep-null ::= NULL +Err-null ::= NULL + +-- Change password +Req-change-pw ::= SEQUENCE { + old-pw[0] UTF8String, + new-pw[1] UTF8String OPTIONAL, + etypes[2] SEQUENCE OF ENCTYPE OPTIONAL, + ... +} + +Rep-change-pw ::= SEQUENCE { + info-text[0] UTF8String OPTIONAL, + new-pw[1] UTF8String OPTIONAL, + etypes[2] SEQUENCE OF ENCTYPE OPTIONAL +} + +Err-change-pw ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + code[1] ENUMERATED { + generic(0), + wont-generate-new-pw(1), + old-pw-incorrect(2), + new-pw-rejected-geneneric(3), + pw-change-too-short(4), + ... + }, + suggested-new-pw[2] UTF8String OPTIONAL, + ... +} + +-- Change/Set keys +Req-set-keys ::= SEQUENCE { + etypes[0] SEQUENCE OF ENCTYPE, + entropy[1] OCTET STRING, + ... +} + +Rep-set-keys ::= SEQUENCE { + info-text[0] UTF8String OPTIONAL, + kvno[1] INTEGER, + keys[2] SEQUENCE OF Key, + aliases[3] SEQUENCE OF SEQUENCE { + name[0] PrincipalName, + realm[1] Realm OPTIONAL, + ... + }, + ... +} + +Err-set-keys ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + enctypes[1] SEQUENCE OF ENCTYPE OPTIONAL, + code[1] ENUMERATED { + etype-no-support(0), + ... + }, + ... +} + +-- Get password policy +Req-get-pw-policy ::= NULL + +Rep-get-pw-policy ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + policy-name[1] UTF8String OPTIONAL, + description[2] UTF8String OPTIONAL, + ... +} + +Err-get-pw-policy ::= NULL + +-- Get principal aliases +Req-get-princ-aliases ::= NULL + +Rep-get-princ-aliases ::= SEQUENCE { + help-text[0] UTF8String OPTIONAL, + aliases[1] SEQUENCE OF SEQUENCE { + name[0] PrincipalName, + realm[1] Realm OPTIONAL, + ... + } OPTIONAL, + ... +} + +Err-get-princ-aliases ::= NULL + +-- Get list of encryption types supported by KDC for new types +Req-get-supported-etypes ::= NULL + +Rep-get-supported-etypes ::= SEQUENCE OF ENCTYPE + +Err-get-supported-etypes ::= NULL + +-- Choice switch + +Op-req ::= CHOICE { + null[0] Req-null, + change-pw[1] Req-change-pw, + set-keys[2] Req-set-keys, + get-pw-policy[3] Req-get-pw-policy, + get-princ-aliases[4] Req-get-princ-aliases, + get-supported-etypes[5] Req-get-supported-etypes, + ... +} + +Op-rep ::= CHOICE { + null[0] Rep-null, + change-pw[1] Rep-change-pw, + set-keys[2] Rep-set-keys, + get-pw-policy[3] Rep-get-pw-policy, + get-princ-aliases[4] Rep-get-princ-aliases, + get-supported-etypes[5] Rep-get-supported-etypes, + ... +} + +Op-error ::= CHOICE { + null[0] Err-null, + change-pw[1] Err-change-pw, + set-keys[2] Err-set-keys, + get-pw-policy[3] Err-get-pw-policy, + get-princ-aliases[4] Err-get-princ-aliases, + get-supported-etypes[5] Err-get-supported-etypes, + ... +} + + +Request ::= [ APPLICATION 0 ] SEQUENCE { + pvno-major[0] INTEGER DEFAULT 2, + pvno-minor[1] INTEGER DEFAULT 0, + languages[2] SEQUENCE OF Language-Tag OPTIONAL, + targ-name[3] PrincipalName OPTIONAL, + targ-realm[4] Realm OPTIONAL, + operation[5] Op-Req, + ... +} + +Response ::= [ APPLICATION 1 ] SEQUENCE { + pvno-major[0] INTEGER DEFAULT 2, + pvno-minor[1] INTEGER DEFAULT 0, + language[2] Language-Tag DEFAULT "i-default", + result[3] Op-rep OPTIONAL, + ... +} + +Error-Response ::= [ APPLICATION 2 ] SEQUENCE { + pvno-major[0] INTEGER DEFAULT 2, + pvno-minor[1] INTEGER DEFAULT 0, + language[2] Language-Tag DEFAULT "i-default", + error-code[3] ProtocolErrorCode, + help-text[4] UTF8String OPTIONAL, + op-error[5] Op-error OP-ERROR, + ... +} + +END + +-- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' setchgpw2.asn1 diff --git a/third_party/heimdal/lib/asn1/symbol.c b/third_party/heimdal/lib/asn1/symbol.c new file mode 100644 index 0000000..b472ebd --- /dev/null +++ b/third_party/heimdal/lib/asn1/symbol.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gen_locl.h" +#include "lex.h" +#include "lex.h" + +static Hashtab *htab; + +struct symhead symbols; + +static int +cmp(void *a, void *b) +{ + Symbol *s1 = (Symbol *) a; + Symbol *s2 = (Symbol *) b; + + return strcmp(s1->name, s2->name); +} + +static unsigned +hash(void *a) +{ + Symbol *s = (Symbol *) a; + + return hashjpw(s->name); +} + +void +initsym(void) +{ + htab = hashtabnew(101, cmp, hash); +} + + +void +output_name(char *s) +{ + char *p; + + for (p = s; *p; ++p) + if (*p == '-' || *p == '.') + *p = '_'; +} + +Symbol * +addsym(char *name) +{ + Symbol key, *s; + + key.name = name; + s = (Symbol *) hashtabsearch(htab, (void *) &key); + if (s == NULL) { + s = (Symbol *) ecalloc(1, sizeof(*s)); + s->name = name; + s->gen_name = estrdup(name); + output_name(s->gen_name); + s->stype = SUndefined; + hashtabadd(htab, s); + //HEIM_TAILQ_INSERT_TAIL(&symbols, s, symlist); + do { + if (((s)->symlist.tqe_next = (&symbols)->tqh_first) != NULL) + (&symbols)->tqh_first->symlist.tqe_prev = &(s)->symlist.tqe_next; + else + (&symbols)->tqh_last = &(s)->symlist.tqe_next; + (&symbols)->tqh_first = (s); + (s)->symlist.tqe_prev = &(&symbols)->tqh_first; + } while (0); + } + return s; +} + +Symbol * +getsym(char *name) +{ + Symbol key; + + key.name = name; + return (Symbol *) hashtabsearch(htab, (void *) &key); +} + +static int +checkfunc(void *ptr, void *arg) +{ + Symbol *s = ptr; + if (s->stype == SUndefined) { + lex_error_message("%s is still undefined\n", s->name); + *(int *) arg = 1; + } + return 0; +} + +int +checkundefined(void) +{ + int f = 0; + hashtabforeach(htab, checkfunc, &f); + return f; +} + +#if 0 +static int +generate_1type(void *ptr, void *arg) +{ + Symbol *s = ptr; + + if (s->stype == Stype && s->type) + generate_type(s); + return 0; +} +#endif + +void +generate_types(void) +{ + Symbol *s; + + if (checkundefined()) + errx(1, "Some types are undefined"); + HEIM_TAILQ_FOREACH_REVERSE(s, &symbols, symhead, symlist) { + if (s->stype == Stype && s->type) + generate_type(s); + } + //hashtabforeach(htab, generate_1type, NULL); +} + +void +emitted_declaration(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_declaration = 1; +} + +void +emitted_definition(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_definition = 1; +} + +void +emitted_tag_enums(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_tag_enums = 1; +} + +void +emitted_asn1(const Symbol *s) +{ + ((Symbol *)(uintptr_t)s)->emitted_asn1 = 1; +} diff --git a/third_party/heimdal/lib/asn1/symbol.h b/third_party/heimdal/lib/asn1/symbol.h new file mode 100644 index 0000000..108749b --- /dev/null +++ b/third_party/heimdal/lib/asn1/symbol.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef _SYMBOL_H +#define _SYMBOL_H + +#include <heimqueue.h> + +enum typetype { + TBitString, + TBoolean, + TChoice, + TEnumerated, + TGeneralString, + TTeletexString, + TGeneralizedTime, + TIA5String, + TInteger, + TNull, + TOID, + TOctetString, + TPrintableString, + TSequence, + TSequenceOf, + TSet, + TSetOf, + TTag, + TType, + TUTCTime, + TUTF8String, + TBMPString, + TUniversalString, + TVisibleString +}; + +typedef enum typetype Typetype; + +struct type; +struct value; +struct typereference; + +struct value { + enum { booleanvalue, + nullvalue, + integervalue, + stringvalue, + objectidentifiervalue + } type; + union { + int booleanvalue; + int64_t integervalue; + char *stringvalue; + struct objid *objectidentifiervalue; + } u; + struct symbol *s; +}; + +struct member { + char *name; + char *gen_name; + char *label; + int64_t val; + int optional; + int ellipsis; + struct type *type; + HEIM_TAILQ_ENTRY(member) members; + struct value *defval; +}; + +typedef struct member Member; + +HEIM_TAILQ_HEAD(memhead, member); + +struct symbol; + +struct tagtype { + int tagclass; + int tagvalue; + enum { TE_IMPLICIT, TE_EXPLICIT } tagenv; +}; + +struct range { + /* + * We can't represent unsigned 64-bit ranges because max might be + * negative... + */ + int64_t min; + int64_t max; +}; + +enum ctype { CT_CONTENTS, CT_USER, CT_TABLE_CONSTRAINT, CT_RANGE } ; + +struct constraint_spec; + +struct iosclassfield { + char *name; + struct type *type; + struct value *defval; + HEIM_TAILQ_ENTRY(iosclassfield) fields; + unsigned long id; + unsigned int optional:1; + unsigned int unique:1; +}; + +typedef struct iosclassfield Field; +HEIM_TAILQ_HEAD(fieldhead, iosclassfield); + +struct iosobjectfield { + char *name; + struct type *type; + struct value *value; + HEIM_TAILQ_ENTRY(iosobjectfield) objfields; + unsigned long id; +}; + +typedef struct iosobjectfield ObjectField; +HEIM_TAILQ_HEAD(objfieldhead, iosobjectfield); + +struct iosclass { + struct symbol *symbol; + struct fieldhead *fields; + unsigned long id; +}; + +typedef struct iosclass IOSClass; + +struct iosobject { + struct symbol *symbol; + struct objfieldhead *objfields; + ObjectField *typeidf; + IOSClass *iosclass; + HEIM_TAILQ_ENTRY(iosobject) objects; + unsigned long id; + unsigned int ellipsis:1; + unsigned int optional:1; +}; + +typedef struct iosobject IOSObject; +HEIM_TAILQ_HEAD(objectshead, iosobject); + +struct iosobjectset { + struct symbol *symbol; + IOSClass *iosclass; + struct objectshead *objects; + unsigned long id; +}; + +typedef struct iosobjectset IOSObjectSet; + +struct typereference { + /* + * For now we don't support link fields, so we don't support chains of more + * than one field. + */ + IOSClass *iosclass; + Field *field; +}; + +struct type { + Typetype type; + struct memhead *members; + struct symbol *symbol; + struct type *subtype; + struct typereference typeref; /* For type fields */ + IOSClass *formal_parameter; + IOSObjectSet *actual_parameter; + struct tagtype tag; + struct range *range; + struct constraint_spec *constraint; + unsigned long id; + unsigned int implicit_choice:1; +}; + +typedef struct type Type; + +struct component_relation_constraint { + char *objectname; + char *membername; +}; + +struct constraint_spec { + enum ctype ctype; + union { + struct { + Type *type; + struct value *encoding; + struct component_relation_constraint crel; + } content; + struct range *range; + } u; +}; + +struct objid { + const char *label; + int value; + struct objid *next; +}; + +struct symbol { + char *name; + char *gen_name; + enum { SUndefined, SValue, Stype, Sparamtype, Sclass, Sobj, Sobjset } stype; + struct value *value; + Type *type; + IOSClass *iosclass; + IOSObject *object; + IOSObjectSet *objectset; + HEIM_TAILQ_ENTRY(symbol) symlist; + unsigned int emitted_asn1:1; + unsigned int emitted_declaration:1; + unsigned int emitted_definition:1; + unsigned int emitted_tag_enums:1; + unsigned int emitted_template:1; +}; + +typedef struct symbol Symbol; + +//HEIM_TAILQ_HEAD(symhead, symbol); +struct symhead { + struct symbol *tqh_first; + struct symbol **tqh_last; +}; + +extern struct symhead symbols; + +void initsym (void); +Symbol *addsym (char *); +Symbol *getsym(char *name); +void output_name (char *); +int checkundefined(void); +void generate_types(void); +void emitted_asn1(const Symbol *); +void emitted_declaration(const Symbol *); +void emitted_definition(const Symbol *); +void emitted_tag_enums(const Symbol *); +#endif diff --git a/third_party/heimdal/lib/asn1/tcg.asn1 b/third_party/heimdal/lib/asn1/tcg.asn1 new file mode 100644 index 0000000..14129b0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/tcg.asn1 @@ -0,0 +1,42 @@ +TCG DEFINITIONS ::= BEGIN + +-- BEGIN Heimdal commentary +-- +-- Copy-pasted from section 4 of +-- https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_EKCredentialProfile_v2p3_r2_pub.pdf +-- https://trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf +-- and adjusted to compile as follows: +-- +-- - Due to limitations of the Heimdal compiler we've moved all of this +-- module's contents to rfc2459.asn1. +-- +-- - Extensibility markers added to all SEQUENCEs as per the TCG's spec they +-- reserve the right to add fields in the future. +-- - Information Object System annotations commented out (Heimdal does not +-- support them) +-- +-- - Types sorted topologically (at the time I did that the Heimdal ASN.1 +-- compiler wouldn't do that on its own) +-- +-- - Two otherwise equal ENUMERATED types share a definition now (at the time +-- the Heimdal ASN.1 compiler did not prefix labels of ENUMERATED types) +-- +-- A small note for anyone whoever finds this: do not add complex structures as +-- DN attributes, or, indeed, never add DN attributes again. If some metadata +-- is name-like, then add a subjectAlternativeName otherName for it, otherwise +-- add a certificate extension to carry that metadata. And, for any name-like +-- metadata, always always include query and display syntax for it. +-- +-- Anyone designing anything but the simplest schema in ASN.1 should have to +-- learn a bit more about ASN.1 and/or get a review from ASN.1 experts. +-- +-- Anyone designing anything but the simplest x.509 extensions should have to +-- learn a bit more about ASN.1 and x.509 and/or get a review from x.509 +-- experts. +-- +-- Note that a module OID was not provided. Indeed, a valid, complete ASN.1 +-- module was not provided. +-- +-- END Heimdal commentary (though some minor Heimdal commentary appears below) + +END diff --git a/third_party/heimdal/lib/asn1/template.c b/third_party/heimdal/lib/asn1/template.c new file mode 100644 index 0000000..ed215d8 --- /dev/null +++ b/third_party/heimdal/lib/asn1/template.c @@ -0,0 +1,3104 @@ +/* + * Copyright (c) 2009 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" +#include <com_err.h> +#include <vis.h> +#include <vis-extras.h> +#include <heimbase.h> + +#ifndef ENOTSUP +/* Very old MSVC CRTs don't have ENOTSUP */ +#define ENOTSUP EINVAL +#endif + +struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = { +#define el(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + (asn1_type_print)der_print_##name, \ + sizeof(type) \ + } +#define elber(name, type) { \ + (asn1_type_encode)der_put_##name, \ + (asn1_type_decode)der_get_##name##_ber, \ + (asn1_type_length)der_length_##name, \ + (asn1_type_copy)der_copy_##name, \ + (asn1_type_release)der_free_##name, \ + (asn1_type_print)der_print_##name, \ + sizeof(type) \ + } + el(integer, int), + el(heim_integer, heim_integer), + el(integer, int), + el(integer64, int64_t), + el(unsigned, unsigned), + el(unsigned64, uint64_t), + el(general_string, heim_general_string), + el(octet_string, heim_octet_string), + elber(octet_string, heim_octet_string), + el(ia5_string, heim_ia5_string), + el(bmp_string, heim_bmp_string), + el(universal_string, heim_universal_string), + el(printable_string, heim_printable_string), + el(visible_string, heim_visible_string), + el(utf8string, heim_utf8_string), + el(generalized_time, time_t), + el(utctime, time_t), + el(bit_string, heim_bit_string), + { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean, + (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer, + (asn1_type_release)der_free_integer, (asn1_type_print)der_print_boolean, + sizeof(int) + }, + el(oid, heim_oid), + el(general_string, heim_general_string), +#undef el +#undef elber +}; + +size_t +_asn1_sizeofType(const struct asn1_template *t) +{ + return t->offset; +} + +/* + * Here is abstraction to not so well evil fact of bit fields in C, + * they are endian dependent, so when getting and setting bits in the + * host local structure we need to know the endianness of the host. + * + * Its not the first time in Heimdal this have bitten us, and some day + * we'll grow up and use #defined constant, but bit fields are still + * so pretty and shiny. + */ + +static void +_asn1_bmember_get_bit(const unsigned char *p, void *data, + unsigned int bit, size_t size) +{ + unsigned int localbit = bit % 8; + if ((*p >> (7 - localbit)) & 1) { +#ifdef WORDS_BIGENDIAN + *(unsigned int *)data |= (1u << ((size * 8) - bit - 1)); +#else + *(unsigned int *)data |= (1u << bit); +#endif + } +} + +int +_asn1_bmember_isset_bit(const void *data, unsigned int bit, size_t size) +{ +#ifdef WORDS_BIGENDIAN + if ((*(unsigned int *)data) & (1u << ((size * 8) - bit - 1))) + return 1; + return 0; +#else + if ((*(unsigned int *)data) & (1u << bit)) + return 1; + return 0; +#endif +} + +void +_asn1_bmember_put_bit(unsigned char *p, const void *data, unsigned int bit, + size_t size, unsigned int *bitset) +{ + unsigned int localbit = bit % 8; + + if (_asn1_bmember_isset_bit(data, bit, size)) { + *p |= (1u << (7 - localbit)); + if (*bitset == 0) + *bitset = (7 - localbit) + 1; + } +} + +/* + * Utility function to tell us if the encoding of some type per its template + * will have an outer tag. This is needed when the caller wants to slap on an + * IMPLICIT tag: if the inner type has a tag then we need to replace it. + */ +static int +is_tagged(const struct asn1_template *t) +{ + size_t elements = A1_HEADER_LEN(t); + + t += A1_HEADER_LEN(t); + if (elements != 1) + return 0; + switch (t->tt & A1_OP_MASK) { + case A1_OP_SEQOF: return 0; + case A1_OP_SETOF: return 0; + case A1_OP_BMEMBER: return 0; + case A1_OP_PARSE: return 0; + case A1_OP_TAG: return 1; + case A1_OP_CHOICE: return 1; + case A1_OP_TYPE: return 1; + case A1_OP_TYPE_EXTERN: { + const struct asn1_type_func *f = t->ptr; + + /* + * XXX Add a boolean to struct asn1_type_func to tell us if the type is + * tagged or not. Basically, it's not tagged if it's primitive. + */ + if (f->encode == (asn1_type_encode)encode_heim_any || + f->encode == (asn1_type_encode)encode_HEIM_ANY) + return 0; + abort(); /* XXX */ + } + default: abort(); + } +} + +static size_t +inner_type_taglen(const struct asn1_template *t) +{ + size_t elements = A1_HEADER_LEN(t); + + t += A1_HEADER_LEN(t); + if (elements != 1) + return 0; + switch (t->tt & A1_OP_MASK) { + case A1_OP_SEQOF: return 0; + case A1_OP_SETOF: return 0; + case A1_OP_BMEMBER: return 0; + case A1_OP_PARSE: return 0; + case A1_OP_CHOICE: return 1; + case A1_OP_TYPE: return inner_type_taglen(t->ptr); + case A1_OP_TAG: return der_length_tag(A1_TAG_TAG(t->tt)); + case A1_OP_TYPE_EXTERN: { + const struct asn1_type_func *f = t->ptr; + + /* + * XXX Add a boolean to struct asn1_type_func to tell us if the type is + * tagged or not. Basically, it's not tagged if it's primitive. + */ + if (f->encode == (asn1_type_encode)encode_heim_any || + f->encode == (asn1_type_encode)encode_HEIM_ANY) + return 0; + abort(); /* XXX */ + } + default: abort(); +#ifdef WIN32 + _exit(0); /* Quiet VC */ +#endif + } +} + +/* + * Compare some int of unknown size in a type ID field to the int value in + * some IOS object's type ID template entry. + * + * This should be called with a `A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Integer)' + * template as the `ttypeid'. + */ +static int +typeid_int_cmp(const void *intp, + int64_t i, + const struct asn1_template *ttypeid) +{ + const struct asn1_template *tint = ttypeid->ptr; + + if ((tint[1].tt & A1_OP_MASK) != A1_OP_PARSE) + return -1; + if (A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER && + A1_PARSE_TYPE(tint[1].tt) != A1T_UNSIGNED && + A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER64 && + A1_PARSE_TYPE(tint[1].tt) != A1T_UNSIGNED64 && + A1_PARSE_TYPE(tint[1].tt) != A1T_IMEMBER) + return -1; + switch (tint[0].offset) { + case 8: return i - *(const int64_t *)intp; + case 4: return i - *(const int32_t *)intp; + default: return -1; + } +} + +/* + * Map a logical SET/SEQUENCE member to a template entry. + * + * This should really have been done by the compiler, but clearly it wasn't. + * + * The point is that a struct type's template may be littered with entries that + * don't directly correspond to a struct field (SET/SEQUENCE member), so we + * have to count just the ones that do to get to the one we want. + */ +static const struct asn1_template * +template4member(const struct asn1_template *t, size_t f) +{ + size_t n = (uintptr_t)t->ptr; + size_t i; + + for (i = 0, t++; i < n; t++, i++) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_TAG: + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: + if (f-- == 0) + return t; + continue; + case A1_OP_OPENTYPE_OBJSET: + case A1_OP_NAME: + return NULL; + default: + continue; + } + } + return NULL; +} + +/* + * Attempt to decode known open type alternatives into a CHOICE-like + * discriminated union. + * + * Arguments: + * + * - object set template + * - decoder flags + * - pointer to memory object (C struct) to decode into + * - template for type ID field of `data' + * - template for open type field of `data' (an octet string or HEIM_ANY) + * + * Returns: + * + * - 0 + * - ENOMEM + * + * Other errors in decoding open type values are ignored, but applications can + * note that an error must have occurred. (Perhaps we should generate a `ret' + * field for the discriminated union we decode into that we could use to + * indicate what went wrong with decoding an open type value? The application + * can always try to decode itself to find out what the error was, but the + * whole point is to save the developer the bother of writing code to decode + * open type values. Then again, the specific cause of any one decode failure + * is not usually very important to users, so it's not very important to + * applications either.) + * + * Here `data' is something like this: + * + * typedef struct SingleAttribute { + * heim_oid type; // <--- decoded already + * HEIM_ANY value; // <--- decoded already + * // We must set this: + * // vvvvvvvv + * struct { + * enum { + * choice_SingleAttribute_iosnumunknown = 0, + * choice_SingleAttribute_iosnum_id_at_name, + * .. + * choice_SingleAttribute_iosnum_id_at_emailAddress, + * } element; // <--- map type ID to enum + * union { + * X520name* at_name; + * X520name* at_surname; + * .. + * AliasIA5String* at_emailAddress; + * } u; // <--- alloc and decode val above into this + * } _ioschoice_value; + * } SingleAttribute; + * + * or + * + * typedef struct AttributeSet { + * heim_oid type; // <--- decoded already + * struct AttributeSet_values { + * unsigned int len; // <--- decoded already + * HEIM_ANY *val; // <--- decoded already + * } values; + * // We must set this: + * // vvvvvvvv + * struct { + * enum { choice_AttributeSet_iosnumunknown = 0, + * choice_AttributeSet_iosnum_id_at_name, + * choice_AttributeSet_iosnum_id_at_surname, + * .. + * choice_AttributeSet_iosnum_id_at_emailAddress, + * } element; // <--- map type ID to enum + * unsigned int len; // <--- set len to len as above + * union { + * X520name *at_name; + * X520name *at_surname; + * .. + * AliasIA5String *at_emailAddress; + * } *val; // <--- alloc and decode vals above into this + * } _ioschoice_values; + * } AttributeSet; + */ +static int +_asn1_decode_open_type(const struct asn1_template *t, + unsigned flags, + void *data, + const struct asn1_template *ttypeid, + const struct asn1_template *topentype) +{ + const struct asn1_template *ttypeid_univ = ttypeid; + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + size_t sz, n; + size_t i = 0; + unsigned int *lenp = NULL; /* Pointer to array length field */ + unsigned int len = 1; /* Array length */ + void **dp = NULL; /* Decoded open type struct pointer */ + int *elementp; /* Choice enum pointer */ + int typeid_is_oid = 0; + int typeid_is_int = 0; + int ret = 0; + + /* + * NOTE: Here expressions like `DPO(data, t->offset + ...)' refer to parts + * of a _ioschoice_<fieldName> struct field of `data'. + * + * Expressions like `DPO(data, topentype->offset + ...)' refer to + * the open type field in `data', which is either a `heim_any', a + * `heim_octet_string', or an array of one of those. + * + * Expressions like `DPO(data, ttypeid->offset)' refer to the open + * type's type ID field in `data'. + */ + + /* + * Minimal setup: + * + * - set type choice to choice_<type>_iosnumunknown (zero). + * - set union value to zero + * + * We need a pointer to the choice ID: + * + * typedef struct AttributeSet { + * heim_oid type; // <--- decoded already + * struct AttributeSet_values { + * unsigned int len; // <--- decoded already + * HEIM_ANY *val; // <--- decoded already + * } values; + * struct { + * enum { choice_AttributeSet_iosnumunknown = 0, + * -----------> ... + * } element; // HERE + * ... + * } ... + * } + * + * XXX NOTE: We're assuming that sizeof(enum) == sizeof(int)! + */ + elementp = DPO(data, t->offset); + *elementp = 0; /* Set the choice to choice_<type>_iosnumunknown */ + if (t->tt & A1_OS_OT_IS_ARRAY) { + /* + * The open type is a SET OF / SEQUENCE OF -- an array. + * + * Get the number of elements to decode from: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * ------------>unsigned int len; // HERE + * HEIM_ANY *val; + * } values; + * ... + * } + */ + len = *((unsigned int *)DPO(data, topentype->offset)); + + /* + * Set the number of decoded elements to zero for now: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * unsigned int len; + * HEIM_ANY *val; + * } values; + * struct { + * enum { ... } element; + * ------------>unsigned int len; // HERE + * ... + * } _ioschoice_values; + * } + */ + lenp = DPO(data, t->offset + sizeof(*elementp)); + *lenp = 0; + /* + * Get a pointer to the place where we must put the decoded value: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * unsigned int len; + * HEIM_ANY *val; + * } values; + * struct { + * enum { ... } element; + * unsigned int len; + * struct { + * union { SomeType *some_choice; ... } u; + * ------------>} *val; // HERE + * } _ioschoice_values; + * } AttributeSet; + */ + dp = DPO(data, t->offset + sizeof(*elementp) + sizeof(*lenp)); + } else { + /* + * Get a pointer to the place where we must put the decoded value: + * + * typedef struct SingleAttribute { + * heim_oid type; + * HEIM_ANY value; + * struct { + * enum { ... } element; + * ------------>union { SomeType *some_choice; ... } u; // HERE + * } _ioschoice_value; + * } SingleAttribute; + */ + dp = DPO(data, t->offset + sizeof(*elementp)); + } + + /* Align `dp' */ + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + *dp = NULL; + + /* + * Find out the type of the type ID member. We currently support only + * integers and OIDs. + * + * Chase through any tags to get to the type. + */ + while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG && + A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) || + ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) { + ttypeid_univ = ttypeid_univ->ptr; + ttypeid_univ++; + } + switch (ttypeid_univ->tt & A1_OP_MASK) { + case A1_OP_TAG: + if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV) + return 0; /* Do nothing, silently */ + switch (A1_TAG_TAG(ttypeid_univ->tt)) { + case UT_OID: + typeid_is_oid = 1; + break; + case UT_Integer: { + const struct asn1_template *tint = ttypeid_univ->ptr; + + tint++; + + if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE) + return 0; /* Do nothing, silently */ + if (A1_PARSE_TYPE(tint->tt) != A1T_INTEGER && + A1_PARSE_TYPE(tint->tt) != A1T_UNSIGNED && + A1_PARSE_TYPE(tint->tt) != A1T_INTEGER64 && + A1_PARSE_TYPE(tint->tt) != A1T_UNSIGNED64 && + A1_PARSE_TYPE(tint->tt) != A1T_IMEMBER) + return 0; /* Do nothing, silently (maybe a large int) */ + typeid_is_int = 1; + break; + } + /* It might be cool to support string types as type ID types */ + default: return 0; /* Do nothing, silently */ + } + break; + default: return 0; /* Do nothing, silently */ + } + + /* + * Find the type of the open type. + * + * An object set template looks like: + * + * const struct asn1_template asn1_ObjectSetName[] = { + * // Header entry (in this case it says there's 17 objects): + * { 0, 0, ((void*)17) }, + * + * // here's the name of the object set: + * { A1_OP_NAME, 0, "ObjectSetName" }, + * + * // then three entries per object: object name, object type ID, + * // object type: + * { A1_OP_NAME, 0, "ext-AuthorityInfoAccess" }, + * { A1_OP_OPENTYPE_ID, 0, (const void*)&asn1_oid_oidName }, + * { A1_OP_OPENTYPE, sizeof(SomeType), (const void*)&asn1_SomeType }, + * ... + * }; + * + * `i' being a logical object offset, i*3+3 would be the index of the + * A1_OP_OPENTYPE_ID entry for the current object, and i*3+4 the index of + * the A1_OP_OPENTYPE entry for the current object. + */ + if (t->tt & A1_OS_IS_SORTED) { + size_t left = 0; + size_t right = A1_HEADER_LEN(tos); + const void *vp = DPO(data, ttypeid->offset); + int c = -1; + + while (left < right) { + size_t mid = (left + right) >> 1; + + if ((tos[3 + mid * 3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + return 0; + if (typeid_is_int) + c = typeid_int_cmp(vp, (intptr_t)tos[3 + mid * 3].ptr, + ttypeid_univ); + else if (typeid_is_oid) + c = der_heim_oid_cmp(vp, tos[3 + mid * 3].ptr); + if (c < 0) { + right = mid; + } else if (c > 0) { + left = mid + 1; + } else { + i = mid; + break; + } + } + if (c) + return 0; /* No match */ + } else { + for (i = 0, n = A1_HEADER_LEN(tos); i < n; i++) { + /* We add 1 to `i' because we're skipping the header */ + if ((tos[3 + i*3].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + return 0; + if (typeid_is_int && + typeid_int_cmp(DPO(data, ttypeid->offset), + (intptr_t)tos[3 + i*3].ptr, + ttypeid_univ)) + continue; + if (typeid_is_oid && + der_heim_oid_cmp(DPO(data, ttypeid->offset), tos[3 + i*3].ptr)) + continue; + break; + } + if (i == n) + return 0; /* No match */ + } + + /* Match! */ + *elementp = i+1; /* Zero is the "unknown" choice, so add 1 */ + + /* + * We want the A1_OP_OPENTYPE template entry. Its `offset' is the sizeof + * the object we'll be decoding into, and its `ptr' is the pointer to the + * template for decoding that type. + */ + tactual_type = &tos[i*3 + 4]; + + /* Decode the encoded open type value(s) */ + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + /* + * Not a SET OF/SEQUENCE OF open type, just singular. + * + * We need the address of the octet string / ANY field containing the + * encoded open type value: + * + * typedef struct SingleAttribute { + * heim_oid type; + * -------->HEIM_ANY value; // HERE + * struct { + * ... + * } ... + * } + */ + const struct heim_base_data *d = DPOC(data, topentype->offset); + void *o; + + if (d->data && d->length) { + if ((o = calloc(1, tactual_type->offset)) == NULL) + return ENOMEM; + + /* Re-enter to decode the encoded open type value */ + ret = _asn1_decode(tactual_type->ptr, flags, d->data, d->length, o, &sz); + /* + * Store the decoded object in the union: + * + * typedef struct SingleAttribute { + * heim_oid type; + * HEIM_ANY value; + * struct { + * enum { ... } element; + * ------------>union { SomeType *some_choice; ... } u; // HERE + * } _ioschoice_value; + * } SingleAttribute; + * + * All the union arms are pointers. + */ + if (ret) { + _asn1_free(tactual_type->ptr, o); + free(o); + /* + * So we failed to decode the open type -- that should not be fatal + * to decoding the rest of the input. Only ENOMEM should be fatal. + */ + ret = 0; + } else { + *dp = o; + } + } + return ret; + } else { + const struct heim_base_data * const *d; + void **val; /* Array of pointers */ + + /* + * A SET OF/SEQUENCE OF open type, plural. + * + * We need the address of the octet string / ANY array pointer field + * containing the encoded open type values: + * + * typedef struct AttributeSet { + * heim_oid type; + * struct AttributeSet_values { + * unsigned int len; + * ------------>HEIM_ANY *val; // HERE + * } values; + * ... + * } + * + * We already know the value of the `len' field. + */ + d = DPOC(data, topentype->offset + sizeof(unsigned int)); + while (sizeof(void *) != sizeof(len) && + ((uintptr_t)d) % sizeof(void *) != 0) + d = (const void *)(((const char *)d) + sizeof(len)); + + if ((val = calloc(len, sizeof(*val))) == NULL) + ret = ENOMEM; + + /* Increment the count of decoded values as we decode */ + *lenp = len; + for (i = 0; ret != ENOMEM && i < len; i++) { + if ((val[i] = calloc(1, tactual_type->offset)) == NULL) + ret = ENOMEM; + if (ret == 0) + /* Re-enter to decode the encoded open type value */ + ret = _asn1_decode(tactual_type->ptr, flags, d[0][i].data, + d[0][i].length, val[i], &sz); + if (ret) { + _asn1_free(tactual_type->ptr, val[i]); + free(val[i]); + val[i] = NULL; + } + } + if (ret != ENOMEM) + ret = 0; /* See above */ + *dp = val; + return ret; + } +} + +int +_asn1_decode(const struct asn1_template *t, unsigned flags, + const unsigned char *p, size_t len, void *data, size_t *size) +{ + const struct asn1_template *tbase = t; + const struct asn1_template *tdefval = NULL; + size_t elements = A1_HEADER_LEN(t); + size_t oldlen = len; + int ret = 0; + const unsigned char *startp = NULL; + unsigned int template_flags = t->tt; + + /* + * Important notes: + * + * - by and large we don't call _asn1_free() on error, except when we're + * decoding optional things or choices, then we do call _asn1_free() + * here + * + * instead we leave it to _asn1_decode_top() to call _asn1_free() on + * error + * + * - on error all fields of whatever we didn't _asn1_free() must have been + * initialized to sane values because _asn1_decode_top() will call + * _asn1_free() on error, so we must have left everything initialized + * that _asn1_free() could possibly look at + * + * - so we must initialize everything + * + * FIXME? but we mostly rely on calloc() to do this... + * + * - we don't use malloc() unless we're going to write over the whole + * thing with memcpy() or whatever + */ + + /* skip over header */ + t++; + + if (template_flags & A1_HF_PRESERVE) + startp = p; + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + size_t opentypeid = t->tt & ((1<<10)-1); + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + + /* Note that the only error returned here would be ENOMEM */ + ret = _asn1_decode_open_type(t, flags, data, + template4member(tbase, opentypeid), + template4member(tbase, opentype)); + if (ret) + return ret; + break; + } + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; + case A1_OP_NAME: break; + case A1_OP_DEFVAL: + tdefval = t; + break; + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize, elsize; + void *el = DPO(data, t->offset); + void **pel = (void **)el; + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + elsize = _asn1_sizeofType(t->ptr); + } else { + const struct asn1_type_func *f = t->ptr; + elsize = f->size; + } + + if (t->tt & A1_FLAG_OPTIONAL) { + *pel = calloc(1, elsize); + if (*pel == NULL) + return ENOMEM; + el = *pel; + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->decode)(p, len, el, &newsize); + } + if (ret) { + /* + * Optional field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + _asn1_free(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + f->release(el); + } + free(*pel); + *pel = NULL; + break; + } + } else { + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->decode)(p, len, el, &newsize); + } + } + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + } else if (t->tt & A1_FLAG_DEFAULT) { + if (!tdefval) + return ASN1_PARSE_ERROR; /* Can't happen */ + /* + * Defaulted field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if (tdefval->tt & A1_DV_BOOLEAN) { + int *i = (void *)(char *)el; + + *i = tdefval->ptr ? 1 : 0; + } else if (tdefval->tt & A1_DV_INTEGER64) { + int64_t *i = (void *)(char *)el; + + *i = (int64_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER32) { + int32_t *i = (void *)(char *)el; + + *i = (int32_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER) { + struct heim_integer *i = (void *)(char *)el; + + if ((ret = der_copy_heim_integer(tdefval->ptr, i))) + return ret; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + char **s = el; + + if ((*s = strdup(tdefval->ptr)) == NULL) + return ENOMEM; + } else { + abort(); + } + break; + } + return ret; /* Error decoding required field */ + } + p += newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + Der_type dertype; + size_t newsize = 0; + size_t datalen, l = 0; + void *olddata = data; + int is_indefinite = 0; + int subflags = flags; + int replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); + void *el = data = DPO(data, t->offset); + void **pel = (void **)el; + + /* + * XXX If this type (chasing t->ptr through IMPLICIT tags, if this + * one is too, till we find a non-TTag) is a [UNIVERSAL SET] type, + * then we have to accept fields out of order. For each field tag + * we see we'd have to do a linear search of the SET's template + * because it won't be sorted (or we could sort a copy and do a + * binary search on that, but these SETs will always be small so it + * won't be worthwhile). We'll need a utility function to do all + * of this. + */ + ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt), + &dertype, A1_TAG_TAG(t->tt), + &datalen, &l); + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + data = olddata; + break; + } else if (t->tt & A1_FLAG_DEFAULT) { + if (!tdefval) + return ASN1_PARSE_ERROR; /* Can't happen */ + /* + * Defaulted field not present in encoding, presumably, + * though we should really look more carefully at `ret'. + */ + if (tdefval->tt & A1_DV_BOOLEAN) { + int *i = (void *)(char *)data; + + *i = tdefval->ptr ? 1 : 0; + } else if (tdefval->tt & A1_DV_INTEGER64) { + int64_t *i = (void *)(char *)data; + + *i = (int64_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER32) { + int32_t *i = (void *)(char *)data; + + *i = (int32_t)(intptr_t)tdefval->ptr; + } else if (tdefval->tt & A1_DV_INTEGER) { + struct heim_integer *i = (void *)(char *)data; + + if ((ret = der_copy_heim_integer(tdefval->ptr, i))) + return ret; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + char **s = data; + + if ((*s = strdup(tdefval->ptr)) == NULL) + return ENOMEM; + } else { + abort(); + } + data = olddata; + break; + } + return ret; /* Error decoding required field */ + } + + p += l; len -= l; + + /* + * Only allow indefinite encoding for OCTET STRING and BER + * for now. Should handle BIT STRING too. + */ + + if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) { + const struct asn1_template *subtype = t->ptr; + subtype++; /* skip header */ + + if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) && + A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING) + subflags |= A1_PF_INDEFINTE; + } + + if (datalen == ASN1_INDEFINITE) { + if ((flags & A1_PF_ALLOW_BER) == 0) + return ASN1_GOT_BER; + is_indefinite = 1; + datalen = len; + if (datalen < 2) + return ASN1_OVERRUN; + /* hide EndOfContent for sub-decoder, catching it below */ + datalen -= 2; + } else if (datalen > len) + return ASN1_OVERRUN; + + if (t->tt & A1_FLAG_OPTIONAL) { + size_t ellen = _asn1_sizeofType(t->ptr); + + *pel = calloc(1, ellen); + if (*pel == NULL) + return ENOMEM; + data = *pel; + } + + if (replace_tag) { + const struct asn1_template *subtype = t->ptr; + int have_tag = 0; + + /* + * So, we have an IMPLICIT tag. What we want to do is find the + * template for the body of the type so-tagged. That's going + * to be a template that has a tag that isn't itself IMPLICIT. + * + * So we chase the pointer in the template until we find such a + * thing, then decode using that template. + */ + while (!have_tag) { + subtype++; + if ((subtype->tt & A1_OP_MASK) == A1_OP_TAG) + replace_tag = (subtype->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); + if (replace_tag) { + subtype = subtype->ptr; + continue; + } + if ((subtype->tt & A1_OP_MASK) == A1_OP_TAG) { + ret = _asn1_decode(subtype->ptr, subflags, p, datalen, data, &newsize); + have_tag = 1; + } else { + subtype = subtype->ptr; + } + } + } else { + ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize); + } + if (ret == 0 && !is_indefinite && newsize != datalen) + /* Hidden data */ + ret = ASN1_EXTRA_DATA; + + if (ret == 0) { + if (is_indefinite) { + /* If we use indefinite encoding, the newsize is the datasize. */ + datalen = newsize; + } + + len -= datalen; + p += datalen; + + /* + * Indefinite encoding needs a trailing EndOfContent, + * check for that. + */ + if (is_indefinite) { + ret = der_match_tag_and_length(p, len, ASN1_C_UNIV, + &dertype, UT_EndOfContent, + &datalen, &l); + if (ret == 0 && dertype != PRIM) + ret = ASN1_BAD_ID; + else if (ret == 0 && datalen != 0) + ret = ASN1_INDEF_EXTRA_DATA; + if (ret == 0) { + p += l; len -= l; + } + } + } + if (ret) { + if (!(t->tt & A1_FLAG_OPTIONAL)) + return ret; + + _asn1_free(t->ptr, data); + free(data); + *pel = NULL; + return ret; + } + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + void *el = DPO(data, t->offset); + + /* + * INDEFINITE primitive types are one element after the + * same type but non-INDEFINITE version. + */ + if (flags & A1_PF_INDEFINTE) + type++; + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (asn1_template_prim[type].decode)(p, len, el, &newsize); + if (ret) + return ret; + p += newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t newsize; + size_t ellen = _asn1_sizeofType(t->ptr); + size_t vallength = 0; + + while (len > 0) { + void *tmp; + size_t newlen = vallength + ellen; + if (vallength > newlen) + return ASN1_OVERFLOW; + + /* XXX Slow */ + tmp = realloc(el->val, newlen); + if (tmp == NULL) + return ENOMEM; + + memset(DPO(tmp, vallength), 0, ellen); + el->val = tmp; + + el->len++; + ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len, + DPO(el->val, vallength), &newsize); + if (ret) + return ret; + vallength = newlen; + p += newsize; len -= newsize; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t bsize = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + size_t pos = 0; + + bmember++; + + memset(data, 0, bsize); + + if (len < 1) + return ASN1_OVERRUN; + p++; len--; + + while (belements && len) { + while (bmember->offset / 8 > pos / 8) { + if (len < 1) + break; + p++; len--; + pos += 8; + } + if (len) { + _asn1_bmember_get_bit(p, data, bmember->offset, bsize); + belements--; bmember++; + } + } + len = 0; + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + unsigned int *element = DPO(data, choice->offset); + size_t datalen; + unsigned int i; + + /* + * CHOICE element IDs are assigned in monotonically increasing + * fashion. Therefore any unrealistic value is a suitable invalid + * CHOICE value. The largest binary value (or -1 if treating the + * enum as signed on a twos-complement system, or...) will do. + */ + *element = ~0; + + for (i = 1; i < A1_HEADER_LEN(choice) + 1 && choice[i].tt; i++) { + /* + * This is more permissive than is required. CHOICE + * alternatives must have different outer tags, so in principle + * we should just match the tag at `p' and `len' in sequence to + * the choice alternatives. + * + * Trying every alternative instead happens to do this anyways + * because each one will first match the tag at `p' and `len', + * but if there are CHOICE altnernatives with the same outer + * tag, then we'll allow it, and they had better be unambiguous + * in their internal details, otherwise there would be some + * aliasing. + * + * Arguably the *compiler* should detect ambiguous CHOICE types + * and raise an error, then we don't have to be concerned here + * at all. + */ + ret = _asn1_decode(choice[i].ptr, 0, p, len, + DPO(data, choice[i].offset), &datalen); + if (ret == 0) { + *element = i; + p += datalen; len -= datalen; + break; + } + _asn1_free(choice[i].ptr, DPO(data, choice[i].offset)); + if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && + ret != ASN1_MISSING_FIELD) + return ret; + } + if (i >= A1_HEADER_LEN(choice) + 1 || !choice[i].tt) { + /* + * If this is an extensible CHOICE, then choice->tt will be the + * offset to u.ellipsis. If it's not, then this "extension" is + * an error and must stop parsing it. (We could be permissive + * and throw away the extension, though one might as well just + * mark such a CHOICE as extensible.) + */ + if (choice->tt == 0) + return ASN1_BAD_ID; + + /* This is the ellipsis case */ + *element = 0; + ret = der_get_octet_string(p, len, + DPO(data, choice->tt), &datalen); + if (ret) + return ret; + p += datalen; len -= datalen; + } + + break; + } + default: + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + t++; + elements--; + } + /* if we are using padding, eat up read of context */ + if (template_flags & A1_HF_ELLIPSIS) + len = 0; + + oldlen -= len; + + if (size) + *size = oldlen; + + /* + * saved the raw bits if asked for it, useful for signature + * verification. + */ + if (startp) { + heim_octet_string *save = data; + + save->data = malloc(oldlen); + if (save->data == NULL) + return ENOMEM; + else { + save->length = oldlen; + memcpy(save->data, startp, oldlen); + } + } + return 0; +} + +/* + * This should be called with a `A1_TAG_T(ASN1_C_UNIV, PRIM, UT_Integer)' + * template as the `ttypeid'. + */ +static int +typeid_int_copy(void *intp, + int64_t i, + const struct asn1_template *ttypeid) +{ + const struct asn1_template *tint = ttypeid->ptr; + + if ((tint[1].tt & A1_OP_MASK) != A1_OP_PARSE) + return -1; + if (A1_PARSE_TYPE(tint[1].tt) != A1T_INTEGER) + return -1; + switch (tint[0].offset) { + case 8: *((int64_t *)intp) = i; return 0; + case 4: *((int32_t *)intp) = i; return 0; + default: memset(intp, 0, tint[0].offset); return 0; + } +} + +/* See commentary in _asn1_decode_open_type() */ +static int +_asn1_encode_open_type(const struct asn1_template *t, + const void *data, /* NOTE: Not really const */ + const struct asn1_template *ttypeid, + const struct asn1_template *topentype) +{ + const struct asn1_template *ttypeid_univ = ttypeid; + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + size_t sz, i; + unsigned int *lenp = NULL; + unsigned int len = 1; + int element = *(const int *)DPOC(data, t->offset); + int typeid_is_oid = 0; + int typeid_is_int = 0; + int enotsup = 0; + int ret = 0; + + if (element == 0 || element >= A1_HEADER_LEN(tos) + 1) + return 0; + + if (t->tt & A1_OS_OT_IS_ARRAY) { + /* The actual `len' is from the decoded open type field */ + len = *(const unsigned int *)DPOC(data, t->offset + sizeof(element)); + + if (!len) + return 0; /* The app may be encoding the open type by itself */ + } + + /* Work out the type ID field's type */ + while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG && + A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) || + ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) { + ttypeid_univ = ttypeid_univ->ptr; + ttypeid_univ++; + } + switch (ttypeid_univ->tt & A1_OP_MASK) { + case A1_OP_TAG: + if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV) { + enotsup = 1; + break; + } + switch (A1_TAG_TAG(ttypeid_univ->tt)) { + case UT_OID: + typeid_is_oid = 1; + break; + case UT_Integer: { + const struct asn1_template *tint = ttypeid_univ->ptr; + + tint++; + if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE || + A1_PARSE_TYPE(tint->tt) != A1T_INTEGER) { + enotsup = 1; + break; + } + typeid_is_int = 1; + break; + } + default: enotsup = 1; break; + } + break; + default: enotsup = 1; break; + } + + /* + * The app may not be aware of our automatic open type handling, so if the + * open type already appears to have been encoded, then ignore the decoded + * values. + */ + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + struct heim_base_data *os = DPO(data, topentype->offset); + + if (os->length && os->data) + return 0; + } else { + struct heim_base_data **os = DPO(data, topentype->offset + sizeof(len)); + + while (sizeof(void *) != sizeof(unsigned int) && + ((uintptr_t)os) % sizeof(void *) != 0) + os = (void *)(((char *)os) + sizeof(unsigned int)); + + lenp = DPO(data, topentype->offset); + if (*lenp == len && os[0]->length && os[0]->data) + return 0; + } + + if (typeid_is_int) { + /* + * Copy the int from the type ID object field to the type ID struct + * field. + */ + ret = typeid_int_copy(DPO(data, ttypeid->offset), + (intptr_t)tos[3 + (element-1)*3].ptr, ttypeid_univ); + } else if (typeid_is_oid) { + /* + * Copy the OID from the type ID object field to the type ID struct + * field. + */ + ret = der_copy_oid(tos[3 + (element-1)*3].ptr, DPO(data, ttypeid->offset)); + } else + enotsup = 1; + + /* + * If the app did not already encode the open type, we can't help it if we + * don't know what it is. + */ + if (enotsup) + return ENOTSUP; + + tactual_type = &tos[(element-1)*3 + 4]; + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + struct heim_base_data *os = DPO(data, topentype->offset); + const void * const *d = DPOC(data, t->offset + sizeof(element)); + + while (sizeof(void *) != sizeof(element) && + ((uintptr_t)d) % sizeof(void *) != 0) { + d = (void *)(((char *)d) + sizeof(element)); + } + + os->length = _asn1_length(tactual_type->ptr, *d); + if ((os->data = malloc(os->length)) == NULL) + return ENOMEM; + ret = _asn1_encode(tactual_type->ptr, (os->length - 1) + (unsigned char *)os->data, os->length, *d, &sz); + } else { + struct heim_base_data *os; + const void * const *val = + DPOC(data, t->offset + sizeof(element) + sizeof(*lenp)); + + if ((os = calloc(len, sizeof(*os))) == NULL) + return ENOMEM; + + *lenp = len; + for (i = 0; ret == 0 && i < len; i++) { + os[i].length = _asn1_length(tactual_type->ptr, val[i]); + if ((os[i].data = malloc(os[i].length)) == NULL) + ret = ENOMEM; + if (ret == 0) + ret = _asn1_encode(tactual_type->ptr, (os[i].length - 1) + (unsigned char *)os[i].data, os[i].length, + val[i], &sz); + } + if (ret) { + for (i = 0; i < (*lenp); i++) + free(os[i].data); + free(os); + *lenp = 0; + return ret; + } + *(struct heim_base_data **)DPO(data, topentype->offset + sizeof(len)) = os; + } + return ret; +} + +int +_asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size) +{ + const struct asn1_template *tbase = t; + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + size_t oldlen = len; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + size_t opentypeid = t->tt & ((1<<10)-1); + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + ret = _asn1_encode_open_type(t, data, + template4member(tbase, opentypeid), + template4member(tbase, opentype)); + if (ret) + return ret; + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + /* Compare tdefval to whatever's at `el' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)el; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + break; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)el; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)el; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)el; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = el; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + break; + } else { + abort(); + } + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret = _asn1_encode(t->ptr, p, len, el, &newsize); + } else { + const struct asn1_type_func *f = t->ptr; + ret = (f->encode)(p, len, el, &newsize); + } + + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_TAG: { + const void *olddata = data; + size_t l, datalen = 0; + int replace_tag = 0; + + /* + * XXX If this type (chasing t->ptr through IMPLICIT tags, if this + * one is too) till we find a non-TTag) is a [UNIVERSAL SET] type, + * then we have to sort [a copy of] its template by tag, then + * encode the SET using that sorted template. These SETs will + * generally be small, so when they are we might want to allocate + * the copy on the stack and insertion sort it. We'll need a + * utility function to do all of this. + */ + + data = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + int exclude = 0; + + /* Compare tdefval to whatever's at `data' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)data; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)data; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)data; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)data; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = data; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + exclude = 1; + } else { + abort(); + } + if (exclude) { + data = olddata; + break; + } + } + + replace_tag = (t->tt & A1_FLAG_IMPLICIT) && is_tagged(t->ptr); + + /* IMPLICIT tags need special handling (see gen_encode.c) */ + if (replace_tag) { + unsigned char *pfree, *psave = p; + Der_class found_class; + Der_type found_type = 0; + unsigned int found_tag; + size_t lensave = len; + size_t oldtaglen = 0; + size_t taglen = der_length_tag(A1_TAG_TAG(t->tt));; + + /* Allocate a buffer at least as big as we need */ + len = _asn1_length(t->ptr, data) + taglen; + if ((p = pfree = malloc(len)) == NULL) { + ret = ENOMEM; + } else { + /* + * Encode into it (with the wrong tag, which we'll replace + * below). + */ + p += len - 1; + ret = _asn1_encode(t->ptr, p, len, data, &datalen); + } + if (ret == 0) { + /* Get the old tag and, critically, its length */ + len -= datalen; p -= datalen; + ret = der_get_tag(p + 1, datalen, &found_class, &found_type, + &found_tag, &oldtaglen); + } + if (ret == 0) { + /* Drop the old tag */ + len += oldtaglen; p += oldtaglen; + /* Put the new tag */ + ret = der_put_tag(p, len, + A1_TAG_CLASS(t->tt), + found_type, + A1_TAG_TAG(t->tt), &l); + } + if (ret == 0) { + /* Copy the encoding where it belongs */ + psave -= (datalen + l - oldtaglen); + lensave -= (datalen + l - oldtaglen); + memcpy(psave + 1, p + 1 - l, datalen + l - oldtaglen); + p = psave; + len = lensave; + } + free(pfree); + } else { + /* Easy case */ + ret = _asn1_encode(t->ptr, p, len, data, &datalen); + if (ret) + return ret; + + len -= datalen; p -= datalen; + + ret = der_put_length_and_tag(p, len, datalen, + A1_TAG_CLASS(t->tt), + A1_TAG_TYPE(t->tt), + A1_TAG_TAG(t->tt), &l); + if (ret == 0) { + p -= l; len -= l; + } + } + if (ret) + return ret; + + data = olddata; + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + size_t newsize; + const void *el = DPOC(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + + ret = (asn1_template_prim[type].encode)(p, len, el, &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + + break; + } + case A1_OP_SETOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + heim_octet_string *val; + unsigned char *elptr = el->val; + size_t i, totallen; + + if (el->len == 0) + break; + + if (el->len > UINT_MAX/sizeof(val[0])) + return ERANGE; + + val = calloc(el->len, sizeof(val[0])); + if (val == NULL) + return ENOMEM; + + for(totallen = 0, i = 0; i < el->len; i++) { + unsigned char *next; + size_t l; + + val[i].length = _asn1_length(t->ptr, elptr); + if (val[i].length) { + val[i].data = malloc(val[i].length); + if (val[i].data == NULL) { + ret = ENOMEM; + break; + } + } + + ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1), + val[i].length, elptr, &l); + if (ret) + break; + + next = elptr + ellen; + if (next < elptr) { + ret = ASN1_OVERFLOW; + break; + } + elptr = next; + totallen += val[i].length; + } + if (ret == 0 && totallen > len) + ret = ASN1_OVERFLOW; + if (ret) { + for (i = 0; i < el->len; i++) + free(val[i].data); + free(val); + return ret; + } + + len -= totallen; + + qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort); + + i = el->len - 1; + do { + p -= val[i].length; + memcpy(p + 1, val[i].data, val[i].length); + free(val[i].data); + } while(i-- > 0); + free(val); + + break; + + } + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + size_t newsize; + unsigned int i; + unsigned char *elptr = el->val; + + if (el->len == 0) + break; + + elptr += ellen * (el->len - 1); + + for (i = 0; i < el->len; i++) { + ret = _asn1_encode(t->ptr, p, len, + elptr, + &newsize); + if (ret) + return ret; + p -= newsize; len -= newsize; + elptr -= ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t bsize = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + size_t pos; + unsigned char c = 0; + unsigned int bitset = 0; + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + bmember += belements; + + if (rfc1510) + pos = 31; + else + pos = bmember->offset; + + while (belements && len) { + while (bmember->offset / 8 < pos / 8) { + if (rfc1510 || bitset || c) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + c = 0; + pos -= 8; + } + _asn1_bmember_put_bit(&c, data, bmember->offset, bsize, &bitset); + belements--; bmember--; + } + if (rfc1510 || bitset) { + if (len < 1) + return ASN1_OVERFLOW; + *p-- = c; len--; + } + + if (len < 1) + return ASN1_OVERFLOW; + if (rfc1510 || bitset == 0) + *p-- = 0; + else + *p-- = bitset - 1; + + len--; + + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + size_t datalen; + const void *el; + + if (*element > A1_HEADER_LEN(choice)) { + printf("element: %d\n", *element); + return ASN1_PARSE_ERROR; + } + + if (*element == 0) { + if (choice->tt) { + /* This is an extensible CHOICE */ + ret += der_put_octet_string(p, len, + DPOC(data, choice->tt), &datalen); + len -= datalen; p -= datalen; + } /* else this is really an error -- XXX what to do? */ + } else { + choice += *element; + el = DPOC(data, choice->offset); + ret = _asn1_encode(choice->ptr, p, len, el, &datalen); + if (ret) + return ret; + len -= datalen; p -= datalen; + } + + break; + } + default: + ABORT_ON_ERROR(); + } + t--; + elements--; + } + if (size) + *size = oldlen - len; + + return 0; +} + +static size_t +_asn1_length_open_type_helper(const struct asn1_template *t, + size_t sz) +{ + const struct asn1_template *tinner = t->ptr; + + switch (t->tt & A1_OP_MASK) { + case A1_OP_TAG: + /* XXX Not tail-recursive :( */ + sz = _asn1_length_open_type_helper(tinner, sz); + sz += der_length_len(sz); + sz += der_length_tag(A1_TAG_TAG(t->tt)); + return sz; + default: + return sz; + } +} + +static size_t +_asn1_length_open_type_id(const struct asn1_template *t, + const void *data) +{ + struct asn1_template pretend[2] = { + { 0, 0, ((void*)(uintptr_t)1) }, + }; + pretend[1] = *t; + while ((t->tt & A1_OP_MASK) == A1_OP_TAG) + t = t->ptr; + pretend[0].offset = t->offset; + return _asn1_length(pretend, data); +} + +/* See commentary in _asn1_encode_open_type() */ +static size_t +_asn1_length_open_type(const struct asn1_template *tbase, + const struct asn1_template *t, + const void *data, + const struct asn1_template *ttypeid, + const struct asn1_template *topentype) +{ + const struct asn1_template *ttypeid_univ = ttypeid; + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + const unsigned int *lenp = NULL; + unsigned int len = 1; + size_t sz = 0; + size_t i; + int element = *(const int *)DPOC(data, t->offset); + int typeid_is_oid = 0; + int typeid_is_int = 0; + + /* If nothing to encode, we add nothing to the length */ + if (element == 0 || element >= A1_HEADER_LEN(tos) + 1) + return 0; + if (t->tt & A1_OS_OT_IS_ARRAY) { + len = *(const unsigned int *)DPOC(data, t->offset + sizeof(element)); + if (!len) + return 0; + } + + /* Work out the type ID field's type */ + while (((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TAG && + A1_TAG_CLASS(ttypeid_univ->tt) == ASN1_C_CONTEXT) || + ((ttypeid_univ->tt & A1_OP_MASK) == A1_OP_TYPE)) { + ttypeid_univ = ttypeid_univ->ptr; + ttypeid_univ++; + } + switch (ttypeid_univ->tt & A1_OP_MASK) { + case A1_OP_TAG: + if (A1_TAG_CLASS(ttypeid_univ->tt) != ASN1_C_UNIV) + return 0; + switch (A1_TAG_TAG(ttypeid_univ->tt)) { + case UT_OID: + typeid_is_oid = 1; + break; + case UT_Integer: { + const struct asn1_template *tint = ttypeid_univ->ptr; + + tint++; + if ((tint->tt & A1_OP_MASK) != A1_OP_PARSE || + A1_PARSE_TYPE(tint->tt) != A1T_INTEGER) + return 0; + typeid_is_int = 1; + break; + } + default: return 0; + } + break; + default: return 0; + } + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + struct heim_base_data *os = DPO(data, topentype->offset); + + if (os->length && os->data) + return 0; + } else { + struct heim_base_data **os = DPO(data, topentype->offset + sizeof(len)); + + while (sizeof(void *) != sizeof(unsigned int) && + ((uintptr_t)os) % sizeof(void *) != 0) + os = (void *)(((char *)os) + sizeof(unsigned int)); + + lenp = DPOC(data, topentype->offset); + if (*lenp == len && os[0]->length && os[0]->data) + return 0; + } + + /* Compute the size of the type ID field */ + if (typeid_is_int) { + int64_t i8; + int32_t i4; + + switch (ttypeid_univ->offset) { + case 8: + i8 = (intptr_t)t->ptr; + sz = _asn1_length_open_type_id(ttypeid, &i8); + i8 = 0; + sz -= _asn1_length_open_type_id(ttypeid, &i8); + break; + case 4: + i4 = (intptr_t)t->ptr; + sz = _asn1_length_open_type_id(ttypeid, &i4); + i4 = 0; + sz -= _asn1_length_open_type_id(ttypeid, &i8); + break; + default: + return 0; + } + } else if (typeid_is_oid) { + heim_oid no_oid = { 0, 0 }; + + sz = _asn1_length_open_type_id(ttypeid, tos[3 + (element - 1)*3].ptr); + sz -= _asn1_length_open_type_id(ttypeid, &no_oid); + } + + tactual_type = &tos[(element-1)*3 + 4]; + + /* Compute the size of the encoded value(s) */ + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + const void * const *d = DPOC(data, t->offset + sizeof(element)); + + while (sizeof(void *) != sizeof(element) && + ((uintptr_t)d) % sizeof(void *) != 0) + d = (void *)(((char *)d) + sizeof(element)); + if (*d) + sz += _asn1_length(tactual_type->ptr, *d); + } else { + size_t bodysz; + const void * const * val = + DPOC(data, t->offset + sizeof(element) + sizeof(*lenp)); + + /* Compute the size of the encoded SET OF / SEQUENCE OF body */ + for (i = 0, bodysz = 0; i < len; i++) { + if (val[i]) + bodysz += _asn1_length(tactual_type->ptr, val[i]); + } + + /* + * We now know the size of the body of the SET OF or SEQUENCE OF. Now + * we just need to count the length of all the TLs on the outside. + */ + sz += _asn1_length_open_type_helper(topentype, bodysz); + } + return sz; +} + +size_t +_asn1_length(const struct asn1_template *t, const void *data) +{ + const struct asn1_template *tbase = t; + size_t elements = A1_HEADER_LEN(t); + size_t ret = 0; + + t += A1_HEADER_LEN(t); + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + size_t opentypeid = t->tt & ((1<<10)-1); + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + ret += _asn1_length_open_type(tbase, t, data, + template4member(tbase, opentypeid), + template4member(tbase, opentype)); + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + if (*pel == NULL) + break; + el = *pel; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + + /* Compare tdefval to whatever's at `el' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)el; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + break; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)el; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)el; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + break; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)el; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + break; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = el; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + break; + } else { + abort(); + } + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + ret += _asn1_length(t->ptr, el); + } else { + const struct asn1_type_func *f = t->ptr; + ret += (f->length)(el); + } + break; + } + case A1_OP_TAG: { + size_t datalen; + const void *olddata = data; + size_t oldtaglen = 0; + + data = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **el = (void **)data; + if (*el == NULL) { + data = olddata; + break; + } + data = *el; + } else if ((t->tt & A1_FLAG_DEFAULT) && elements > 1) { + const struct asn1_template *tdefval = t - 1; + int exclude = 0; + + /* Compare tdefval to whatever's at `data' */ + if (tdefval->tt & A1_DV_BOOLEAN) { + const int *i = (void *)(char *)data; + + if ((*i && tdefval->ptr) || (!*i && !tdefval->ptr)) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER64) { + const int64_t *i = (void *)(char *)data; + + if (*i == (int64_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER32) { + const int32_t *i = (void *)(char *)data; + + if ((int64_t)(intptr_t)tdefval->ptr <= INT_MAX && + (int64_t)(intptr_t)tdefval->ptr >= INT_MIN && + *i == (int32_t)(intptr_t)tdefval->ptr) + exclude = 1; + } else if (tdefval->tt & A1_DV_INTEGER) { + const struct heim_integer *i = (void *)(char *)data; + + if (der_heim_integer_cmp(i, tdefval->ptr) == 0) + exclude = 1; + } else if (tdefval->tt & A1_DV_UTF8STRING) { + const char * const *s = data; + + if (*s && strcmp(*s, tdefval->ptr) == 0) + exclude = 1; + } else { + abort(); + } + if (exclude) { + data = olddata; + break; + } + } + + if (t->tt & A1_FLAG_IMPLICIT) + oldtaglen = inner_type_taglen(t->ptr); + + datalen = _asn1_length(t->ptr, data); + ret += datalen; + ret += der_length_tag(A1_TAG_TAG(t->tt)); + ret += oldtaglen ? -oldtaglen : der_length_len(datalen); + data = olddata; + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + ret += (asn1_template_prim[type].length)(el); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + ret += _asn1_length(t->ptr, element); + element += ellen; + } + + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + int rfc1510 = (bmember->tt & A1_HBF_RFC1510); + + if (rfc1510) { + ret += 5; + } else { + + ret += 1; + + bmember += belements; + + while (belements) { + if (_asn1_bmember_isset_bit(data, bmember->offset, size)) { + ret += (bmember->offset / 8) + 1; + break; + } + belements--; bmember--; + } + } + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + if (choice->tt) + ret += der_length_octet_string(DPOC(data, choice->tt)); + } else { + choice += *element; + ret += _asn1_length(choice->ptr, DPOC(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + elements--; + t--; + } + return ret; +} + +/* See commentary in _asn1_decode_open_type() */ +static void +_asn1_free_open_type(const struct asn1_template *t, /* object set template */ + void *data) +{ + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + unsigned int *lenp = NULL; /* Pointer to array length field */ + unsigned int len = 1; /* Array length */ + size_t i; + void **dp; + void **val; + int *elementp = DPO(data, t->offset); /* Choice enum pointer */ + + /* XXX We assume sizeof(enum) == sizeof(int) */ + if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1) + return; /* Unknown choice -> it's not decoded, nothing to free here */ + tactual_type = tos[3*(*elementp - 1) + 4].ptr; + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + dp = DPO(data, t->offset + sizeof(*elementp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + if (*dp) { + _asn1_free(tactual_type, *dp); + free(*dp); + *dp = NULL; + } + return; + } + + lenp = DPO(data, t->offset + sizeof(*elementp)); + len = *lenp; + dp = DPO(data, t->offset + sizeof(*elementp) + sizeof(*lenp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + val = *dp; + + for (i = 0; i < len; i++) { + if (val[i]) { + _asn1_free(tactual_type, val[i]); + free(val[i]); + } + } + free(val); + *lenp = 0; + *dp = NULL; +} + +void +_asn1_free(const struct asn1_template *t, void *data) +{ + size_t elements = A1_HEADER_LEN(t); + + if (t->tt & A1_HF_PRESERVE) + der_free_octet_string(data); + + t++; + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + _asn1_free_open_type(t, data); + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: + case A1_OP_TYPE_DECORATE: + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + void *el = DPO(data, t->offset); + void **pel = (void **)el; + + if (t->tt & A1_FLAG_OPTIONAL) { + if (*pel == NULL) + break; + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { + _asn1_free(t->ptr, el); + } else if ((t->tt & A1_OP_MASK) == A1_OP_TYPE_EXTERN) { + const struct asn1_type_func *f = t->ptr; + (f->release)(el); + } else { + /* A1_OP_TYPE_DECORATE_EXTERN */ + const struct asn1_type_func *f = t->ptr; + + if (f && f->release) + (f->release)(el); + else if (f) + memset(el, 0, f->size); + } + if (t->tt & A1_FLAG_OPTIONAL) { + free(el); + *pel = NULL; + } + + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + void *el = DPO(data, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + (asn1_template_prim[type].release)(el); + break; + } + case A1_OP_TAG: { + void *el = DPO(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pel = (void **)el; + + if (*pel == NULL) + break; + _asn1_free(t->ptr, *pel); + free(*pel); + *pel = NULL; + } else { + _asn1_free(t->ptr, el); + } + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + struct template_of *el = DPO(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + unsigned char *element = el->val; + unsigned int i; + + for (i = 0; i < el->len; i++) { + _asn1_free(t->ptr, element); + element += ellen; + } + free(el->val); + el->val = NULL; + el->len = 0; + + break; + } + case A1_OP_BMEMBER: + break; + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + + if (*element > A1_HEADER_LEN(choice)) + break; + + if (*element == 0) { + /* + * If choice->tt != 0 then this is an extensible choice, and + * the offset choice->tt is the offset to u.ellipsis. + */ + if (choice->tt != 0) + der_free_octet_string(DPO(data, choice->tt)); + /* + * Else this was a not-fully initialized CHOICE. We could + * stand to memset clear the rest of it though... + */ + } else { + choice += *element; + _asn1_free(choice->ptr, DPO(data, choice->offset)); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } +} + +static char * +getindent(int flags, unsigned int i) +{ + char *s; + + if (!(flags & ASN1_PRINT_INDENT) || i == 0) + return NULL; + if (i > 128) + i = 128; + if ((s = malloc(i * 2 + 2)) == NULL) + return NULL; + s[0] = '\n'; + s[i * 2 + 1] = '\0'; + memset(s + 1, ' ', i * 2); + return s; +} + +static struct rk_strpool *_asn1_print(const struct asn1_template *, + struct rk_strpool *, + int, + unsigned int, + const void *, + const heim_octet_string *); + +/* See commentary in _asn1_decode_open_type() */ +static struct rk_strpool * +_asn1_print_open_type(const struct asn1_template *t, /* object set template */ + struct rk_strpool *r, + int flags, + unsigned int indent, + const void *data, + const char *opentype_name) +{ + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + const unsigned int *lenp = NULL; /* Pointer to array length field */ + unsigned int len = 1; /* Array length */ + size_t i; + const void * const *dp; + const void * const *val; + const int *elementp = DPOC(data, t->offset); /* Choice enum pointer */ + char *indents = getindent(flags, indent); + + /* XXX We assume sizeof(enum) == sizeof(int) */ + if (!*elementp || *elementp >= A1_HEADER_LEN(tos) + 1) { + r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"_ERROR_DECODING_\"", + indents ? indents : "", opentype_name); + free(indents); + return r; + } + tactual_type = tos[3*(*elementp - 1) + 4].ptr; + + r = rk_strpoolprintf(r, ",%s\"_%s_choice\":\"%s\"", + indents ? indents : "", opentype_name, + (const char *)tos[3*(*elementp - 1) + 2].ptr); + if (!r) { + free(indents); + return r; + } + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + dp = DPOC(data, t->offset + sizeof(*elementp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + if (*dp) { + struct rk_strpool *r2 = NULL; + char *s = NULL; + + r2 = _asn1_print(tactual_type, r2, flags, indent + 1, *dp, NULL); + if (r2 == NULL) { + r = rk_strpoolprintf(r, ",%s\"_%s\":\"_ERROR_FORMATTING_\"", + indents ? indents : "", opentype_name); + free(indents); + return r; + } + s = rk_strpoolcollect(r2); + if (s) + r = rk_strpoolprintf(r, ",%s\"_%s\":%s", + indents ? indents : "", opentype_name, s); + free(s); + } + free(indents); + return r; + } + + lenp = DPOC(data, t->offset + sizeof(*elementp)); + len = *lenp; + dp = DPOC(data, t->offset + sizeof(*elementp) + sizeof(*lenp)); + while (sizeof(void *) != sizeof(*elementp) && + ((uintptr_t)dp) % sizeof(void *) != 0) + dp = (void *)(((char *)dp) + sizeof(*elementp)); + val = *dp; + + r = rk_strpoolprintf(r, ",%s\"_%s\":[", indents ? indents : "", + opentype_name); + free(indents); + indents = getindent(flags, indent + 1); + r = rk_strpoolprintf(r, "%s", indents ? indents : ""); + for (i = 0; r && i < len; i++) { + struct rk_strpool *r2 = NULL; + char *s = NULL;; + + if (val[i]) { + r2 = _asn1_print(tactual_type, r2, flags, indent + 2, val[i], NULL); + if (r2 == NULL) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + } + if (i) + r = rk_strpoolprintf(r, ",%s", indents ? indents : ""); + if (r) + r = rk_strpoolprintf(r, "%s", (s = rk_strpoolcollect(r2))); + free(s); + } + free(indents); + return rk_strpoolprintf(r, "]"); +} + +static struct rk_strpool * +_asn1_print(const struct asn1_template *t, + struct rk_strpool *r, + int flags, + unsigned int indent, + const void *data, + const heim_octet_string *saved) +{ + const struct asn1_template *tbase = t; + const struct asn1_template *tnames; + size_t nelements = A1_HEADER_LEN(t); + size_t elements = nelements; + size_t nnames = 0; + char *indents = getindent(flags, indent); + + for (t += nelements; t > tbase && (t->tt & A1_OP_MASK) == A1_OP_NAME; t--) + nnames++; + + tnames = tbase + nelements - nnames + 1; + + if (!r) + r = rk_strpoolprintf(r, "%s", ""); + + if (nnames) + r = rk_strpoolprintf(r, "%s{\"_type\":\"%s\"", + indents ? indents : "", + (const char *)(tnames++)->ptr); + if (saved && r) { + char *s = der_print_octet_string(data, 0); + + if (!s) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + r = rk_strpoolprintf(r, ",%s\"_save\":\"%s\"", + indents ? indents : "", s); + free(s); + } + saved = NULL; + if (tbase->tt & A1_HF_PRESERVE) + saved = data; + + t = tbase + 1; + while (r && elements && (t->tt & A1_OP_MASK) != A1_OP_NAME) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_NAME: + continue; + case A1_OP_DEFVAL: + t++; + elements--; + continue; + case A1_OP_OPENTYPE_OBJSET: { + size_t opentype = (t->tt >> 10) & ((1<<10)-1); + r = _asn1_print_open_type(t, r, flags, indent + 1, data, + tbase[(nelements - nnames) + 2 + opentype].ptr); + t++; + elements--; + continue; + } + default: break; + } + if (nnames && + (t->tt & A1_OP_MASK) != A1_OP_TYPE_DECORATE_EXTERN && + (t->tt & A1_OP_MASK) != A1_OP_TYPE_DECORATE) + r = rk_strpoolprintf(r, ",%s\"%s\":", + indents ? indents : "", + (const char *)(tnames++)->ptr); + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: + break; + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: break; + case A1_OP_TYPE_DECORATE: break; /* We could probably print this though */ + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + const void * const *pel = (const void *const *)el; + if (*pel == NULL) { + r = rk_strpoolprintf(r, "null"); + break; + } + el = *pel; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { + r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved); + } else { + const struct asn1_type_func *f = t->ptr; + char *s = NULL; + + s = (f->print)(el, 0); + if (s == NULL) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + r = rk_strpoolprintf(r, "%s", s); + free(s); + } + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *el = DPOC(data, t->offset); + char *s = NULL; + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + break; + } + + if (type == A1T_IMEMBER && t->ptr) { + /* Enumeration. Use the symbolic name of this value */ + const struct asn1_template *tenum = t->ptr; + size_t left = 0; + size_t right = A1_HEADER_LEN(tenum); + size_t mid; + uint32_t v = *(unsigned int *)el; + int c = -1; + + while (left <= right) { + mid = (left + right) >> 1; + + if ((tenum[mid].tt & A1_OP_MASK) != A1_OP_NAME) + break; + c = v - tenum[mid].offset; + if (c < 0) { + if (mid) + right = mid - 1; + else + break; + } else if (c > 0) { + left = mid + 1; + } else { + break; + } + } + if (c == 0) { + r = rk_strpoolprintf(r, "\"%s\"", (const char *)tenum[mid].ptr); + break; + } + } + s = (asn1_template_prim[type].print)(el, flags); + switch (type) { + case A1T_OID: + case A1T_IMEMBER: + case A1T_BOOLEAN: + case A1T_INTEGER: + case A1T_INTEGER64: + case A1T_UNSIGNED: + case A1T_UNSIGNED64: + if (s) + r = rk_strpoolprintf(r, "%s", s); + break; + default: { + char *s2 = NULL; + + if (s) + (void) rk_strasvis(&s2, s, VIS_CSTYLE|VIS_TAB|VIS_NL, "\""); + free(s); + s = s2; + if (s) + r = rk_strpoolprintf(r, "\"%s\"", s); + } + } + if (!s) { + rk_strpoolfree(r); + free(indents); + return NULL; + } + free(s); + break; + } + case A1_OP_TAG: { + const void *el = DPOC(data, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + const void * const *pel = (const void * const *)el; + if (*pel == NULL) { + r = rk_strpoolprintf(r, "null"); + break; + } + el = *pel; + } + + r = _asn1_print(t->ptr, r, flags, indent + 1, el, saved); + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *el = DPOC(data, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + const unsigned char *element = el->val; + unsigned int i; + + r = rk_strpoolprintf(r, "%s[", indents ? indents : ""); + for (i = 0; r && i < el->len; i++) { + if (i) + r = rk_strpoolprintf(r, ",%s", indents ? indents : ""); + r = _asn1_print(t->ptr, r, flags, indent + 1, element, saved); + element += ellen; + } + if (r) + r = rk_strpoolprintf(r, "]"); + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + size_t belements = A1_HEADER_LEN(bmember); + int first = 1; + + bmember += belements; + r = rk_strpoolprintf(r, "%s[", indents ? indents : ""); + while (r && belements) { + if (r && _asn1_bmember_isset_bit(data, bmember->offset, size)) { + if (!first) + r = rk_strpoolprintf(r, ","); + first = 0; + r = rk_strpoolprintf(r, "%s\"%s\"", indents ? indents : "", + (const char *)bmember->ptr); + } + belements--; bmember--; + } + if (r) + r = rk_strpoolprintf(r, "]"); + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *element = DPOC(data, choice->offset); + unsigned int nchoices = ((uintptr_t)choice->ptr) >> 1; + + if (*element > A1_HEADER_LEN(choice)) { + r = rk_strpoolprintf(r, "null"); + } else if (*element == 0) { + /* XXX If choice->tt then we should print the u.ellipsis */ + r = rk_strpoolprintf(r, "null"); + } else { + choice += *element; + r = rk_strpoolprintf(r, "%s{\"_choice\":\"%s\",%s\"value\":", + indents ? indents : "", + (const char *)choice[nchoices].ptr, + indents ? indents : ""); + if (r) + r = _asn1_print(choice->ptr, r, flags, indent + 1, + DPOC(data, choice->offset), NULL); + if (r) + r = rk_strpoolprintf(r, "}"); + } + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } + free(indents); + if (nnames && r) + return rk_strpoolprintf(r, "}"); + return r; +} + +char * +_asn1_print_top(const struct asn1_template *t, + int flags, + const void *data) +{ + struct rk_strpool *r = _asn1_print(t, NULL, flags, 0, data, NULL); + + if (r == NULL) + return NULL; + return rk_strpoolcollect(r); +} + +/* See commentary in _asn1_decode_open_type() */ +static int +_asn1_copy_open_type(const struct asn1_template *t, /* object set template */ + const void *from, + void *to) +{ + const struct asn1_template *tactual_type; + const struct asn1_template *tos = t->ptr; + size_t i; + const void * const *dfromp; + const void * const *valfrom; + const unsigned int *lenfromp; + void **dtop; + void **valto; + unsigned int *lentop; + unsigned int len; + const int *efromp = DPO(from, t->offset); + int *etop = DPO(to, t->offset); + int ret = 0; + + /* XXX We assume sizeof(enum) == sizeof(int) */ + if (!*efromp || *efromp >= A1_HEADER_LEN(tos) + 1) { + if ((t->tt & A1_OS_OT_IS_ARRAY)) + memset(etop, 0, sizeof(int) + sizeof(unsigned int) + sizeof(void *)); + else + memset(etop, 0, sizeof(int) + sizeof(void *)); + return 0; /* Unknown choice -> not copied */ + } + tactual_type = &tos[3*(*efromp - 1) + 4]; + + if (!(t->tt & A1_OS_OT_IS_ARRAY)) { + dfromp = DPO(from, t->offset + sizeof(*efromp)); + while (sizeof(void *) != sizeof(*efromp) && + ((uintptr_t)dfromp) % sizeof(void *) != 0) + dfromp = (void *)(((char *)dfromp) + sizeof(*efromp)); + if (!*dfromp) + return 0; + + dtop = DPO(to, t->offset + sizeof(*etop)); + while (sizeof(void *) != sizeof(*etop) && + ((uintptr_t)dtop) % sizeof(void *) != 0) + dtop = (void *)(((char *)dtop) + sizeof(*etop)); + + if ((*dtop = calloc(1, tactual_type->offset)) == NULL) + ret = ENOMEM; + if (ret == 0) + ret = _asn1_copy(tactual_type->ptr, *dfromp, *dtop); + if (ret == 0) + *etop = *efromp; + return ret; + } + + lenfromp = DPO(from, t->offset + sizeof(*efromp)); + dfromp = DPO(from, t->offset + sizeof(*efromp) + sizeof(*lenfromp)); + valfrom = *dfromp; + lentop = DPO(to, t->offset + sizeof(*etop)); + dtop = DPO(to, t->offset + sizeof(*etop) + sizeof(*lentop)); + + *etop = *efromp; + + len = *lenfromp; + *lentop = 0; + *dtop = NULL; + if ((valto = calloc(len, sizeof(valto[0]))) == NULL) + ret = ENOMEM; + for (i = 0, len = *lenfromp; ret == 0 && i < len; i++) { + if (valfrom[i] == NULL) { + valto[i] = NULL; + continue; + } + if ((valto[i] = calloc(1, tactual_type->offset)) == NULL) + ret = ENOMEM; + else + ret = _asn1_copy(tactual_type->ptr, valfrom[i], valto[i]); + (*lentop)++; + } + + for (i = 0; ret && i < (*lentop); i++) { + if (valto[i]) { + _asn1_free(tactual_type->ptr, valto[i]); + free(valto[i]); + } + } + if (ret) { + free(valto); + *lentop = 0; + } else + *dtop = valto; + return ret; +} + +int +_asn1_copy(const struct asn1_template *t, const void *from, void *to) +{ + size_t elements = A1_HEADER_LEN(t); + int ret = 0; + int preserve = (t->tt & A1_HF_PRESERVE); + + t++; + + if (preserve) { + ret = der_copy_octet_string(from, to); + if (ret) + return ret; + } + + while (elements) { + switch (t->tt & A1_OP_MASK) { + case A1_OP_OPENTYPE_OBJSET: { + _asn1_copy_open_type(t, from, to); + break; + } + case A1_OP_NAME: break; + case A1_OP_DEFVAL: break; + case A1_OP_TYPE_DECORATE_EXTERN: + case A1_OP_TYPE_DECORATE: + case A1_OP_TYPE: + case A1_OP_TYPE_EXTERN: { + const void *fel = DPOC(from, t->offset); + void *tel = DPO(to, t->offset); + void **ptel = (void **)tel; + size_t size; + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || + (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { + size = _asn1_sizeofType(t->ptr); + } else { + const struct asn1_type_func *f = t->ptr; + size = f->size; + } + + if (t->tt & A1_FLAG_OPTIONAL) { + void **pfel = (void **)fel; + if (*pfel == NULL) + break; + fel = *pfel; + + tel = *ptel = calloc(1, size); + if (tel == NULL) + return ENOMEM; + } + + if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || + (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) { + ret = _asn1_copy(t->ptr, fel, tel); + } else if ((t->tt & A1_OP_MASK) == A1_OP_TYPE_EXTERN) { + const struct asn1_type_func *f = t->ptr; + ret = (f->copy)(fel, tel); + } else { + const struct asn1_type_func *f = t->ptr; + + /* A1_OP_TYPE_DECORATE_EXTERN */ + if (f && f->copy) + ret = (f->copy)(fel, tel); + else if (f) + memset(tel, 0, f->size); + } + + if (ret) { + if (t->tt & A1_FLAG_OPTIONAL) { + free(*ptel); + *ptel = NULL; + } + return ret; + } + break; + } + case A1_OP_PARSE: { + unsigned int type = A1_PARSE_TYPE(t->tt); + const void *fel = DPOC(from, t->offset); + void *tel = DPO(to, t->offset); + + if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { + ABORT_ON_ERROR(); + return ASN1_PARSE_ERROR; + } + ret = (asn1_template_prim[type].copy)(fel, tel); + if (ret) + return ret; + break; + } + case A1_OP_TAG: { + const void *oldfrom = from; + void *oldto = to; + void **tel = NULL; + + from = DPOC(from, t->offset); + to = DPO(to, t->offset); + + if (t->tt & A1_FLAG_OPTIONAL) { + void **fel = (void **)from; + tel = (void **)to; + if (*fel == NULL) { + from = oldfrom; + to = oldto; + break; + } + from = *fel; + + to = *tel = calloc(1, _asn1_sizeofType(t->ptr)); + if (to == NULL) + return ENOMEM; + } + + ret = _asn1_copy(t->ptr, from, to); + if (ret) { + if (tel) { + free(*tel); + *tel = NULL; + } + return ret; + } + + from = oldfrom; + to = oldto; + + break; + } + case A1_OP_SETOF: + case A1_OP_SEQOF: { + const struct template_of *fel = DPOC(from, t->offset); + struct template_of *tel = DPO(to, t->offset); + size_t ellen = _asn1_sizeofType(t->ptr); + unsigned int i; + + tel->val = calloc(fel->len, ellen); + if (tel->val == NULL && fel->len > 0) + return ENOMEM; + + tel->len = fel->len; + + for (i = 0; i < fel->len; i++) { + ret = _asn1_copy(t->ptr, + DPOC(fel->val, (i * ellen)), + DPO(tel->val, (i *ellen))); + if (ret) + return ret; + } + break; + } + case A1_OP_BMEMBER: { + const struct asn1_template *bmember = t->ptr; + size_t size = bmember->offset; + memcpy(to, from, size); + break; + } + case A1_OP_CHOICE: { + const struct asn1_template *choice = t->ptr; + const unsigned int *felement = DPOC(from, choice->offset); + unsigned int *telement = DPO(to, choice->offset); + + if (*felement > A1_HEADER_LEN(choice)) + return ASN1_PARSE_ERROR; + + *telement = *felement; + + if (*felement == 0) { + if (choice->tt) + ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt)); + /* + * Else we should really memset clear the rest of this choice, + * but we don't really know its size. + */ + } else { + choice += *felement; + ret = _asn1_copy(choice->ptr, + DPOC(from, choice->offset), + DPO(to, choice->offset)); + } + if (ret) + return ret; + break; + } + default: + ABORT_ON_ERROR(); + break; + } + t++; + elements--; + } + return 0; +} + +int +_asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size) +{ + int ret; + memset(data, 0, t->offset); + ret = _asn1_decode(t, flags, p, len, data, size); + if (ret) + _asn1_free_top(t, data); + + return ret; +} + +int +_asn1_copy_top(const struct asn1_template *t, const void *from, void *to) +{ + int ret; + memset(to, 0, t->offset); + ret = _asn1_copy(t, from, to); + if (ret) + _asn1_free_top(t, to); + + return ret; +} + +void +_asn1_free_top(const struct asn1_template *t, void *data) +{ + _asn1_free(t, data); + memset(data, 0, t->offset); +} diff --git a/third_party/heimdal/lib/asn1/test.asn1 b/third_party/heimdal/lib/asn1/test.asn1 new file mode 100644 index 0000000..08c7dcd --- /dev/null +++ b/third_party/heimdal/lib/asn1/test.asn1 @@ -0,0 +1,309 @@ +-- $Id$ -- + +TEST DEFINITIONS ::= + +BEGIN + +IMPORTS HEIM_ANY FROM heim; + +-- Check that we handle out of order definitions. +-- The compiler should emit the definition of TESTOutOfOrderBar before that of +-- TESTOutOfOrderFoo. +TESTOutOfOrderFoo ::= SEQUENCE { + bar TESTOutOfOrderBar +} + +TESTOutOfOrderBar ::= SEQUENCE { + aMember INTEGER +} + +-- Check that we can handle rpc.mountd style "lists". This is unnecessarily +-- inefficient in its encoding, and there's no point to using this over +-- SEQUENCE OF (arrays), but it's neat that we can do this now that we can do +-- out of order definitions. +-- +-- This could be useful if we ever extend asn1_compile to also handle XDR, +-- which we well might since XDR's syntax is a dual of a strict subset of +-- ASN.1, and since XDR the encoding is fairly straightforward. +-- +-- Note that the `next' member has to be OPTIONAL for this to work. +TESTCircular ::= SEQUENCE { + name UTF8String, + next TESTCircular OPTIONAL +} + +TESTDefault ::= SEQUENCE { + name UTF8String DEFAULT "Heimdal", + version [0] TESTuint32 DEFAULT 8, + maxint TESTuint64 DEFAULT 9223372036854775807, + works BOOLEAN DEFAULT TRUE +} + +TESTuint32 ::= INTEGER (0..4294967295) +TESTuint64 ::= INTEGER(0..9223372036854775807) +TESTint64 ::= INTEGER(-9223372036854775808..9223372036854775807) + +TESTLargeTag ::= SEQUENCE { + foo[127] INTEGER (-2147483648..2147483647), + bar[128] INTEGER (-2147483648..2147483647) +} + +TESTSeq ::= SEQUENCE { + tag0[0] INTEGER (-2147483648..2147483647), + tag1[1] TESTLargeTag, + tagless INTEGER (-2147483648..2147483647), + tag3[2] INTEGER (-2147483648..2147483647) +} + +TESTChoice1 ::= CHOICE { + i1[1] INTEGER (-2147483648..2147483647), + i2[2] INTEGER (-2147483648..2147483647), + ... +} + +TESTChoice2 ::= CHOICE { + i1[1] INTEGER (-2147483648..2147483647), + ... +} + +TESTInteger ::= INTEGER (-2147483648..2147483647) + +TESTInteger2 ::= [4] IMPLICIT TESTInteger +TESTInteger3 ::= [5] IMPLICIT TESTInteger2 + +TESTImplicit ::= SEQUENCE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[1] IMPLICIT SEQUENCE { + foo[127] INTEGER (-2147483648..2147483647) + }, + ti3[2] IMPLICIT [5] IMPLICIT [4] IMPLICIT INTEGER (-2147483648..2147483647) +} + +TESTImplicit2 ::= SEQUENCE { + ti1[0] IMPLICIT TESTInteger, +-- ti2[1] IMPLICIT TESTLargeTag, this is disabled since the IMPLICT encoder does't get the types right when stepping inside an structure -- + ti3[2] IMPLICIT TESTInteger3, + ti4[51] IMPLICIT TESTInteger OPTIONAL +} + +TESTImplicit3 ::= CHOICE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[5] IMPLICIT CHOICE { i1[1] INTEGER (-2147483648..2147483647) } +} + +TESTImplicit4 ::= CHOICE { + ti1[0] IMPLICIT INTEGER (-2147483648..2147483647), + ti2[5] IMPLICIT TESTChoice2 +} + +TESTAllocInner ::= SEQUENCE { + ai[0] TESTInteger +} + +TESTAlloc ::= SEQUENCE { + tagless TESTAllocInner OPTIONAL, + three [1] INTEGER (-2147483648..2147483647), + tagless2 HEIM_ANY OPTIONAL +} + +TESTOptional ::= SEQUENCE { + zero [0] INTEGER (-2147483648..2147483647) OPTIONAL, + one [1] INTEGER (-2147483648..2147483647) OPTIONAL +} + + +TESTCONTAINING ::= OCTET STRING ( CONTAINING INTEGER ) +TESTENCODEDBY ::= OCTET STRING ( ENCODED BY + { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } +) + +testDer OBJECT IDENTIFIER ::= { + joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) +} + +testContainingEncodedBy ::= OCTET STRING ( CONTAINING INTEGER ENCODED BY + { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } +) + +testContainingEncodedBy2 ::= OCTET STRING ( + CONTAINING INTEGER ENCODED BY testDer +) + + +testValue1 INTEGER ::= 1 + +testUserConstrained ::= OCTET STRING (CONSTRAINED BY { -- meh -- }) +-- TESTUSERCONSTRAINED2 ::= OCTET STRING (CONSTRAINED BY { TESTInteger }) +-- TESTUSERCONSTRAINED3 ::= OCTET STRING (CONSTRAINED BY { INTEGER }) +-- TESTUSERCONSTRAINED4 ::= OCTET STRING (CONSTRAINED BY { INTEGER : 1 }) + +TESTSeqOf ::= SEQUENCE OF TESTInteger + +TESTSeqSizeOf1 ::= SEQUENCE SIZE (2) OF TESTInteger +TESTSeqSizeOf2 ::= SEQUENCE SIZE (1..2) OF TESTInteger +TESTSeqSizeOf3 ::= SEQUENCE SIZE (1..MAX) OF TESTInteger +TESTSeqSizeOf4 ::= SEQUENCE SIZE (0..2) OF TESTInteger + +TESTOSSize1 ::= OCTET STRING SIZE (1..2) + +TESTSeqOfSeq ::= SEQUENCE OF SEQUENCE { + zero [0] TESTInteger +} + +TESTSeqOfSeq2 ::= SEQUENCE OF SEQUENCE { + string [0] GeneralString +} + +TESTSeqOfSeq3 ::= SEQUENCE OF SEQUENCE { + zero [0] TESTInteger, + string [0] GeneralString +} + +TESTSeqOf2 ::= SEQUENCE { + strings SEQUENCE OF GeneralString +} + +TESTSeqOf3 ::= SEQUENCE { + strings SEQUENCE OF GeneralString OPTIONAL +} + +-- Larger/more complex to increase odds of out-of-bounds +-- read/writes if miscoded + +TESTSeqOf4 ::= SEQUENCE { + b1 [0] SEQUENCE OF SEQUENCE { + s1 OCTET STRING, + s2 OCTET STRING, + u1 TESTuint64, + u2 TESTuint64 + } OPTIONAL, + b2 [1] IMPLICIT SEQUENCE OF SEQUENCE { + u1 TESTuint64, + u2 TESTuint64, + u3 TESTuint64, + s1 OCTET STRING, + s2 OCTET STRING, + s3 OCTET STRING + } OPTIONAL, + b3 [2] IMPLICIT SEQUENCE OF SEQUENCE { + s1 OCTET STRING, + u1 TESTuint64, + s2 OCTET STRING, + u2 TESTuint64, + s3 OCTET STRING, + u3 TESTuint64, + s4 OCTET STRING, + u4 TESTuint64 + } OPTIONAL +} + +TESTSeqOf5 ::= SEQUENCE { + outer SEQUENCE { + inner SEQUENCE { + u0 TESTuint64, + s0 OCTET STRING, + u1 TESTuint64, + s1 OCTET STRING, + u2 TESTuint64, + s2 OCTET STRING, + u3 TESTuint64, + s3 OCTET STRING, + u4 TESTuint64, + s4 OCTET STRING, + u5 TESTuint64, + s5 OCTET STRING, + u6 TESTuint64, + s6 OCTET STRING, + u7 TESTuint64, + s7 OCTET STRING + } + } + OPTIONAL +} + +TESTPreserve ::= SEQUENCE { + zero [0] TESTInteger, + one [1] TESTInteger +} + +TESTBitString ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31) +} + +TESTBitString64 ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31), + thirtytwo(32), + sixtythree(63) +} + +TESTLargeBitString ::= BIT STRING { + zero(0), + eight(8), + thirtyone(31), + onehundredtwenty(120) +} + +TESTMechType::= OBJECT IDENTIFIER +TESTMechTypeList ::= SEQUENCE OF TESTMechType + + +-- IOS stuff +_EXTENSION ::= CLASS { + &id OBJECT IDENTIFIER UNIQUE, + &ExtnType, + &Critical BOOLEAN DEFAULT FALSE +} + +TESTExtension{_EXTENSION:ExtensionSet} ::= SEQUENCE { + extnID _EXTENSION.&id({ExtensionSet}), + critical BOOLEAN +-- (EXTENSION.&Critical({ExtensionSet}{@extnID})) + DEFAULT FALSE, + extnValue OCTET STRING (CONTAINING + _EXTENSION.&ExtnType({ExtensionSet}{@extnID})) +} + +id-test-default OBJECT IDENTIFIER ::= { 1 2 3 4 } +testext-TESTDefault _EXTENSION ::= { + &id id-test-default, + &Critical FALSE, + &ExtnType TESTDefault +} + +-- And Here's an object set for the EXTENSION CLASS collecting a bunch of +-- related extensions (here they are the extensions that certificates can +-- carry in their extensions member): +TestExtensions _EXTENSION ::= { testext-TESTDefault } + +TESTExtension ::= TESTExtension { TestExtensions } + +TESTExtensible ::= SEQUENCE { + version INTEGER, + extensions SEQUENCE OF TESTExtension +} + +TESTDecorated ::= SEQUENCE { + version TESTuint32 + -- gets decorated with varius fields (see test.opt) +} + +TESTNotDecorated ::= SEQUENCE { + version TESTuint32 + -- should have the same encoding as TESTDecorated +} + +TESTDecoratedChoice ::= CHOICE { + version TESTuint32 + -- gets decorated with varius fields (see test.opt) +} + +TESTNotDecoratedChoice ::= CHOICE { + version TESTuint32 + -- should have the same encoding as TESTDecoratedChoice +} + +END diff --git a/third_party/heimdal/lib/asn1/test.gen b/third_party/heimdal/lib/asn1/test.gen new file mode 100644 index 0000000..bfb0486 --- /dev/null +++ b/third_party/heimdal/lib/asn1/test.gen @@ -0,0 +1,14 @@ +# $Id$ +# Sample for TESTSeq in test.asn1 +# + +UNIV CONS Sequence 23 + CONTEXT CONS 0 3 + UNIV PRIM Integer 1 01 + CONTEXT CONS 1 8 + UNIV CONS Sequence 6 + CONTEXT CONS 127 3 + UNIV PRIM Integer 1 01 + UNIV PRIM Integer 1 01 + CONTEXT CONS 2 3 + UNIV PRIM Integer 1 01 diff --git a/third_party/heimdal/lib/asn1/test.opt b/third_party/heimdal/lib/asn1/test.opt new file mode 100644 index 0000000..755eba0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/test.opt @@ -0,0 +1,7 @@ +--sequence=TESTSeqOf +--decorate=TESTDecorated:TESTuint32:version2? +--decorate=TESTDecorated:my_vers:version3:my_copy_vers:my_free_vers:"check-gen.h" +--decorate=TESTDecorated:void *:privthing +--decorate=TESTDecoratedChoice:TESTuint32:version2? +--decorate=TESTDecoratedChoice:my_vers:version3:my_copy_vers:my_free_vers:"check-gen.h" +--decorate=TESTDecoratedChoice:void *:privthing diff --git a/third_party/heimdal/lib/asn1/timegm.c b/third_party/heimdal/lib/asn1/timegm.c new file mode 100644 index 0000000..4746fa8 --- /dev/null +++ b/third_party/heimdal/lib/asn1/timegm.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "der_locl.h" + +#define ASN1_MAX_YEAR 2000 + +static int +is_leap(unsigned y) +{ + y += 1900; + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); +} + +static const unsigned ndays[2][12] ={ + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + +/* + * This is a simplifed version of timegm(3) that doesn't accept out of + * bound values that timegm(3) normally accepts but those are not + * valid in asn1 encodings. + */ + +time_t +_der_timegm (struct tm *tm) +{ + time_t res = 0; + int i; + + /* + * See comment in _der_gmtime + */ + if (tm->tm_year > ASN1_MAX_YEAR) + return 0; + + if (tm->tm_year < 0) + return -1; + if (tm->tm_mon < 0 || tm->tm_mon > 11) + return -1; + if (tm->tm_mday < 1 || tm->tm_mday > (int)ndays[is_leap(tm->tm_year)][tm->tm_mon]) + return -1; + if (tm->tm_hour < 0 || tm->tm_hour > 23) + return -1; + if (tm->tm_min < 0 || tm->tm_min > 59) + return -1; + if (tm->tm_sec < 0 || tm->tm_sec > 59) + return -1; + + for (i = 70; i < tm->tm_year; ++i) + res += is_leap(i) ? 366 : 365; + + for (i = 0; i < tm->tm_mon; ++i) + res += ndays[is_leap(tm->tm_year)][i]; + res += tm->tm_mday - 1; + res *= 24; + res += tm->tm_hour; + res *= 60; + res += tm->tm_min; + res *= 60; + res += tm->tm_sec; + return res; +} + +struct tm * +_der_gmtime(time_t t, struct tm *tm) +{ + time_t secday = t % (3600 * 24); + time_t days = t / (3600 * 24); + + memset(tm, 0, sizeof(*tm)); + + tm->tm_sec = secday % 60; + tm->tm_min = (secday % 3600) / 60; + tm->tm_hour = (int)(secday / 3600); + + /* + * Refuse to calculate time ~ 2000 years into the future, this is + * not possible for systems where time_t is a int32_t, however, + * when time_t is a int64_t, that can happen, and this becomes a + * denial of sevice. + */ + if (days > (ASN1_MAX_YEAR * 365)) + return NULL; + + tm->tm_year = 70; + while(1) { + unsigned dayinyear = (is_leap(tm->tm_year) ? 366 : 365); + if (days < dayinyear) + break; + tm->tm_year += 1; + days -= dayinyear; + } + tm->tm_mon = 0; + + while (1) { + unsigned daysinmonth = ndays[is_leap(tm->tm_year)][tm->tm_mon]; + if (days < daysinmonth) + break; + days -= daysinmonth; + tm->tm_mon++; + } + tm->tm_mday = (int)(days + 1); + + return tm; +} diff --git a/third_party/heimdal/lib/asn1/version-script.map b/third_party/heimdal/lib/asn1/version-script.map new file mode 100644 index 0000000..67f9ff0 --- /dev/null +++ b/third_party/heimdal/lib/asn1/version-script.map @@ -0,0 +1,6 @@ +# Export everything, but put a tag on is so that we make ourself incompatible with older versions + +HEIMDAL_ASN1_1.0 { + global: + *; +}; diff --git a/third_party/heimdal/lib/asn1/x690sample.asn1 b/third_party/heimdal/lib/asn1/x690sample.asn1 new file mode 100644 index 0000000..18954a4 --- /dev/null +++ b/third_party/heimdal/lib/asn1/x690sample.asn1 @@ -0,0 +1,181 @@ +x690sample DEFINITIONS ::= BEGIN + +-- This is taken from Appendix A of X.690. The same module is used by all +-- X.690 series specifications of ASN.1 Encoding Rules. +-- +-- This doesn't exercise every feature, like OPTIONAL, not really DEFAULT, not +-- EXPLICIT tagging, extensibility markers, etc., but it exercises some hard +-- ones like SET and IMPLICIT tagging. +-- +-- Because we don't yet have an option to add a namespace prefix to generated +-- symbols, to avoid conflicts with rfc2459's Name we're prefixing the type +-- names here manually. +-- +-- WARNING: The encoding rules used for the sample encoding given in Appendix A +-- of X.690, and used in lib/asn1/check-gen.c, is not specified in +-- X.690! It seems very likely that it is neither CER nor DER but BER +-- because the tags in the X690SamplePersonnelRecord (a SET { ... }) +-- are not in canonical order: +-- +-- APPL CONS tag 0 = 133 bytes [0] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "John" +-- UNIV PRIM VisibleString = "P" +-- UNIV PRIM VisibleString = "Smith" +-- -> CONTEXT CONS tag 0 = 10 bytes [0] +-- UNIV PRIM VisibleString = "Director" +-- -> APPL PRIM tag 2 = 1 bytes [2] IMPLICIT content +-- ... +-- +-- The canonical ordering of members in SET { ... } types is by tag, +-- with UNIVERSAL tags before APPLICATION tags, those before CONTEXT, +-- and those before PRIVATE, and within each class from lowest to +-- highest numeric tag value. See X.680, section 8.6, which is +-- referenced from X.690, section 10.3. +-- +-- Here we can see that the `title` member should come _after_ the +-- `number` member, but it does not. +-- +-- Our test relies on our compiler producing the same test data when +-- encoding the structure that the given test data decodes to. That +-- works here only because our compiler does NOT sort SET { ... } +-- members as it should (since we always produce DER). +-- +-- Sorting SET members in the compiler is hard currently because we +-- don't parse imported modules, so we don't know the tags of imported +-- types, so we can only sort at run-time, which we don't do. +-- +-- There is an obvious workaround, however: sort the SET { ... } +-- definition manually! + +X690SamplePersonnelRecord ::= [APPLICATION 0] IMPLICIT SET { + name X690SampleName, + title [0] VisibleString, + number X690SampleEmployeeNumber, + dateOfHire [1] X690SampleDate, + nameOfSpouse [2] X690SampleName, + -- Heimdal's ASN.1 compiler doesn't handle DEFAULT values for types for + -- which it doesn't support literal values. + children [3] IMPLICIT SEQUENCE OF X690SampleChildInformation -- DEFAULT {} +} + +X690SampleChildInformation ::= SET { + name X690SampleName, + dateOfBirth [0] X690SampleDate +} + +X690SampleName ::= [APPLICATION 1] IMPLICIT SEQUENCE { + givenName VisibleString, + initial VisibleString, + familyName VisibleString +} + +-- Range added for test convenience. +X690SampleEmployeeNumber ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295) + +X690SampleDate::= [APPLICATION 3] IMPLICIT VisibleString --YYYYMMDD + +-- The following is value syntax for the above, but Heimdal's ASN.1 compiler +-- does not yet support value syntax for anything other than OIDs, booleans, +-- integers, and UTF-8 strings: +-- +-- { name { givenName "John", initial "P", familyName "Smith" }, +-- title "Director", +-- number 51, +-- dateOfHire "19710917", +-- nameOfSpouse {givenName "Mary", initial "T", familyName "Smith" }, +-- children { +-- {name {givenName "Ralph", initial "T", familyName "Smith" }, +-- dateOfBirth "19571111"}, +-- {name {givenName "Susan", initial "B", familyName "Jones" }, +-- I dateOfBirth "19590717"} +-- } +-- } +-- +-- The encoding of this value is supposed to be (all hex) (adapted from X.690 +-- Appendix A): +-- +-- 60818561101A044A6F686E1A01501A05536D697468A00A1A084469726563746F +-- 72420133A10A43083139373130393137A21261101A044D6172791A01541A0553 +-- 6D697468A342311F61111A0552616C70681A01541A05536D697468A00A430831 +-- 39353731313131311F61111A05537573616E1A01421A05536D697468A00A4308 +-- 3139353930373137 +-- +-- And a rough visualization of this is (adapted from X.690 Appendix A): +-- +-- T L +-- 60 8185 # 3 +-- Name +-- T L +-- 61 10 # 2 +-- T L "John" +-- 1A 04 4A6F686E # 6 +-- T L "P" +-- 1A 01 50 # 3 +-- T L "Smith" +-- 1A 05 536D697468 # 7 +-- Title +-- T L T L "Director" +-- A0 0A 1A 08 4469726563746F72 #12 +-- Emp. # +-- 42 01 33 # 3 +-- Date of hire +-- A1 0A 43 08 3139373130393137 #12 +-- Spouse +-- A2 12 # 2 +-- Name +-- 61 10 # 2 +-- 1A 04 4D617279 # 6 +-- 1A 01 54 # 3 +-- 1A 05 536D697468 # 7 +-- Children +-- A3 42 # 2 +-- 31 1F # 2 +-- Name +-- 61 11 1A 05 52616C7068 # 9 +-- 1A 01 54 # 3 +-- 1A 05 536D697468 # 7 +-- DoB +-- A0 0A 43 08 3139353731313131 #12 +-- 31 1F # 2 bytes +-- 61 11 1A 05 537573616E # 9 bytes +-- 1A 01 42 # 3 bytes +-- 1A 05 536D697468 # 7 bytes +-- A0 0A 43 08 3139353930373137 #12 bytes +-- +-- Our asn1_print program dumps this as follows, which looks correct: +-- +-- APPL CONS tag 0 = 133 bytes [0] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "John" +-- UNIV PRIM VisibleString = "P" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- UNIV PRIM VisibleString = "Director" +-- APPL PRIM tag 2 = 1 bytes [2] IMPLICIT content +-- CONTEXT CONS tag 1 = 10 bytes [1] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- CONTEXT CONS tag 2 = 18 bytes [2] +-- APPL CONS tag 1 = 16 bytes [1] +-- UNIV PRIM VisibleString = "Mary" +-- UNIV PRIM VisibleString = "T" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 3 = 66 bytes [3] +-- UNIV CONS Set = 31 bytes { +-- APPL CONS tag 1 = 17 bytes [1] +-- UNIV PRIM VisibleString = "Ralph" +-- UNIV PRIM VisibleString = "T" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- } +-- UNIV CONS Set = 31 bytes { +-- APPL CONS tag 1 = 17 bytes [1] +-- UNIV PRIM VisibleString = "Susan" +-- UNIV PRIM VisibleString = "B" +-- UNIV PRIM VisibleString = "Smith" +-- CONTEXT CONS tag 0 = 10 bytes [0] +-- APPL PRIM tag 3 = 8 bytes [3] IMPLICIT content +-- } + +END |