diff --git a/configure.ac b/configure.ac index 3346b74cb..7ba178d36 100644 --- a/configure.ac +++ b/configure.ac @@ -139,9 +139,9 @@ fi AM_CONDITIONAL(OPENLDAP_MODULE, test "$enable_hdb_openldap_module" = yes -a "$with_openldap" = yes) AC_ARG_ENABLE(asn1-templating, - AS_HELP_STRING([--enable-asn1-templating], + AS_HELP_STRING([--disable-asn1-templating], [if you want disable to use of the ASN.1 templating compiler])) -AM_CONDITIONAL(ASN1_TEMPLATING, test "x$enable_asn1_templating" = xyes) +AM_CONDITIONAL(ASN1_TEMPLATING, test "x$enable_asn1_templating" != xno) dnl dnl Optional modules, pk-init, digest, kx509 diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index aa6f5aeaa..9decc9dd2 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2255,7 +2255,7 @@ _kdc_as_rep(astgs_request_t r) copy_HostAddresses(b->addresses, r->et.caddr); } - r->et.transited.tr_type = DOMAIN_X500_COMPRESS; + r->et.transited.tr_type = domain_X500_Compress; krb5_data_zero(&r->et.transited.contents); /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index a84118c17..bc4f3eaa2 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -658,7 +658,7 @@ fix_transited_encoding(krb5_context context, size_t i; switch (tr->tr_type) { - case DOMAIN_X500_COMPRESS: + case domain_X500_Compress: break; case 0: /* @@ -744,7 +744,7 @@ fix_transited_encoding(krb5_context context, } et->flags.transited_policy_checked = 1; } - et->transited.tr_type = DOMAIN_X500_COMPRESS; + et->transited.tr_type = domain_X500_Compress; ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents); if(ret) krb5_warn(context, ret, "Encoding transited encoding"); diff --git a/kuser/kimpersonate.c b/kuser/kimpersonate.c index b1cefea0f..9ff4e4707 100644 --- a/kuser/kimpersonate.c +++ b/kuser/kimpersonate.c @@ -89,7 +89,7 @@ encode_ticket(krb5_context context, krb5_data empty_string; krb5_data_zero(&empty_string); - et.transited.tr_type = DOMAIN_X500_COMPRESS; + et.transited.tr_type = domain_X500_Compress; et.transited.contents = empty_string; } et.authtime = cred->times.authtime; diff --git a/lib/asn1/Makefile.am b/lib/asn1/Makefile.am index 5f8dc9754..d2146fe3e 100644 --- a/lib/asn1/Makefile.am +++ b/lib/asn1/Makefile.am @@ -6,6 +6,8 @@ YFLAGS = -d -t AM_CPPFLAGS += $(ROKEN_RENAME) +man_MANS = asn1_compile.1 + lib_LTLIBRARIES = libasn1.la libasn1_la_LDFLAGS = -version-info 8:0:0 @@ -23,9 +25,7 @@ libasn1_la_LIBADD = \ BUILT_SOURCES = \ $(gen_files_rfc2459:.x=.c) \ - $(gen_files_rfc4043:.x=.c) \ $(gen_files_rfc4108:.x=.c) \ - $(gen_files_tcg:.x=.c) \ $(gen_files_cms:.x=.c) \ $(gen_files_krb5:.x=.c) \ $(gen_files_ocsp:.x=.c) \ @@ -42,9 +42,7 @@ gen_files_krb5 = asn1_krb5_asn1.x gen_files_cms = asn1_cms_asn1.x gen_files_crmf = asn1_crmf_asn1.x gen_files_rfc2459 = asn1_rfc2459_asn1.x -gen_files_rfc4043 = asn1_rfc4043_asn1.x gen_files_rfc4108 = asn1_rfc4108_asn1.x -gen_files_tcg = asn1_tcg_asn1.x gen_files_ocsp = asn1_ocsp_asn1.x gen_files_pkinit = asn1_pkinit_asn1.x gen_files_pkcs10 = asn1_pkcs10_asn1.x @@ -73,6 +71,7 @@ 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:.x=.c) +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:.x=.c) @@ -154,9 +153,7 @@ check_ber_LDADD = $(check_gen_LDADD) CLEANFILES = \ $(BUILT_SOURCES) \ $(gen_files_rfc2459) \ - $(gen_files_rfc4043) \ $(gen_files_rfc4108) \ - $(gen_files_tcg) \ $(gen_files_cms) \ $(gen_files_krb5) \ $(gen_files_ocsp) \ @@ -174,9 +171,7 @@ CLEANFILES = \ asn1parse.c asn1parse.h lex.c \ asn1_err.c asn1_err.h \ rfc2459_asn1_files rfc2459_asn1*.h* rfc2459_asn1*.x \ - rfc4043_asn1_files rfc4043_asn1*.h* rfc4043_asn1*.x \ rfc4108_asn1_files rfc4108_asn1*.h* rfc4108_asn1*.x \ - tcg_asn1_files tcg_asn1*.h* tcg_asn1*.x \ cms_asn1_files cms_asn1*.h* cms_asn1*.x \ crmf_asn1_files crmf_asn1*.h* crmf_asn1*.x \ krb5_asn1_files krb5_asn1*.h* krb5_asn1*.x \ @@ -203,9 +198,7 @@ nodist_include_HEADERS += pkinit_asn1.h nodist_include_HEADERS += cms_asn1.h nodist_include_HEADERS += crmf_asn1.h nodist_include_HEADERS += rfc2459_asn1.h -nodist_include_HEADERS += rfc4043_asn1.h nodist_include_HEADERS += rfc4108_asn1.h -nodist_include_HEADERS += tcg_asn1.h nodist_include_HEADERS += ocsp_asn1.h nodist_include_HEADERS += pkcs8_asn1.h nodist_include_HEADERS += pkcs9_asn1.h @@ -220,9 +213,7 @@ priv_headers += pkinit_asn1-priv.h priv_headers += cms_asn1-priv.h priv_headers += crmf_asn1-priv.h priv_headers += rfc2459_asn1-priv.h -priv_headers += rfc4043_asn1-priv.h priv_headers += rfc4108_asn1-priv.h -priv_headers += tcg_asn1-priv.h priv_headers += ocsp_asn1-priv.h priv_headers += pkcs8_asn1-priv.h priv_headers += pkcs9_asn1-priv.h @@ -255,9 +246,7 @@ $(gen_files_pkcs12) pkcs12_asn1.hx pkcs12_asn1-priv.hx: pkcs12_asn1_files $(gen_files_digest) digest_asn1.hx digest_asn1-priv.hx: digest_asn1_files $(gen_files_kx509) kx509_asn1.hx kx509_asn1-priv.hx: kx509_asn1_files $(gen_files_rfc2459) rfc2459_asn1.hx rfc2459_asn1-priv.hx: rfc2459_asn1_files -$(gen_files_rfc4043) rfc4043_asn1.hx rfc4043_asn1-priv.hx: rfc4043_asn1_files $(gen_files_rfc4108) rfc4108_asn1.hx rfc4108_asn1-priv.hx: rfc4108_asn1_files -$(gen_files_tcg) tcg_asn1.hx tcg_asn1-priv.hx: tcg_asn1_files $(gen_files_cms) cms_asn1.hx cms_asn1-priv.hx: cms_asn1_files $(gen_files_crmf) crmf_asn1.hx crmf_asn1-priv.hx: crmf_asn1_files $(gen_files_x690sample) x690sample_asn1.hx x690sample_asn1-priv.hx: x690sample_asn1_files @@ -270,19 +259,12 @@ else TEMPLATE_OPTION= endif -# XXX Currently using the template compiler for rfc2459.asn1 breaks 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) -rfc4043_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/rfc4043.asn1 - $(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) $(srcdir)/rfc4043.asn1 rfc4043_asn1 || (rm -f rfc4043_asn1_files ; exit 1) - 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) -tcg_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/tcg.asn1 - $(ASN1_COMPILE) --prefix-enum --one-code-file $(TEMPLATE_OPTION) $(srcdir)/tcg.asn1 tcg_asn1 || (rm -f tcg_asn1_files ; exit 1) - 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) @@ -348,7 +330,6 @@ EXTRA_DIST = \ pkcs10.asn1 \ pkinit.asn1 \ rfc2459.asn1 \ - rfc4043.asn1 \ rfc4108.asn1 \ tcg.asn1 \ setchgpw2.asn1 \ diff --git a/lib/asn1/NTMakefile b/lib/asn1/NTMakefile index bdf383c4d..d738db12a 100644 --- a/lib/asn1/NTMakefile +++ b/lib/asn1/NTMakefile @@ -31,7 +31,7 @@ RELDIR=lib\asn1 -intcflags=-I$(SRCDIR) -I$(OBJ) -DROKEN_RENAME +intcflags=-I$(SRCDIR) -I$(OBJ) -DROKEN_RENAME -DASN1_IOS_SUPPORTED !include ../../windows/NTMakefile.w32 @@ -43,12 +43,8 @@ gen_files_crmf = $(OBJ)\asn1_crmf_asn1.x gen_files_rfc2459 = $(OBJ)\asn1_rfc2459_asn1.x -gen_files_rfc4043 = $(OBJ)\asn1_rfc4043_asn1.x - gen_files_rfc4108 = $(OBJ)\asn1_rfc4108_asn1.x -gen_files_tcg = $(OBJ)\asn1_tcg_asn1.x - gen_files_ocsp = $(OBJ)\asn1_ocsp_asn1.x gen_files_pkinit = $(OBJ)\asn1_pkinit_asn1.x @@ -128,11 +124,8 @@ LIBASN1_OBJS= \ $(OBJ)\extra.obj \ $(OBJ)\timegm.obj \ $(gen_files_rfc2459:.x=.obj) \ - $(gen_files_rfc4043:.x=.obj) \ $(gen_files_rfc4108:.x=.obj) \ - $(gen_files_tcg:.x=.obj) \ $(gen_files_cms:.x=.obj) \ - $(gen_files_crmf:.x=.obj) \ $(gen_files_krb5:.x=.obj) \ $(gen_files_ocsp:.x=.obj) \ $(gen_files_pkinit:.x=.obj) \ @@ -190,12 +183,8 @@ $(gen_files_kx509:.x=.c) : $$(@R).x $(gen_files_rfc2459:.x=.c) : $$(@R).x -$(gen_files_rfc4043:.x=.c) : $$(@R).x - $(gen_files_rfc4108:.x=.c) : $$(@R).x -$(gen_files_tcg:.x=.c) : $$(@R).x - $(gen_files_cms:.x=.c) : $$(@R).x $(gen_files_crmf:.x=.c) : $$(@R).x @@ -209,6 +198,7 @@ $(gen_files_test_template:.x=.c) : $$(@R).x $(gen_files_krb5) $(OBJ)\krb5_asn1.hx: $(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 \ @@ -218,6 +208,7 @@ $(gen_files_krb5) $(OBJ)\krb5_asn1.hx: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5 $(gen_files_ocsp) $(OBJ)\ocsp_asn1.hx: $(BINDIR)\asn1_compile.exe ocsp.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ + --template \ --one-code-file \ --option-file=$(SRCDIR)\ocsp.opt \ $(SRCDIR)\ocsp.asn1 \ @@ -227,25 +218,26 @@ $(gen_files_ocsp) $(OBJ)\ocsp_asn1.hx: $(BINDIR)\asn1_compile.exe ocsp.asn1 $(gen_files_pkinit) $(OBJ)\pkinit_asn1.hx: $(BINDIR)\asn1_compile.exe pkinit.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\pkinit.asn1 pkinit_asn1 \ + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkinit.asn1 pkinit_asn1 \ || ($(RM) $(OBJ)\pkinit_asn1.h ; exit /b 1) cd $(SRCDIR) $(gen_files_pkcs8) $(OBJ)\pkcs8_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs8.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\pkcs8.asn1 pkcs8_asn1 \ + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs8.asn1 pkcs8_asn1 \ || ($(RM) $(OBJ)\pkcs8_asn1.h ; exit /b 1) cd $(SRCDIR) $(gen_files_pkcs9) $(OBJ)\pkcs9_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs9.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\pkcs9.asn1 pkcs9_asn1 \ + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs9.asn1 pkcs9_asn1 \ || ($(RM) $(OBJ)\pkcs9_asn1.h ; exit /b 1) cd $(SRCDIR) $(gen_files_pkcs10) $(OBJ)\pkcs10_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs10.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ + --template \ --one-code-file \ --option-file=$(SRCDIR)\pkcs10.opt \ $(SRCDIR)\pkcs10.asn1 \ @@ -255,58 +247,45 @@ $(gen_files_pkcs10) $(OBJ)\pkcs10_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs10.asn $(gen_files_pkcs12) $(OBJ)\pkcs12_asn1.hx: $(BINDIR)\asn1_compile.exe pkcs12.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\pkcs12.asn1 pkcs12_asn1 \ + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\pkcs12.asn1 pkcs12_asn1 \ || ($(RM) $(OBJ)\pkcs12_asn1.h ; exit /b 1) cd $(SRCDIR) $(gen_files_digest) $(OBJ)\digest_asn1.hx: $(BINDIR)\asn1_compile.exe digest.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\digest.asn1 digest_asn1 \ + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\digest.asn1 digest_asn1 \ || ($(RM) $(OBJ)\digest_asn1.h ; exit /b 1) cd $(SRCDIR) $(gen_files_kx509) $(OBJ)\kx509_asn1.hx: $(BINDIR)\asn1_compile.exe kx509.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\kx509.asn1 kx509_asn1 \ + $(BINDIR)\asn1_compile.exe --template --one-code-file $(SRCDIR)\kx509.asn1 kx509_asn1 \ || ($(RM) $(OBJ)\kx509_asn1.h ; exit /b 1) cd $(SRCDIR) $(gen_files_rfc2459) $(OBJ)\rfc2459_asn1.hx: $(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) -$(gen_files_rfc4043) $(OBJ)\rfc4043_asn1.hx: $(BINDIR)\asn1_compile.exe rfc4043.asn1 - cd $(OBJ) - $(BINDIR)\asn1_compile.exe \ - --one-code-file \ - $(SRCDIR)\rfc4043.asn1 rfc4043_asn1 \ - || ($(RM) $(OBJ)\rfc4043_asn1.h ; exit /b 1) - cd $(SRCDIR) - $(gen_files_rfc4108) $(OBJ)\rfc4108_asn1.hx: $(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) -$(gen_files_tcg) $(OBJ)\tcg_asn1.hx: $(BINDIR)\asn1_compile.exe tcg.asn1 - cd $(OBJ) - $(BINDIR)\asn1_compile.exe \ - --one-code-file \ - $(SRCDIR)\tcg.asn1 tcg_asn1 \ - || ($(RM) $(OBJ)\tcg_asn1.h ; exit /b 1) - cd $(SRCDIR) - $(gen_files_cms) $(OBJ)\cms_asn1.hx: $(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) @@ -315,6 +294,7 @@ $(gen_files_cms) $(OBJ)\cms_asn1.hx: $(BINDIR)\asn1_compile.exe cms.asn1 cms.opt $(gen_files_crmf) $(OBJ)\crmf_asn1.hx: $(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) @@ -323,6 +303,7 @@ $(gen_files_crmf) $(OBJ)\crmf_asn1.hx: $(BINDIR)\asn1_compile.exe crmf.asn1 crmf $(gen_files_x690sample) $(OBJ)\x690sample_asn1.hx: $(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) @@ -331,6 +312,7 @@ $(gen_files_x690sample) $(OBJ)\x690sample_asn1.hx: $(BINDIR)\asn1_compile.exe x6 $(gen_files_test) $(OBJ)\test_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ + --template \ --one-code-file --sequence=TESTSeqOf \ $(SRCDIR)\test.asn1 test_asn1 \ || ($(RM) $(OBJ)\test_asn1.h ; exit /b 1) @@ -339,6 +321,7 @@ $(gen_files_test) $(OBJ)\test_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1 $(gen_files_test_template) $(OBJ)\test_template_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1 cd $(OBJ) $(BINDIR)\asn1_compile.exe \ + --template \ --one-code-file --template \ --sequence=TESTSeqOf \ $(SRCDIR)\test.asn1 test_template_asn1 \ @@ -370,9 +353,7 @@ GENINCFILES= \ $(INCDIR)\pkcs10_asn1.h \ $(INCDIR)\pkinit_asn1.h \ $(INCDIR)\rfc2459_asn1.h \ - $(INCDIR)\rfc4043_asn1.h \ $(INCDIR)\rfc4108_asn1.h \ - $(INCDIR)\tcg_asn1.h \ $(INCDIR)\x690sample_asn1.h \ $(OBJ)\krb5_asn1-priv.h \ $(OBJ)\ocsp_asn1-priv.h \ @@ -380,9 +361,7 @@ GENINCFILES= \ $(OBJ)\cms_asn1-priv.h \ $(OBJ)\crmf_asn1-priv.h \ $(OBJ)\rfc2459_asn1-priv.h \ - $(OBJ)\rfc4043_asn1-priv.h \ $(OBJ)\rfc4108_asn1-priv.h \ - $(OBJ)\tcg_asn1-priv.h \ $(OBJ)\x690sample_asn1-priv.h \ $(OBJ)\pkcs8_asn1-priv.h \ $(OBJ)\pkcs9_asn1-priv.h \ @@ -437,7 +416,6 @@ clean:: TEST_BINARIES=\ $(OBJ)\check-der.exe \ - $(OBJ)\check-gen.exe \ $(OBJ)\check-gen-template.exe \ $(OBJ)\check-timegm.exe \ $(OBJ)\check-ber.exe \ @@ -448,7 +426,6 @@ test-binaries: $(TEST_BINARIES) test-run: cd $(OBJ) -check-der.exe - -check-gen.exe -check-gen-template.exe -check-timegm.exe -check-ber.exe @@ -470,11 +447,6 @@ $(OBJ)\check-der.exe: $(OBJ)\check-der.obj $(OBJ)\check-common.obj \ $(EXECONLINK) $(EXEPREP_NODIST) -$(OBJ)\check-gen.exe: $(OBJ)\check-gen.obj $(OBJ)\check-common.obj \ - $(LIBHEIMDAL) $(LIBROKEN) $(gen_files_test:.x=.obj) - $(EXECONLINK) - $(EXEPREP_NODIST) - $(OBJ)\check-gen-template.exe: $(OBJ)\check-gen.obj $(OBJ)\check-common.obj \ $(LIBHEIMDAL) $(LIBROKEN) $(gen_files_test_template:.x=.obj) $(EXECONLINK) diff --git a/lib/asn1/README-X681.md b/lib/asn1/README-X681.md index 4c306b448..e045f0f59 100644 --- a/lib/asn1/README-X681.md +++ b/lib/asn1/README-X681.md @@ -1,4 +1,4 @@ -# Bringing the Magical Power of X.681 (ASN.1 Information Object System) to Heimdal +# Automatic Open Type Handling via X.68x Support in Heimdal's ASN.1 Compiler ## Table of Contents @@ -6,45 +6,62 @@ 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. [Implementation Thoughts](#implementation-thoughts) - 5. [Moving From C](#moving-from-c) + 4. [Usage](#Usage) + 5. [Limitations](#Limitations) + 6. [Implementation Design](#implementation-design) + 7. [Moving From C](#moving-from-c) ## Introduction -The base of ASN.1 is specified by X.680, an ITU-T standard. +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. -Various extensions are specified in other X.680 series documents: +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 -While X.680 is essential for implementing many Internet (and other) protocols, -and sufficient for implementing all of those, implementing a subset of X.681, -X.682, and X.683, can enable some magical features. These magical features are -generally not the focus of those ITU-T specifications nor of many RFCs that -make use of them. - 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. -This README will cover some ideas for what this magic will be, and -implementation of it. +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 improces that further. +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 future support for the ASN.1 JSON Encoding Rules (JER) [X.697], -the automatic handling of open types should allow us to trivially implement a -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. +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. Combined with transcoders for JSON/CBOR and other binary-JSON formats, we could support those encodings too. @@ -113,12 +130,16 @@ has typed holes, see SSHv2. In ASN.1 these generally look like: ```ASN.1 - TypedHole ::= SEQUENCE { typeId INTEGER, hole OCTET STRING } + TypedHole ::= SEQUENCE { + typeId INTEGER, + opaque OCTET STRING + } ``` or ```ASN.1 + -- Old ASN.1 style TypedHole ::= SEQUENCE { typeId OBJECT IDENTIFIER, opaque ANY DEFINED BY typeID @@ -128,6 +149,7 @@ or or ```ASN.1 + -- Old ASN.1 style TypedHole ::= SEQUENCE { typeId OBJECT IDENTIFIER, opaque ANY -- DEFINED BY typeID @@ -208,9 +230,9 @@ Compare this to the handling of discriminated unions (what ASN.1 calls a 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 -conceivably be encoded in radically different encoding rules than the structure -containing it in a typed hole. +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 @@ -328,7 +350,8 @@ RFC5912 has lots of examples, such as this `CLASS` corresponding to the SEQUENCE SIZE (1..MAX) OF Extension{{ExtensionSet}} ``` -and these uses of it in RFC5280 (PKIX base): +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 @@ -361,7 +384,7 @@ and these uses of it in RFC5280 (PKIX base): -- 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*! + -- This is where the rubber meets the road: Certificate ::= SIGNED{TBSCertificate} @@ -391,74 +414,96 @@ and these uses of it in RFC5280 (PKIX base): ``` Notice that the `extensions` field of `TBSCertificate` is of type `Extensions` -parametrized by the `CertExtensions` information object set. +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 == id-ce-authorityKeyIdentifier` must have an -`extnValue` of type `AuthorityKeyIdentifier`. +an `Extension` with `extnID` value of `id-ce-authorityKeyIdentifier` must have +an `extnValue` of type `AuthorityKeyIdentifier`. ### IOS Crash Course -The ASN.1 IOS is... a bit difficult to understand. X.681 has a lot of strange -terminology, like "variable type value set field". An IOS "class" has fields, -and those fields are of kind `[Fixed]Type[Value[Set]]` or `Object[Set]`. +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". -Classes can have "object sets" associated with them, and each object set has -zero, one, or more "objects". Each object has settings for all required fields -of a class, and possibly also for optional/defaulted fields as well. +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. -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 tables with one predefined column naming object sets, rows -being objects grouped into oject sets by that column. IOS supports complex -path expressions across these objects (but we won't need that yet). +_Classes_ have fields of various kinds. More on this below. -These relational entities are constant in that they are defined in ASN.1 -modules that are compiled. There is no way to change them at run-time, only -query them. They also have no on-the-wire representation. +_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. 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 constant relational data. +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. We want to use classes and object sets to constrain `SET` or -`SEQUENCE` types (well, really, just `SEQUENCE`) so that our ASN.1 compiler can -have the metadata it needs in ordr to auto-generate decoding and encoding of -values of open types. +using the IOS [X.681], constraint specification [X.682], and type +parameterization [X.683]. We can express the following things: -A termnology point: `SET` and `SEQUENCE` types have "members", but classes and -objects have "fields". + - that some _member_ of a `SET` or `SEQUENCE` is of open type -Objects of a class have all the required fields of a class and any of the -`OPTIONAL` or `DEFAULT` fields of the class. This is very similar to -`SET`/`SEQUENCE` members, which can be `OPTIONAL` or `DEFAULT`ed. + - 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` -The "members" (we call them fields in C, instance variables in C++, Java, ...) + - 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 can have 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 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's -essential that we explain them by reference to how they relate to the members -of `SEQUENCE` types constrained by object sets: +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 (open) type. + - 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 + 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", as is seen in high-level languages - like Haskell. + 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. + 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 @@ -470,17 +515,18 @@ of `SEQUENCE` types constrained by object sets: - An `object field` will be a field that names another class (possibly the same class), which can be used to provide rich hierarchical type semantics - that... we don't need for PKIX. + 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; - - object and object set fields are also known as `link fields`. + - 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. @@ -501,18 +547,22 @@ Here's a simple example from PKIX: } ``` - - The `&id` field is a fixed-type value field. It's not a fixed-type value - _set_ field because its identifier (`id`) starts with a lower-case letter. + - The `&id` field 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. - The `UNIQUE` keyword tells us there can be only one object with any given - value of this field in any object set of this class. + 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. + 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. @@ -522,8 +572,7 @@ Here's a simple example from PKIX: 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 butimplementor-hostile syntax for specifying objects for this - class. + 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 @@ -571,7 +620,7 @@ 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. + - 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 @@ -679,35 +728,88 @@ 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 -## Implementation Thoughts +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 + + - Currently no effort is made to check the uniqueness of `UNIQUE` fields of + objects in object sets. + + - Currently no effort is made to check that required fields are specified in + objects. + + - `AtNotation` 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: Much of this is already implemented in the `x68x` branch of +https://github.com/nicowilliams/heimdal. - The required specifications, X.681, X.682, and X.683, are fairly large and - non-trivial. Perhaps 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. + 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 should want are: - - `ATTRIBUTE` (used for `DN` attributes in RFC5280) - - `EXTENSION` (used for certificate extensions in RFC5280) + - `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` + 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 create our own, and will. We want magic open type decoding to recurse + can and will create 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 -- maintaining and developing two compiler - backends is difficult enough, but the template compiler is superior just on - account of emitted code size scaling as `O(N)` instead of `O(M * N)` where - `M` is the number of encoding rules supported and `N` is the number of types - in an ASN.1 module (or all modules). + abandoning the original compiler. The codegen backend should generate 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 @@ -715,64 +817,297 @@ now. encoding/decoding can still work and we can then update Heimdal in-tree slowly to take advantage of the new magic. - Thus `Extension` should compile to something like: + Below are the C types for the ASN.1 PKIX types we care about, as generated + by the current prototype. + + `Extension` should and does compile to something like: ```C - typedef struct Extension { - -- Existing fields: - heim_oid extnID; - int *critical; - heim_octet_string extnValue; - -- New, CHOICE-like fields: - enum Extension_iosnum { - Extension_iosnumunknown = 0, /* when the extnID is unrecognized */ - Extension_iosnum_ext_AuthorityKeyIdentifier = 1, - Extension_iosnum_ext_ext-SubjectKeyIdentifier = 2, - ... - } _ios_element; - union { - heim_octet_string *_value; - authorityKeyIdentifier AuthorityKeyIdentifier; - subjectKeyIdentifier SubjectKeyIdentifier; - ... - } _ios_u; - } Extension; +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 { + 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 should and do 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 { + 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 { + 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 should and does compile 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 { + 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 == Extension_iosnumunknown`, then the encoder - should use the `extnID` and `extnValue` fields, otherwise it should use the - `_ioselement` and `_iosu` fields and ignore the `extnID` and `extnValue` - fields. + extensions with `_ioselement == choice_Extension_iosnumunknown` (or + whatever, for each open type), then the encoder should use the `extnID` and + `extnValue` fields, otherwise it should 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 should get used as-is. The rule should 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 must get mapped to discrete enum values. We'll want type IDs - to be sorted, too, so that we can binary search the object set's template - when decoding for extra speed. For encoding we'll want to "switch" on the - mapped type ID enum, directly indexing the template for the object set. + - Type ID values get mapped to discrete enum values. Object sets get sorted + by object type IDs, allowing for a binary search when decoding. For + encoding and other case we directly index the object set by the mapped type + ID enum. - - The ASN.1 parser merely builds an AST. That will not change. + - The C header generator remains shared between the two backends. - - The C header generator will remain shared between the two backends. + - SET and SEQUENCE types containing an open type are represented as follows in + their templates. - - Only the template backend will support the ASN.1 IOS. We'll basically - encode a new template for the combination of object set and typed hole - container type. This will come with a header entry indicating how many - items are in the object set, and each item will be one entry pointing to the - template for one particular object in the object set. The template for each - object will identify the type ID and the template for the associated type. +```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 } + }; - Perhaps we'll inline the objects for locality of reference. + /* 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 if the objects are sorted by type ID value. ## Moving From C - - Generate a JSON representation of each ASN.1 module + - Generate and output a JSON representation of the compiled ASN.1 module. - - Code codegen/templategen backends in jq or Haskell or whatever + - Code codegen/templategen backends in jq or Haskell or whatever. - - Code template interpreters in <host> language + - Code template interpreters in <host> language. + + - Eventually rewrite the compiler itself in Rust or whatever. diff --git a/lib/asn1/README-template.md b/lib/asn1/README-template.md new file mode 100644 index 000000000..4f43bb472 --- /dev/null +++ b/lib/asn1/README-template.md @@ -0,0 +1,192 @@ + +#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). + +TODO: + + - Fuzzing tests + + - 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/lib/asn1/README.md b/lib/asn1/README.md new file mode 100644 index 000000000..3a4a31275 --- /dev/null +++ b/lib/asn1/README.md @@ -0,0 +1,322 @@ +# 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. [Implementation](#implementation) + 8. [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) ([RFC2641](https://tools.ietf.org/html/rfc2641)) + + - 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. + +## Features + + - Most of X.680 is supported. + + - Most of X.690 is supported for decoding, with only DER supported for + encoding. + + - Unconstrained integer types have a large integer representation in C that is + not terribly useful in common cases. Range constraints on integer types + cause the compiler to use `int32_t`, `int64_t`, `uint32_t`, and/or + `uint64_t`. + + - 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.) + +... + +## Limitations + + - 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. + + - `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. Structured value syntax is not + supported. + + - ... + +## Compiler Usage + +See the manual page `asn1_compile.1`: + +``` +ASN1_COMPILE(1) HEIMDAL 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-NAME] + [--sequence=TYPE-NAME] [--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. + + 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 func‐ + tions directly, with no template interpretation. The template + backend scales better than the codegen backend because as we add + support for more encoding rules 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. More importantly, currently + only the template backend supports automatic decoding of open + types via X.681/X.682/X.683 annotations. + + --prefix-enum + This option should be removed because ENUMERATED types should + always have their labels prefixed. + + --enum-prefix=PREFIX + This option should be removed because ENUMERATED types should + always 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-NAME + Generate ‘_save’ fields in structs to preserve the original + encoding of some sub-value. This is useful for cryptographic + applications to avoid having to re-encode values to check signa‐ + tures, etc. + + --sequence=TYPE-NAME + Generate add/remove functions for ‘SET OF’ and ‘SEQUENCE OF’ + types. + + --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 + +HEIMDAL February 22, 2021 HEIMDAL + +``` + +## Implementation + +... + +## Futures + + - Add JER support so we can convert between JER and DER? + + - Add XDR support? + + - Add OER support? + + - Add NDR support? + + - Perhaps third parties will contribute more control over generate types? + +## 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/lib/asn1/README.template b/lib/asn1/README.template deleted file mode 100644 index 602262ba7..000000000 --- a/lib/asn1/README.template +++ /dev/null @@ -1,163 +0,0 @@ -#!/bin/sh - -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: /' - -exit 0 - -Notes about the template parser: - -- assumption: code is large, tables smaller - -- smaller tables and code, smaller cache footprint, better performance - -- how to generate template based stubs: - - make check asn1_compile_FLAGS=--template > log - - or - - ./configure --enable-asn1-templating - -- pretty much the same as the generate code, except uses tables instead of code - -- 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 gen.c (to generate - declarations of those stub functions). - -TODO: - - Fuzzing tests - - - 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. - - Or maybe not. We can afford larger template footprint if we can get - more bang for that. For example, if we add type and member names to - the templates, we could have template interpreters that implement JER - (JSON Encoding Rules) and/or GSER (Generic String Encoding Rules), - and it will cost only the size of the new interpreters plust the - extra metadata (type and member names). - - Perhaps we could rely on `dladdr()` to find the names of template - data structures and work out the type and member names from that? - But then, making more of those static / stripping them would save us - some of the cost of adding type and member names to the templates. - Using `dladdr()` might be a problem because it's not really portable, - and our implementation in lib/roken for WIN32 does not report a - symbol name, but there is a way to get that in WIN32 - (see https://github.com/dlfcn-win32/dlfcn-win32/). - - E.g., if we know the name of a template table as - "asn1_TBSCertificate_tag_version_28" then we can work out that it's - for the member named `version` in the type named `TBSCertificate`. - - -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/lib/asn1/asn1-common.h b/lib/asn1/asn1-common.h index 8a935d374..f68efa0e9 100644 --- a/lib/asn1/asn1-common.h +++ b/lib/asn1/asn1-common.h @@ -52,6 +52,8 @@ typedef struct 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; #define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \ do { \ diff --git a/lib/asn1/asn1-template.h b/lib/asn1/asn1-template.h index aba17d76d..47fe53499 100644 --- a/lib/asn1/asn1-template.h +++ b/lib/asn1/asn1-template.h @@ -38,9 +38,55 @@ #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/GSER/whatver, and probably for not-C-coded template interpreters, + * we'll need to have an entry type for the names of structures and their + * fields. + * + * - For auto open types we need a new opcode, let's call it + * A1_OP_OPENTYPE_OBJSET, and we need to encode into its entry: + * a) the index of the template entry for the type ID field, and + * b) the index of the template entry for the open type field, + * c) 1 bit to indicate whether the object set is sorted by type ID value, + * d) a pointer to the object set's template. + * With that we can then find the struct offsets of those, and also their + * types (since we can find their template entries). + * The object set entries should be encoded into two template entries each: + * one pointing to the value of the type ID field for that object (unless + * the value is an integer, in which case the ptr should be the integer + * value directly), and the other pointing to the template for the type + * identified by the type ID. These will need an opcode each... + * A1_OP_OPENTYPE_ID and A1_OP_OPENTYPE. + * We should also end the object set with an A1_OP_OPENTYPE_OBJSET entry so + * that iterating backwards can be fast. Unless... unless we don't inline + * the object set and its objects but point to the object set's template. + * Also, for extensible object sets we can point to the object set's name, + * and we can then have a function to get an object set template by name, + * one to release that, and one to add an object to the object set (there's + * no need to remove objects from object sets, which helps with thread- + * safety). And then we don't need (c) either. + * The decoder will then not see these entries until after decoding the type + * ID and open type field (as its outer type, so OCTET STRING, BIT STRING, + * or HEIM_ANY) and so it will be able to find those values in the struct at + * their respective offsets. + * The encoder and decoder both need to identify the relevant object in the + * object set, either by linear search or binary search if they are sorted + * by type ID value, then interpret the template for the identified type. + * The encoder needs to place the encoding into the normal location for it + * in the struct, then it can execute the normal template entry for it. + */ + /* 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: @@ -49,6 +95,9 @@ * 22..23 class * 24..27 flags * 28..31 op + * + * ptr points to template for tagged type + * offset is offset of struct field */ /* parse: @@ -56,11 +105,55 @@ * 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: when it happens at index 1 it's the name of the SET/SEQUENCE/CHOICE + * when it happens at any other index it's the name of the field that the + * next entry deals with + * + * 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) @@ -73,6 +166,10 @@ #define A1_OP_BMEMBER (0x70000000) #define A1_OP_CHOICE (0x80000000) #define A1_OP_DEFVAL (0x90000000) +#define A1_OP_OPENTYPE_OBJSET (0xa0000000) +#define A1_OP_OPENTYPE_ID (0xb0000000) +#define A1_OP_OPENTYPE (0xc0000000) +#define A1_OP_NAME (0xd0000000) #define A1_FLAG_MASK (0x0f000000) #define A1_FLAG_OPTIONAL (0x01000000) @@ -105,6 +202,10 @@ #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; diff --git a/lib/asn1/asn1_compile.1 b/lib/asn1/asn1_compile.1 new file mode 100644 index 000000000..206111981 --- /dev/null +++ b/lib/asn1/asn1_compile.1 @@ -0,0 +1,135 @@ +.\" 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-NAME +.Op Fl Fl sequence=TYPE-NAME +.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 +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). +The template backend generates +.Dq 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 +because as we add support for more encoding rules 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. +More importantly, currently only the template backend supports +automatic decoding of open types via X.681/X.682/X.683 +annotations. +.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-NAME +Generate +.Sq _save +fields in structs to preserve the original encoding of some +sub-value. +This is useful for cryptographic applications to avoid having to +re-encode values to check signatures, etc. +.It Fl Fl sequence=TYPE-NAME +Generate add/remove functions for +.Sq SET OF +and +.Sq SEQUENCE OF +types. +.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 . +.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 diff --git a/lib/asn1/asn1parse.y b/lib/asn1/asn1parse.y index 5a808f57d..2930d2d4b 100644 --- a/lib/asn1/asn1parse.y +++ b/lib/asn1/asn1parse.y @@ -49,6 +49,18 @@ #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 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 *); @@ -62,6 +74,7 @@ struct string_list { }; static int default_tag_env = TE_EXPLICIT; +static unsigned long idcounter; /* Declarations for Bison */ #define YYMALLOC malloc @@ -75,12 +88,21 @@ static int default_tag_env = TE_EXPLICIT; 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; } @@ -169,15 +191,36 @@ static int default_tag_env = TE_EXPLICIT; %token EEQUAL %token ELLIPSIS -%token IDENTIFIER referencename +%token TYPE_IDENTIFIER referencename +%token CLASS_IDENTIFIER +%token VALUE_IDENTIFIER %token STRING %token NUMBER %type SignedNumber %type Class tagenv +%type DummyReference -%type Value -%type BuiltinValue +%type 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 ValueExNull +%type BuiltinValue BuiltinValueExNull %type IntegerValue %type BooleanValue %type ObjectIdentifierValue @@ -187,6 +230,10 @@ static int default_tag_env = TE_EXPLICIT; %type ReferencedValue %type Valuereference +%type DefinedObjectClass ParamGovernor +%type ObjectClassDefn +%type Parameter + %type Type %type BuiltinType %type BitStringType @@ -208,9 +255,19 @@ static int default_tag_env = TE_EXPLICIT; %type ObjectIdentifierType %type CharacterStringType %type RestrictedCharactedStringType +%type ObjectClassFieldType +%type ParameterizedType +/*%type TypeFromObject*/ + +%type ObjectSet DefinedObjectSet +%type ActualParameter +%type Object DefinedObject ObjectDefn +%type FieldSetting %type Tag +%type FieldSpec TypeFieldSpec FixedTypeValueFieldSpec +%type FieldSpecList %type ComponentType %type NamedBit %type NamedNumber @@ -219,6 +276,8 @@ static int default_tag_env = TE_EXPLICIT; %type Enumerations %type NamedBitList %type NamedNumberList +%type ObjectSetSpec +%type FieldSettings %type objid objid_list objid_element objid_opt %type range size @@ -230,6 +289,8 @@ static int default_tag_env = TE_EXPLICIT; %type GeneralConstraint %type ContentsConstraint %type UserDefinedConstraint +%type SimpleTableConstraint TableConstraint +%type ComponentRelationConstraint @@ -237,13 +298,60 @@ static int default_tag_env = TE_EXPLICIT; %% -ModuleDefinition: IDENTIFIER objid_opt kw_DEFINITIONS TagDefault ExtensionDefault +/* + * We have sinned by allowing types to have names that start with lower-case, + * and values that have names that start with upper-case. + * + * 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 begun to undo our sin by not allowing wrong-case identifiers in + * certain situations. + * + * 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) + * + * We have fixed most of these, in some cases leaving behind aliases in header + * files as needed. + * + * This issue is probably also the source of remaining shift/reduce conflicts. + * + * In the FieldSetting rule in particular, 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 even without committing this + * leading-identifier-character-case sin, 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/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. + */ +Identifier : TYPE_IDENTIFIER { $$ = $1; } + | VALUE_IDENTIFIER { $$ = $1; }; + +ModuleDefinition: Identifier objid_opt kw_DEFINITIONS TagDefault ExtensionDefault EEQUAL kw_BEGIN ModuleBody kw_END { } + | CLASS_IDENTIFIER objid_opt kw_DEFINITIONS TagDefault ExtensionDefault + EEQUAL kw_BEGIN ModuleBody kw_END ; -TagDefault : kw_EXPLICIT kw_TAGS +TagDefault : kw_EXPLICIT kw_TAGS { default_tag_env = TE_EXPLICIT; } | kw_IMPLICIT kw_TAGS { default_tag_env = TE_IMPLICIT; } @@ -273,8 +381,22 @@ SymbolsFromModuleList: SymbolsFromModule | SymbolsFromModuleList SymbolsFromModule ; -SymbolsFromModule: referencenames kw_FROM IDENTIFIER objid_opt +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); @@ -301,15 +423,20 @@ AssignmentList : Assignment Assignment : TypeAssignment | ValueAssignment + | ParameterizedTypeAssignment + | ObjectClassAssignment + | ObjectAssignment + | ObjectSetAssignment + /* | ParameterizedAssignment // from X.683 */ ; -referencenames : IDENTIFIER ',' referencenames +referencenames : Identifier ',' referencenames { $$ = emalloc(sizeof(*$$)); $$->string = $1; $$->next = $3; } - | IDENTIFIER + | Identifier { $$ = emalloc(sizeof(*$$)); $$->string = $1; @@ -317,19 +444,447 @@ referencenames : IDENTIFIER ',' referencenames } ; -TypeAssignment : IDENTIFIER EEQUAL Type +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; + 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); - if (original_order) - generate_type(s); - else - generate_type_header_forwards(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 */ + ; + Type : BuiltinType | ReferencedType | ConstrainedType @@ -349,8 +904,14 @@ BuiltinType : BitStringType | 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, @@ -429,7 +990,7 @@ NamedNumberList : NamedNumber { $$ = $1; } /* XXX used for Enumerations */ ; -NamedNumber : IDENTIFIER '(' SignedNumber ')' +NamedNumber : Identifier '(' SignedNumber ')' { $$ = emalloc(sizeof(*$$)); $$->name = $1; @@ -440,6 +1001,20 @@ NamedNumber : IDENTIFIER '(' SignedNumber ')' $$->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 '}' @@ -562,9 +1137,16 @@ ChoiceType : kw_CHOICE '{' /* AlternativeTypeLists */ ComponentTypeList '}' ReferencedType : DefinedType | UsefulType + /* | TypeFromObject // X.681 */ + /* | ValueSetFromObjects // X.681 */ ; -DefinedType : IDENTIFIER +/* +TypeFromObject : VALUE_IDENTIFIER '.' '&' TYPE_IDENTIFIER + { $$ = type_from_object($1, $4); }; + */ + +DefinedType : TYPE_IDENTIFIER { Symbol *s = addsym($1); $$ = new_type(TType); @@ -573,8 +1155,55 @@ DefinedType : IDENTIFIER 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; + + /* 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, @@ -589,7 +1218,9 @@ UsefulType : kw_GeneralizedTime ConstrainedType : Type Constraint { - /* if (Constraint.type == contentConstrant) { + $$ = $1; + $$->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); @@ -614,6 +1245,7 @@ ConstraintSpec : GeneralConstraint GeneralConstraint: ContentsConstraint | UserDefinedConstraint + | TableConstraint ; ContentsConstraint: kw_CONTAINING Type @@ -646,6 +1278,65 @@ UserDefinedConstraint: kw_CONSTRAINED kw_BY '{' '}' } ; +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); @@ -654,35 +1345,35 @@ TaggedType : Tag tagenv Type if (template_flag) { $$->subtype = $3; } else if ($2 == TE_IMPLICIT) { - Type *t = $3; + Type *t = $3; - /* - * XXX 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) - $$->tag.tagenv = TE_EXPLICIT; + /* + * 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) + $$->tag.tagenv = TE_EXPLICIT; if($3->type == TTag && $2 == TE_IMPLICIT) { $$->subtype = $3->subtype; free($3); - } else { - $$->subtype = $3; + } else { + $$->subtype = $3; } } else { - $$->subtype = $3; - } + $$->subtype = $3; + } } ; @@ -727,7 +1418,7 @@ tagenv : /* */ ; -ValueAssignment : IDENTIFIER Type EEQUAL Value +ValueAssignment : Identifier Type EEQUAL Value { Symbol *s; s = addsym ($1); @@ -735,6 +1426,15 @@ ValueAssignment : IDENTIFIER Type EEQUAL Value 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; } ; @@ -806,7 +1506,7 @@ ComponentTypeList: ComponentType } ; -NamedType : IDENTIFIER Type +NamedType : Identifier Type { $$ = emalloc(sizeof(*$$)); $$->name = $1; @@ -850,7 +1550,7 @@ NamedBitList : NamedBit } ; -NamedBit : IDENTIFIER '(' NUMBER ')' +NamedBit : Identifier '(' NUMBER ')' { $$ = emalloc(sizeof(*$$)); $$->name = $1; @@ -888,11 +1588,11 @@ objid_list : /* empty */ } ; -objid_element : IDENTIFIER '(' NUMBER ')' +objid_element : Identifier '(' NUMBER ')' { $$ = new_objid($1, $3); } - | IDENTIFIER + | Identifier { Symbol *s = addsym($1); if(s->stype != SValue || @@ -913,6 +1613,10 @@ Value : BuiltinValue | ReferencedValue ; +ValueExNull : BuiltinValueExNull + | ReferencedValue + ; + BuiltinValue : BooleanValue | CharacterStringValue | IntegerValue @@ -920,13 +1624,20 @@ BuiltinValue : BooleanValue | NullValue ; +BuiltinValueExNull + : BooleanValue + | CharacterStringValue + | IntegerValue + | ObjectIdentifierValue + ; + ReferencedValue : DefinedValue ; DefinedValue : Valuereference ; -Valuereference : IDENTIFIER +Valuereference : VALUE_IDENTIFIER { Symbol *s = addsym($1); if(s->stype != SValue) @@ -1029,8 +1740,6 @@ add_oid_to_tail(struct objid *head, struct objid *tail) o->next = tail; } -static unsigned long idcounter; - static Type * new_type (Typetype tt) { @@ -1077,6 +1786,123 @@ fix_labels(Symbol *s) char *p = NULL; if (asprintf(&p, "choice_%s", s->gen_name) < 0 || p == NULL) errx(1, "malloc"); - fix_labels2(s->type, p); + 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; +} diff --git a/lib/asn1/check-gen.c b/lib/asn1/check-gen.c index 6d6cc18f7..7165db290 100644 --- a/lib/asn1/check-gen.c +++ b/lib/asn1/check-gen.c @@ -2029,6 +2029,256 @@ test_x690sample(void) 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, + }; + heim_octet_string os; + Certificate c0, c1; + size_t i, nknown, size; + 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; + + 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)) + 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)) + 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)) + return 1; + der_free_octet_string(&os); + + /* XXX Test setting some of the _ioschoice_extnValue._element's to 0 */ + free_Certificate(&c0); + free_Certificate(&c1); + return 0; +} +#endif + int main(int argc, char **argv) { @@ -2072,5 +2322,9 @@ main(int argc, char **argv) DO_ONE(test_default); +#if ASN1_IOS_SUPPORTED + DO_ONE(test_ios); +#endif + return ret; } diff --git a/lib/asn1/cms.asn1 b/lib/asn1/cms.asn1 index 4c1077028..ae547e573 100644 --- a/lib/asn1/cms.asn1 +++ b/lib/asn1/cms.asn1 @@ -5,7 +5,7 @@ CMS DEFINITIONS ::= BEGIN IMPORTS CertificateSerialNumber, AlgorithmIdentifier, Name, Attribute, Certificate, SubjectKeyIdentifier FROM rfc2459 - heim_any FROM heim; + HEIM_ANY FROM heim; id-pkcs7 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) } @@ -18,11 +18,11 @@ 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) + cMSVersion-v0(0), + cMSVersion-v1(1), + cMSVersion-v2(2), + cMSVersion-v3(3), + cMSVersion-v4(4) } DigestAlgorithmIdentifier ::= AlgorithmIdentifier @@ -34,7 +34,7 @@ MessageDigest ::= OCTET STRING ContentInfo ::= SEQUENCE { contentType ContentType, - content [0] EXPLICIT heim_any OPTIONAL -- DEFINED BY contentType + content [0] EXPLICIT HEIM_ANY OPTIONAL -- DEFINED BY contentType } EncapsulatedContentInfo ::= SEQUENCE { @@ -42,7 +42,7 @@ EncapsulatedContentInfo ::= SEQUENCE { eContent [0] EXPLICIT OCTET STRING OPTIONAL } -CertificateSet ::= SET OF heim_any +CertificateSet ::= SET OF HEIM_ANY CertificateList ::= Certificate diff --git a/lib/asn1/crmf.asn1 b/lib/asn1/crmf.asn1 index 8fa29a655..696a89be1 100644 --- a/lib/asn1/crmf.asn1 +++ b/lib/asn1/crmf.asn1 @@ -12,7 +12,7 @@ IMPORTS Extension, AlgorithmIdentifier FROM rfc2459 - heim_any + HEIM_ANY FROM heim; CRMFRDNSequence ::= SEQUENCE OF RelativeDistinguishedName @@ -56,7 +56,7 @@ POPOPrivKey ::= CHOICE { subsequentMessage [1] IMPLICIT SubsequentMessage, dhMAC [2] BIT STRING, -- Deprecated agreeMAC [3] IMPLICIT PKMACValue, - encryptedKey [4] heim_any + encryptedKey [4] HEIM_ANY } ProofOfPossession ::= CHOICE { @@ -71,7 +71,7 @@ CertTemplate ::= SEQUENCE { serialNumber [1] INTEGER OPTIONAL, signingAlg [2] SEQUENCE { algorithm OBJECT IDENTIFIER, - parameters heim_any OPTIONAL + parameters HEIM_ANY OPTIONAL } -- AlgorithmIdentifier -- OPTIONAL, issuer [3] IMPLICIT CHOICE { rdnSequence CRMFRDNSequence diff --git a/lib/asn1/der.c b/lib/asn1/der.c index 0c59e6f64..f500de3ce 100644 --- a/lib/asn1/der.c +++ b/lib/asn1/der.c @@ -66,7 +66,7 @@ static const char *tag_names[] = { NULL, /* 9 */ "Enumerated", /* 10 */ NULL, /* 11 */ - NULL, /* 12 */ + "UTF8String", /* 12 */ NULL, /* 13 */ NULL, /* 14 */ NULL, /* 15 */ diff --git a/lib/asn1/extra.c b/lib/asn1/extra.c index a18797ec2..a4a18f63e 100644 --- a/lib/asn1/extra.c +++ b/lib/asn1/extra.c @@ -102,6 +102,38 @@ copy_heim_any(const heim_any *from, heim_any *to) return der_copy_octet_string(from, to); } +int +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 +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 +free_HEIM_ANY(heim_any *data) +{ + der_free_octet_string(data); +} + +size_t +length_HEIM_ANY(const heim_any *data) +{ + return data->length; +} + +int +copy_HEIM_ANY(const heim_any *from, heim_any *to) +{ + return der_copy_octet_string(from, to); +} + int encode_heim_any_set(unsigned char *p, size_t len, const heim_any_set *data, size_t *size) @@ -139,3 +171,41 @@ heim_any_cmp(const heim_any_set *p, const heim_any_set *q) { return der_heim_octet_string_cmp(p, q); } + +int +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 +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 +free_HEIM_ANY_SET(heim_any_set *data) +{ + der_free_octet_string(data); +} + +size_t +length_HEIM_ANY_SET(const heim_any *data) +{ + return data->length; +} + +int +copy_HEIM_ANY_SET(const heim_any_set *from, heim_any_set *to) +{ + return der_copy_octet_string(from, to); +} + +int +HEIM_ANY_cmp(const heim_any_set *p, const heim_any_set *q) +{ + return der_heim_octet_string_cmp(p, q); +} diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index a96e59619..3dd09b959 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -234,7 +234,9 @@ init_generate (const char *filename, const char *base) "} heim_bit_string;\n\n"); fprintf (headerfile, "typedef struct heim_base_data heim_any;\n" - "typedef struct heim_base_data heim_any_set;\n\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"); fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \\\n" " do { \\\n" " (BL) = length_##T((S)); \\\n" @@ -643,7 +645,12 @@ define_asn1 (int level, Type *t) { switch (t->type) { case TType: - fprintf (headerfile, "%s", t->symbol->name); + if (!t->symbol && t->typeref.iosclass) { + fprintf(headerfile, "%s.&%s", + t->typeref.iosclass->symbol->name, + t->typeref.field->name); + } else + fprintf(headerfile, "%s", t->symbol->name); break; case TInteger: if(t->members == NULL) { @@ -810,8 +817,215 @@ getnewbasename(char **newbasename, int typedefp, const char *basename, const cha err(1, "malloc"); } +static void define_type(int, const char *, const char *, Type *, Type *, int, int); + +/* + * 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 */ + *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 */ + *opentypemember = m; + *opentypefield = subtype->typeref.field; + *is_array_of = sOfType != NULL; + idmembername = subtype->constraint->u.content.crel.membername; + break; + } + } + /* 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)) + 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_type (int level, const char *name, const char *basename, Type *t, int typedefp, int preservep) +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"); + + /* Iterate objects in the object set, gen enum labels */ + fprintf(headerfile, "enum { choice_%s_iosnumunknown = 0,\n", + newbasename); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + if (strcmp(of->name, typeidfield->name)) + 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(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"); + for (i = 0; i < nobjs; i++) { + HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) { + char *n = NULL; + + if (strcmp(of->name, opentypefield->name)) + 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, FALSE, FALSE); + free(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 void +define_type(int level, const char *name, const char *basename, Type *pt, Type *t, int typedefp, int preservep) { const char *label_prefix = NULL; const char *label_prefix_sep = NULL; @@ -820,7 +1034,12 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ switch (t->type) { case TType: space(level); - fprintf(headerfile, "%s %s;\n", t->symbol->gen_name, name); + 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 + fprintf(headerfile, "%s %s;\n", t->symbol->gen_name, name); break; case TInteger: if (t->symbol && t->symbol->emitted_definition) @@ -915,7 +1134,7 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ while (pos < m->val) { if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL) err(1, "malloc"); - define_type (level + 1, n, newbasename, &i, FALSE, FALSE); + define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE); free(n); pos++; } @@ -923,7 +1142,7 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ n = NULL; if (asprintf (&n, "%s:1", m->gen_name) < 0 || n == NULL) errx(1, "malloc"); - define_type (level + 1, n, newbasename, &i, FALSE, FALSE); + define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE); free (n); n = NULL; pos++; @@ -938,7 +1157,7 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ char *n = NULL; if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL) errx(1, "malloc"); - define_type (level + 1, n, newbasename, &i, FALSE, FALSE); + define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE); free(n); pos++; } @@ -989,13 +1208,15 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ } else if (m->optional) { char *n = NULL; - if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL) + if (asprintf(&n, "*%s", m->gen_name) < 0 || n == NULL) errx(1, "malloc"); - define_type (level + 1, n, newbasename, m->type, FALSE, FALSE); + define_type(level + 1, n, newbasename, t, m->type, FALSE, FALSE); free (n); } else - define_type (level + 1, m->gen_name, newbasename, m->type, FALSE, FALSE); + define_type(level + 1, m->gen_name, newbasename, t, m->type, FALSE, FALSE); } + if (t->actual_parameter && t->actual_parameter->objects) + define_open_type(level, newbasename, name, basename, t, t); space(level); fprintf (headerfile, "} %s;\n", name); break; @@ -1013,8 +1234,8 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ space(level); fprintf (headerfile, "struct %s {\n", newbasename); - define_type (level + 1, "len", newbasename, &i, FALSE, FALSE); - define_type (level + 1, "*val", newbasename, t->subtype, FALSE, FALSE); + define_type(level + 1, "len", newbasename, t, &i, FALSE, FALSE); + define_type(level + 1, "*val", newbasename, t, t->subtype, FALSE, FALSE); space(level); fprintf (headerfile, "} %s;\n", name); break; @@ -1032,7 +1253,7 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ fprintf (headerfile, "heim_general_string %s;\n", name); break; case TTag: - define_type (level, name, basename, t->subtype, typedefp, preservep); + define_type(level, name, basename, t, t->subtype, typedefp, preservep); break; case TChoice: { int first = 1; @@ -1077,10 +1298,10 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL) errx(1, "malloc"); - define_type (level + 2, n, newbasename, m->type, FALSE, FALSE); + define_type(level + 2, n, newbasename, t, m->type, FALSE, FALSE); free (n); } else - define_type (level + 2, m->gen_name, newbasename, m->type, FALSE, FALSE); + define_type(level + 2, m->gen_name, newbasename, t, m->type, FALSE, FALSE); } space(level + 1); fprintf (headerfile, "} u;\n"); @@ -1140,7 +1361,7 @@ declare_type(const Symbol *s, Type *t, int typedefp) switch (t->type) { case TType: - define_type(0, s->gen_name, s->gen_name, s->type, TRUE, TRUE); + define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, TRUE); if (template_flag) generate_template_type_forward(s->gen_name); emitted_declaration(s); @@ -1162,7 +1383,7 @@ declare_type(const Symbol *s, Type *t, int typedefp) case TVisibleString: case TOID : case TNull: - define_type(0, s->gen_name, s->gen_name, s->type, TRUE, TRUE); + define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, TRUE); if (template_flag) generate_template_type_forward(s->gen_name); emitted_declaration(s); @@ -1295,10 +1516,12 @@ generate_subtypes_header(const Symbol *s) switch (t->type) { default: return; - case TType: - if (t->symbol && (s = getsym(t->symbol->name))) - generate_type_header(s); + case TType: { + Symbol *s2; + if (t->symbol && (s2 = getsym(t->symbol->name)) != s) + generate_type_header(s2); return; + } case TSet: case TSequence: case TChoice: @@ -1342,10 +1565,14 @@ generate_type_header (const Symbol *s) * needed in stripped objects. */ if (!s->emitted_tag_enums) { - while (t->type == TType && s->type->symbol && s->type->symbol->type) - t = s->type->symbol->type; + 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")) { + if (t->type == TType && t->symbol && strcmp(t->symbol->name, "HEIM_ANY")) { /* * This type is ultimately an alias of an imported type, so we don't * know its outermost tag here. @@ -1375,13 +1602,10 @@ generate_type_header (const Symbol *s) return; fprintf(headerfile, "typedef "); - define_type(0, s->gen_name, s->gen_name, s->type, TRUE, + define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, preserve_type(s->name) ? TRUE : FALSE); fprintf(headerfile, "\n"); - if (template_flag) - generate_template_type_forward(s->gen_name); - emitted_definition(s); } @@ -1390,6 +1614,8 @@ 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 diff --git a/lib/asn1/gen_decode.c b/lib/asn1/gen_decode.c index 2ebaa955f..e40870b4f 100644 --- a/lib/asn1/gen_decode.c +++ b/lib/asn1/gen_decode.c @@ -531,7 +531,7 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval, (t->subtype->type == TSequence || t->subtype->type == TSet)) replace_tag = 1; - else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any")) + 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 = 1; diff --git a/lib/asn1/gen_glue.c b/lib/asn1/gen_glue.c index bed2cdfe1..24f16528c 100644 --- a/lib/asn1/gen_glue.c +++ b/lib/asn1/gen_glue.c @@ -103,17 +103,9 @@ generate_units (const Type *t, const char *gen_name) { Member *m; - if (template_flag) { - fprintf (headerfile, - "extern const struct units *asn1_%s_table_units;\n", - gen_name); - fprintf (headerfile, "#define asn1_%s_units() (asn1_%s_table_units)\n", - gen_name, gen_name); - } else { - fprintf (headerfile, - "const struct units * asn1_%s_units(void);\n", - gen_name); - } + fprintf (headerfile, + "const struct units * asn1_%s_units(void);\n", + gen_name); fprintf (get_code_file(), "static struct units %s_units[] = {\n", @@ -130,16 +122,11 @@ generate_units (const Type *t, const char *gen_name) "\t{NULL,\t0}\n" "};\n\n"); - if (template_flag) - fprintf (get_code_file(), - "const struct units * asn1_%s_table_units = %s_units;\n", - gen_name, gen_name); - else - fprintf (get_code_file(), - "const struct units * asn1_%s_units(void){\n" - "return %s_units;\n" - "}\n\n", - gen_name, gen_name); + fprintf (get_code_file(), + "const struct units * asn1_%s_units(void){\n" + "return %s_units;\n" + "}\n\n", + gen_name, gen_name); } diff --git a/lib/asn1/gen_locl.h b/lib/asn1/gen_locl.h index e92a43144..5eccd0b07 100644 --- a/lib/asn1/gen_locl.h +++ b/lib/asn1/gen_locl.h @@ -128,6 +128,7 @@ 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); @@ -144,9 +145,15 @@ int seq_type(const char *); 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 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 *); diff --git a/lib/asn1/gen_template.c b/lib/asn1/gen_template.c index 0859a887e..82fc053a9 100644 --- a/lib/asn1/gen_template.c +++ b/lib/asn1/gen_template.c @@ -295,6 +295,8 @@ 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_pointer_reference(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); static struct tlisthead tlistmaster = HEIM_TAILQ_HEAD_INITIALIZER(tlistmaster); @@ -426,7 +428,7 @@ tlist_find_dup(const struct tlist *tl) /* - * + * Add an entry to a template. */ static struct template * @@ -442,6 +444,10 @@ add_line(struct templatehead *t, const char *fmt, ...) return q; } +/* + * Add an entry to a template, with the pointer field bein 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, @@ -464,6 +470,28 @@ add_line_pointer(struct templatehead *t, q->ptr = strdup(ptr); } +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) { @@ -598,6 +626,229 @@ defval(struct templatehead *temp, Member *m) } } +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; +} + +static 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; + + /* FIXME: This would be a good place to check field UNIQUE constraints */ + + 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 : ""); + continue; + } + o->typeidf = typeidobjf; + nobjs++; + } + *nobjsp = nobjs; + + 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; + 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); + 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 : ""); + continue; + } + + /* + * 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 *)%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 *)%lu) }", 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_members(struct templatehead *temp, const char *basetype, @@ -742,7 +993,18 @@ template_members(struct templatehead *temp, break; } case TSet: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; Member *m; + 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); @@ -752,6 +1014,9 @@ template_members(struct templatehead *temp, 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"); @@ -766,12 +1031,28 @@ template_members(struct templatehead *temp, 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); break; } case TSequence: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; Member *m; + 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); @@ -781,6 +1062,9 @@ template_members(struct templatehead *temp, 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"); @@ -795,8 +1079,13 @@ template_members(struct templatehead *temp, 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); break; } case TTag: { @@ -1010,6 +1299,15 @@ 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, diff --git a/lib/asn1/heim_asn1.h b/lib/asn1/heim_asn1.h index 4eeafc20f..0f8ff65d1 100644 --- a/lib/asn1/heim_asn1.h +++ b/lib/asn1/heim_asn1.h @@ -49,4 +49,19 @@ size_t length_heim_any_set(const heim_any_set *); int copy_heim_any_set(const heim_any_set *, heim_any_set *); int heim_any_cmp(const heim_any_set *, const heim_any_set *); +int encode_HEIM_ANY(unsigned char *, size_t, const heim_any *, size_t *); +int decode_HEIM_ANY(const unsigned char *, size_t, heim_any *, size_t *); +void free_HEIM_ANY(heim_any *); +size_t length_HEIM_ANY(const heim_any *); +int copy_HEIM_ANY(const heim_any *, heim_any *); + +int encode_HEIM_ANY_SET(unsigned char *, size_t, + const heim_any_set *, size_t *); +int decode_HEIM_ANY_SET(const unsigned char *, size_t, + heim_any_set *,size_t *); +void free_HEIM_ANY_SET(heim_any_set *); +size_t length_HEIM_ANY_SET(const heim_any_set *); +int copy_HEIM_ANY_SET(const heim_any_set *, heim_any_set *); +int heim_any_cmp(const heim_any_set *, const heim_any_set *); + #endif /* __HEIM_ANY_H__ */ diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 5031e3921..42a4bd59a 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -286,8 +286,8 @@ ENCTYPE ::= INTEGER { -- this is sugar to make something ASN1 does not have: unsigned -krb5uint32 ::= INTEGER (0..4294967295) -krb5int32 ::= INTEGER (-2147483648..2147483647) +Krb5UInt32 ::= INTEGER (0..4294967295) +Krb5Int32 ::= INTEGER (-2147483648..2147483647) KerberosString ::= GeneralString @@ -306,14 +306,14 @@ Principal ::= SEQUENCE { Principals ::= SEQUENCE OF Principal HostAddress ::= SEQUENCE { - addr-type[0] krb5int32, + addr-type[0] Krb5Int32, address[1] OCTET STRING } -- This is from RFC1510. -- -- HostAddresses ::= SEQUENCE OF SEQUENCE { --- addr-type[0] krb5int32, +-- addr-type[0] Krb5Int32, -- address[1] OCTET STRING -- } @@ -324,7 +324,7 @@ HostAddresses ::= SEQUENCE OF HostAddress KerberosTime ::= GeneralizedTime -- Specifying UTC time zone (Z) AuthorizationDataElement ::= SEQUENCE { - ad-type[0] krb5int32, + ad-type[0] Krb5Int32, ad-data[1] OCTET STRING } @@ -393,23 +393,23 @@ LastReq ::= SEQUENCE OF SEQUENCE { EncryptedData ::= SEQUENCE { etype[0] ENCTYPE, -- EncryptionType - kvno[1] krb5int32 OPTIONAL, + kvno[1] Krb5Int32 OPTIONAL, cipher[2] OCTET STRING -- ciphertext } EncryptionKey ::= SEQUENCE { - keytype[0] krb5int32, + keytype[0] Krb5Int32, keyvalue[1] OCTET STRING } -- encoded Transited field TransitedEncoding ::= SEQUENCE { - tr-type[0] krb5int32, -- must be registered + tr-type[0] Krb5Int32, -- must be registered contents[1] OCTET STRING } Ticket ::= [APPLICATION 1] SEQUENCE { - tkt-vno[0] krb5int32, + tkt-vno[0] Krb5Int32, realm[1] Realm, sname[2] PrincipalName, enc-part[3] EncryptedData @@ -435,14 +435,14 @@ Checksum ::= SEQUENCE { } Authenticator ::= [APPLICATION 2] SEQUENCE { - authenticator-vno[0] krb5int32, + authenticator-vno[0] Krb5Int32, crealm[1] Realm, cname[2] PrincipalName, cksum[3] Checksum OPTIONAL, - cusec[4] krb5int32, + cusec[4] Krb5Int32, ctime[5] KerberosTime, subkey[6] EncryptionKey OPTIONAL, - seq-number[7] krb5uint32 OPTIONAL, + seq-number[7] Krb5UInt32 OPTIONAL, authorization-data[8] AuthorizationData OPTIONAL } @@ -455,7 +455,7 @@ PA-DATA ::= SEQUENCE { ETYPE-INFO-ENTRY ::= SEQUENCE { etype[0] ENCTYPE, salt[1] OCTET STRING OPTIONAL, - salttype[2] krb5int32 OPTIONAL + salttype[2] Krb5Int32 OPTIONAL } ETYPE-INFO ::= SEQUENCE OF ETYPE-INFO-ENTRY @@ -471,7 +471,7 @@ ETYPE-INFO2 ::= SEQUENCE SIZE (1..MAX) OF ETYPE-INFO2-ENTRY METHOD-DATA ::= SEQUENCE OF PA-DATA TypedData ::= SEQUENCE { - data-type[0] krb5int32, + data-type[0] Krb5Int32, data-value[1] OCTET STRING OPTIONAL } @@ -486,7 +486,7 @@ KDC-REQ-BODY ::= SEQUENCE { from[4] KerberosTime OPTIONAL, till[5] KerberosTime OPTIONAL, rtime[6] KerberosTime OPTIONAL, - nonce[7] krb5int32, + nonce[7] Krb5Int32, etype[8] SEQUENCE OF ENCTYPE, -- EncryptionType, -- in preference order addresses[9] HostAddresses OPTIONAL, @@ -496,7 +496,7 @@ KDC-REQ-BODY ::= SEQUENCE { } KDC-REQ ::= SEQUENCE { - pvno[1] krb5int32, + pvno[1] Krb5Int32, msg-type[2] MESSAGE-TYPE, padata[3] METHOD-DATA OPTIONAL, req-body[4] KDC-REQ-BODY @@ -510,7 +510,7 @@ TGS-REQ ::= [APPLICATION 12] KDC-REQ PA-ENC-TS-ENC ::= SEQUENCE { patimestamp[0] KerberosTime, -- client's time - pausec[1] krb5int32 OPTIONAL + pausec[1] Krb5Int32 OPTIONAL } -- draft-brezak-win2k-krb-authz-01 @@ -523,7 +523,7 @@ PA-PAC-REQUEST ::= SEQUENCE { PROV-SRV-LOCATION ::= GeneralString KDC-REP ::= SEQUENCE { - pvno[0] krb5int32, + pvno[0] Krb5Int32, msg-type[1] MESSAGE-TYPE, padata[2] METHOD-DATA OPTIONAL, crealm[3] Realm, @@ -538,7 +538,7 @@ TGS-REP ::= [APPLICATION 13] KDC-REP EncKDCRepPart ::= SEQUENCE { key[0] EncryptionKey, last-req[1] LastReq, - nonce[2] krb5int32, + nonce[2] Krb5Int32, key-expiration[3] KerberosTime OPTIONAL, flags[4] TicketFlags, authtime[5] KerberosTime, @@ -555,7 +555,7 @@ EncASRepPart ::= [APPLICATION 25] EncKDCRepPart EncTGSRepPart ::= [APPLICATION 26] EncKDCRepPart AP-REQ ::= [APPLICATION 14] SEQUENCE { - pvno[0] krb5int32, + pvno[0] Krb5Int32, msg-type[1] MESSAGE-TYPE, ap-options[2] APOptions, ticket[3] Ticket, @@ -563,50 +563,50 @@ AP-REQ ::= [APPLICATION 14] SEQUENCE { } AP-REP ::= [APPLICATION 15] SEQUENCE { - pvno[0] krb5int32, + pvno[0] Krb5Int32, msg-type[1] MESSAGE-TYPE, enc-part[2] EncryptedData } EncAPRepPart ::= [APPLICATION 27] SEQUENCE { ctime[0] KerberosTime, - cusec[1] krb5int32, + cusec[1] Krb5Int32, subkey[2] EncryptionKey OPTIONAL, - seq-number[3] krb5uint32 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, + 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, + 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, + 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, + 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, + pvno[0] Krb5Int32, msg-type[1] MESSAGE-TYPE, -- KRB_CRED tickets[2] SEQUENCE OF Ticket, enc-part[3] EncryptedData @@ -628,21 +628,21 @@ KrbCredInfo ::= SEQUENCE { EncKrbCredPart ::= [APPLICATION 29] SEQUENCE { ticket-info[0] SEQUENCE OF KrbCredInfo, - nonce[1] krb5int32 OPTIONAL, + nonce[1] Krb5Int32 OPTIONAL, timestamp[2] KerberosTime OPTIONAL, - usec[3] krb5int32 OPTIONAL, + usec[3] Krb5Int32 OPTIONAL, s-address[4] HostAddress OPTIONAL, r-address[5] HostAddress OPTIONAL } KRB-ERROR ::= [APPLICATION 30] SEQUENCE { - pvno[0] krb5int32, + pvno[0] Krb5Int32, msg-type[1] MESSAGE-TYPE, ctime[2] KerberosTime OPTIONAL, - cusec[3] krb5int32 OPTIONAL, + cusec[3] Krb5Int32 OPTIONAL, stime[4] KerberosTime, - susec[5] krb5int32, - error-code[6] krb5int32, + susec[5] Krb5Int32, + error-code[6] Krb5Int32, crealm[7] Realm OPTIONAL, cname[8] PrincipalName OPTIONAL, realm[9] Realm, -- Correct realm @@ -661,11 +661,11 @@ 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 +krb5-pvno Krb5Int32 ::= 5 -- current Kerberos protocol version number -- transited encodings -DOMAIN-X500-COMPRESS krb5int32 ::= 1 +domain-X500-Compress Krb5Int32 ::= 1 -- authorization data primitives @@ -679,7 +679,7 @@ AD-KDCIssued ::= SEQUENCE { } AD-AND-OR ::= SEQUENCE { - condition-count[0] INTEGER, + condition-count[0] Krb5Int32, elements[1] AuthorizationData } @@ -705,7 +705,7 @@ SAMFlags ::= BIT STRING { } PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE { - sam-type[0] krb5int32, + sam-type[0] Krb5Int32, sam-flags[1] SAMFlags, sam-type-name[2] GeneralString OPTIONAL, sam-track-id[3] GeneralString OPTIONAL, @@ -713,8 +713,8 @@ PA-SAM-CHALLENGE-2-BODY ::= SEQUENCE { 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, + sam-nonce[8] Krb5Int32, + sam-etype[9] Krb5Int32, ... } @@ -725,16 +725,16 @@ PA-SAM-CHALLENGE-2 ::= SEQUENCE { } PA-SAM-RESPONSE-2 ::= SEQUENCE { - sam-type[0] krb5int32, + 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, + sam-nonce[4] Krb5Int32, ... } PA-ENC-SAM-RESPONSE-ENC ::= SEQUENCE { - sam-nonce[0] krb5int32, + sam-nonce[0] Krb5Int32, sam-sad[1] GeneralString OPTIONAL, ... } @@ -799,7 +799,7 @@ KrbFastReq ::= SEQUENCE { } KrbFastArmor ::= SEQUENCE { - armor-type [0] krb5int32, + armor-type [0] Krb5Int32, armor-value [1] OCTET STRING, ... } @@ -817,7 +817,7 @@ PA-FX-FAST-REQUEST ::= CHOICE { KrbFastFinished ::= SEQUENCE { timestamp [0] KerberosTime, - usec [1] krb5int32, + usec [1] Krb5Int32, crealm [2] Realm, cname [3] PrincipalName, ticket-checksum [4] Checksum, @@ -828,7 +828,7 @@ KrbFastResponse ::= SEQUENCE { padata [0] METHOD-DATA, strengthen-key [1] EncryptionKey OPTIONAL, finished [2] KrbFastFinished OPTIONAL, - nonce [3] krb5uint32, + nonce [3] Krb5UInt32, ... } @@ -891,7 +891,7 @@ KERB-CRED ::= SEQUENCE { KERB-TGS-REQ-IN ::= SEQUENCE { cache [0] OCTET STRING SIZE (16), addrs [1] HostAddresses, - flags [2] krb5uint32, + flags [2] Krb5UInt32, imp [3] Principal OPTIONAL, ticket [4] OCTET STRING OPTIONAL, in_cred [5] KERB-CRED, diff --git a/lib/asn1/lex.l b/lib/asn1/lex.l index 9f38665a7..4554a9477 100644 --- a/lib/asn1/lex.l +++ b/lib/asn1/lex.l @@ -150,6 +150,10 @@ 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; @@ -250,7 +254,6 @@ WITH { return kw_WITH; } if(c == EOF) unterminated("string", start_lineno); *p++ = '\0'; - fprintf(stderr, "string -- %s\n", buf); yylval.name = estrdup(buf); return STRING; } @@ -263,9 +266,17 @@ WITH { return kw_WITH; } else return NUMBER; } -[A-Za-z][-A-Za-z0-9_]* { +[_][-A-Z0-9]* { yylval.name = estrdup ((const char *)yytext); - return IDENTIFIER; + 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; } diff --git a/lib/asn1/libasn1-exports.def b/lib/asn1/libasn1-exports.def index ffbaefd7f..956a099d0 100644 --- a/lib/asn1/libasn1-exports.def +++ b/lib/asn1/libasn1-exports.def @@ -4,6 +4,18 @@ EXPORTS _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 @@ -43,6 +55,7 @@ EXPORTS 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 @@ -92,9 +105,7 @@ EXPORTS asn1_oid_id_nist_aes_algs DATA asn1_oid_id_nistAlgorithm DATA asn1_oid_id_nist_sha_algs DATA - asn1_oid_id_on DATA asn1_oid_id_on_hardwareModuleName DATA - asn1_oid_id_on_permanentIdentifier DATA asn1_oid_id_pbeWithSHAAnd128BitRC2_CBC DATA asn1_oid_id_pbeWithSHAAnd128BitRC4 DATA asn1_oid_id_pbeWithSHAAnd2_KeyTripleDES_CBC DATA @@ -191,6 +202,10 @@ EXPORTS 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 @@ -274,12 +289,16 @@ EXPORTS 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 @@ -402,7 +421,9 @@ EXPORTS copy_HardwareModules copy_HardwareSerialEntry copy_heim_any + copy_HEIM_ANY copy_heim_any_set + copy_HEIM_ANY_SET copy_HostAddress copy_HostAddresses copy_ImplementedCompressAlgorithms @@ -432,11 +453,11 @@ EXPORTS copy_KeyIdentifier copy_KeyTransRecipientInfo copy_KeyUsage - copy_krb5int32 + copy_Krb5Int32 copy_KRB5PrincipalName copy_KRB5SignedPath copy_KRB5SignedPathData - copy_krb5uint32 + copy_Krb5UInt32 copy_KRB_CRED copy_KrbCredInfo copy_KRB_ERROR @@ -532,6 +553,7 @@ EXPORTS copy_PkinitSP80056AOtherInfo copy_PkinitSuppPubInfo copy_PKIXXmppAddr + copy_PolicyConstraints copy_PolicyInformation copy_PolicyMapping copy_PolicyMappings @@ -566,8 +588,11 @@ EXPORTS copy_SignerIdentifier copy_SignerInfo copy_SignerInfos + copy_SingleAttribute + copy_SkipCerts copy_SRVName copy_StrengthOfFunction + copy_SubjectDirectoryAttributes copy_SubjectInfoAccessSyntax copy_SubjectKeyIdentifier copy_SubjectPublicKeyInfo @@ -599,6 +624,12 @@ EXPORTS copy_VendorLoadErrorCode copy_Version copy_WrappedFirmwareKey + copy_X520CommonName + copy_X520LocalityName + copy_X520name + copy_X520OrganizationalUnitName + copy_X520OrganizationName + copy_X520StateOrProvinceName copy_X690SampleChildInformation copy_X690SampleDate copy_X690SampleEmployeeNumber @@ -612,12 +643,16 @@ EXPORTS 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 @@ -740,7 +775,9 @@ EXPORTS decode_HardwareModules decode_HardwareSerialEntry decode_heim_any + decode_HEIM_ANY decode_heim_any_set + decode_HEIM_ANY_SET decode_HostAddress decode_HostAddresses decode_ImplementedCompressAlgorithms @@ -770,11 +807,11 @@ EXPORTS decode_KeyIdentifier decode_KeyTransRecipientInfo decode_KeyUsage - decode_krb5int32 + decode_Krb5Int32 decode_KRB5PrincipalName decode_KRB5SignedPath decode_KRB5SignedPathData - decode_krb5uint32 + decode_Krb5UInt32 decode_KRB_CRED decode_KrbCredInfo decode_KRB_ERROR @@ -870,6 +907,7 @@ EXPORTS decode_PkinitSP80056AOtherInfo decode_PkinitSuppPubInfo decode_PKIXXmppAddr + decode_PolicyConstraints decode_PolicyInformation decode_PolicyMapping decode_PolicyMappings @@ -904,8 +942,11 @@ EXPORTS decode_SignerIdentifier decode_SignerInfo decode_SignerInfos + decode_SingleAttribute + decode_SkipCerts decode_SRVName decode_StrengthOfFunction + decode_SubjectDirectoryAttributes decode_SubjectInfoAccessSyntax decode_SubjectKeyIdentifier decode_SubjectPublicKeyInfo @@ -937,6 +978,12 @@ EXPORTS decode_VendorLoadErrorCode decode_Version decode_WrappedFirmwareKey + decode_X520CommonName + decode_X520LocalityName + decode_X520name + decode_X520OrganizationalUnitName + decode_X520OrganizationName + decode_X520StateOrProvinceName decode_X690SampleChildInformation decode_X690SampleDate decode_X690SampleEmployeeNumber @@ -1042,9 +1089,27 @@ EXPORTS 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 @@ -1078,12 +1143,16 @@ EXPORTS 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 @@ -1206,7 +1275,9 @@ EXPORTS encode_HardwareModules encode_HardwareSerialEntry encode_heim_any + encode_HEIM_ANY encode_heim_any_set + encode_HEIM_ANY_SET encode_HostAddress encode_HostAddresses encode_ImplementedCompressAlgorithms @@ -1236,11 +1307,11 @@ EXPORTS encode_KeyIdentifier encode_KeyTransRecipientInfo encode_KeyUsage - encode_krb5int32 + encode_Krb5Int32 encode_KRB5PrincipalName encode_KRB5SignedPath encode_KRB5SignedPathData - encode_krb5uint32 + encode_Krb5UInt32 encode_KRB_CRED encode_KrbCredInfo encode_KRB_ERROR @@ -1336,6 +1407,7 @@ EXPORTS encode_PkinitSP80056AOtherInfo encode_PkinitSuppPubInfo encode_PKIXXmppAddr + encode_PolicyConstraints encode_PolicyInformation encode_PolicyMapping encode_PolicyMappings @@ -1370,8 +1442,11 @@ EXPORTS encode_SignerIdentifier encode_SignerInfo encode_SignerInfos + encode_SingleAttribute + encode_SkipCerts encode_SRVName encode_StrengthOfFunction + encode_SubjectDirectoryAttributes encode_SubjectInfoAccessSyntax encode_SubjectKeyIdentifier encode_SubjectPublicKeyInfo @@ -1403,6 +1478,12 @@ EXPORTS encode_VendorLoadErrorCode encode_Version encode_WrappedFirmwareKey + encode_X520CommonName + encode_X520LocalityName + encode_X520name + encode_X520OrganizationalUnitName + encode_X520OrganizationName + encode_X520StateOrProvinceName encode_X690SampleChildInformation encode_X690SampleDate encode_X690SampleEmployeeNumber @@ -1417,12 +1498,16 @@ EXPORTS 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 @@ -1545,7 +1630,9 @@ EXPORTS free_HardwareModules free_HardwareSerialEntry free_heim_any + free_HEIM_ANY free_heim_any_set + free_HEIM_ANY_SET free_HostAddress free_HostAddresses free_ImplementedCompressAlgorithms @@ -1575,11 +1662,11 @@ EXPORTS free_KeyIdentifier free_KeyTransRecipientInfo free_KeyUsage - free_krb5int32 + free_Krb5Int32 free_KRB5PrincipalName free_KRB5SignedPath free_KRB5SignedPathData - free_krb5uint32 + free_Krb5UInt32 free_KRB_CRED free_KrbCredInfo free_KRB_ERROR @@ -1675,6 +1762,7 @@ EXPORTS free_PkinitSP80056AOtherInfo free_PkinitSuppPubInfo free_PKIXXmppAddr + free_PolicyConstraints free_PolicyInformation free_PolicyMapping free_PolicyMappings @@ -1709,8 +1797,11 @@ EXPORTS free_SignerIdentifier free_SignerInfo free_SignerInfos + free_SingleAttribute + free_SkipCerts free_SRVName free_StrengthOfFunction + free_SubjectDirectoryAttributes free_SubjectInfoAccessSyntax free_SubjectKeyIdentifier free_SubjectPublicKeyInfo @@ -1742,12 +1833,19 @@ EXPORTS 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 @@ -1777,12 +1875,16 @@ EXPORTS 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 @@ -1905,7 +2007,9 @@ EXPORTS length_HardwareModules length_HardwareSerialEntry length_heim_any + length_HEIM_ANY length_heim_any_set + length_HEIM_ANY_SET length_HostAddress length_HostAddresses length_ImplementedCompressAlgorithms @@ -1935,11 +2039,11 @@ EXPORTS length_KeyIdentifier length_KeyTransRecipientInfo length_KeyUsage - length_krb5int32 + length_Krb5Int32 length_KRB5PrincipalName length_KRB5SignedPath length_KRB5SignedPathData - length_krb5uint32 + length_Krb5UInt32 length_KRB_CRED length_KrbCredInfo length_KRB_ERROR @@ -2035,6 +2139,7 @@ EXPORTS length_PkinitSP80056AOtherInfo length_PkinitSuppPubInfo length_PKIXXmppAddr + length_PolicyConstraints length_PolicyInformation length_PolicyMapping length_PolicyMappings @@ -2069,8 +2174,11 @@ EXPORTS length_SignerIdentifier length_SignerInfo length_SignerInfos + length_SingleAttribute + length_SkipCerts length_SRVName length_StrengthOfFunction + length_SubjectDirectoryAttributes length_SubjectInfoAccessSyntax length_SubjectKeyIdentifier length_SubjectPublicKeyInfo @@ -2102,6 +2210,12 @@ EXPORTS length_VendorLoadErrorCode length_Version length_WrappedFirmwareKey + length_X520CommonName + length_X520LocalityName + length_X520name + length_X520OrganizationalUnitName + length_X520OrganizationName + length_X520StateOrProvinceName length_X690SampleChildInformation length_X690SampleDate length_X690SampleEmployeeNumber diff --git a/lib/asn1/main.c b/lib/asn1/main.c index 8078b1516..7acb62427 100644 --- a/lib/asn1/main.c +++ b/lib/asn1/main.c @@ -123,7 +123,8 @@ struct getargs args[] = { "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, NULL, 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", "C-HEADER-FILE" }, diff --git a/lib/asn1/oid_resolution.c b/lib/asn1/oid_resolution.c index b6716cd53..b58ba98a7 100644 --- a/lib/asn1/oid_resolution.c +++ b/lib/asn1/oid_resolution.c @@ -46,9 +46,7 @@ #include "pkcs9_asn1.h" #include "pkinit_asn1.h" #include "rfc2459_asn1.h" -#include "rfc4043_asn1.h" #include "rfc4108_asn1.h" -#include "tcg_asn1.h" struct sym_oid { @@ -73,9 +71,7 @@ static const struct sym_oid sym_oids[] = { #include "pkcs9_asn1_oids.x" #include "pkinit_asn1_oids.x" #include "rfc2459_asn1_oids.x" -#include "rfc4043_asn1_oids.x" #include "rfc4108_asn1_oids.x" -#include "tcg_asn1_oids.x" }; static size_t num_sym_oids = sizeof(sym_oids) / sizeof(sym_oids[0]); diff --git a/lib/asn1/pkcs12.asn1 b/lib/asn1/pkcs12.asn1 index 8b604c68d..61d3e2ca9 100644 --- a/lib/asn1/pkcs12.asn1 +++ b/lib/asn1/pkcs12.asn1 @@ -6,7 +6,7 @@ BEGIN IMPORTS ContentInfo FROM cms DigestInfo FROM rfc2459 - heim_any, heim_any_set FROM heim; + HEIM_ANY, HEIM_ANY_SET FROM heim; -- The PFX PDU @@ -50,14 +50,14 @@ PKCS12-AuthenticatedSafe ::= SEQUENCE OF ContentInfo PKCS12-Attribute ::= SEQUENCE { attrId OBJECT IDENTIFIER, - attrValues -- SET OF -- heim_any_set + attrValues -- SET OF -- HEIM_ANY_SET } PKCS12-Attributes ::= SET OF PKCS12-Attribute PKCS12-SafeBag ::= SEQUENCE { bagId OBJECT IDENTIFIER, - bagValue [0] heim_any, + bagValue [0] HEIM_ANY, bagAttributes PKCS12-Attributes OPTIONAL } @@ -65,7 +65,7 @@ PKCS12-SafeContents ::= SEQUENCE OF PKCS12-SafeBag PKCS12-CertBag ::= SEQUENCE { certType OBJECT IDENTIFIER, - certValue [0] heim_any + certValue [0] HEIM_ANY } PKCS12-PBEParams ::= SEQUENCE { diff --git a/lib/asn1/pkinit.asn1 b/lib/asn1/pkinit.asn1 index 45c29bf08..bc45210b8 100644 --- a/lib/asn1/pkinit.asn1 +++ b/lib/asn1/pkinit.asn1 @@ -5,7 +5,7 @@ PKINIT DEFINITIONS ::= BEGIN IMPORTS EncryptionKey, PrincipalName, Realm, KerberosTime, Checksum, Ticket FROM krb5 IssuerAndSerialNumber FROM cms SubjectPublicKeyInfo, AlgorithmIdentifier FROM rfc2459 - heim_any FROM heim; + HEIM_ANY FROM heim; id-pkinit OBJECT IDENTIFIER ::= { iso (1) org (3) dod (6) internet (1) security (5) @@ -96,11 +96,6 @@ AuthPack ::= SEQUENCE { TD-TRUSTED-CERTIFIERS ::= ExternalPrincipalIdentifiers TD-INVALID-CERTIFICATES ::= ExternalPrincipalIdentifiers -KRB5PrincipalName ::= SEQUENCE { - realm [0] Realm, - principalName [1] PrincipalName -} - AD-INITIAL-VERIFIED-CAS ::= SEQUENCE OF ExternalPrincipalIdentifier DHRepInfo ::= SEQUENCE { @@ -150,7 +145,7 @@ AuthPack-Win2k ::= SEQUENCE { TrustedCA-Win2k ::= CHOICE { - caName [1] heim_any, + caName [1] HEIM_ANY, issuerAndSerial [2] IssuerAndSerialNumber } @@ -178,8 +173,8 @@ ReplyKeyPack-Win2k ::= SEQUENCE { } PA-PK-AS-REP-BTMM ::= SEQUENCE { - dhSignedData [0] heim_any OPTIONAL, - encKeyPack [1] heim_any OPTIONAL + dhSignedData [0] HEIM_ANY OPTIONAL, + encKeyPack [1] HEIM_ANY OPTIONAL } diff --git a/lib/asn1/rfc2459.asn1 b/lib/asn1/rfc2459.asn1 index 2583d0a21..fcb03f2db 100644 --- a/lib/asn1/rfc2459.asn1 +++ b/lib/asn1/rfc2459.asn1 @@ -9,7 +9,13 @@ RFC2459 DEFINITIONS ::= BEGIN -IMPORTS heim_any FROM heim; +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), @@ -169,6 +175,10 @@ id-Userid OBJECT IDENTIFIER ::= 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 @@ -176,12 +186,12 @@ id-x509-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, - parameters heim_any OPTIONAL + parameters HEIM_ANY OPTIONAL } AttributeType ::= OBJECT IDENTIFIER -AttributeValue ::= heim_any +AttributeValue ::= HEIM_ANY DirectoryString ::= CHOICE { ia5String IA5String, @@ -204,7 +214,18 @@ AttributeTypeAndValue ::= SEQUENCE { value DirectoryString } -RelativeDistinguishedName ::= SET OF AttributeTypeAndValue +-- 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). +-- +RelativeDistinguishedName ::= SET OF AttributeTypeAndValue -- XXX SingleAttribute RDNSequence ::= SEQUENCE OF RelativeDistinguishedName @@ -231,10 +252,48 @@ SubjectPublicKeyInfo ::= SEQUENCE { subjectPublicKey BIT STRING } -Extension ::= SEQUENCE { - extnID OBJECT IDENTIFIER, - critical BOOLEAN OPTIONAL, -- DEFAULT FALSE XXX - extnValue OCTET 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 @@ -285,16 +344,8 @@ DHParameter ::= SEQUENCE { DHPublicKey ::= INTEGER -OtherName ::= SEQUENCE { - type-id OBJECT IDENTIFIER, - value [0] EXPLICIT heim_any -} - GeneralName ::= CHOICE { - otherName [0] IMPLICIT -- OtherName -- SEQUENCE { - type-id OBJECT IDENTIFIER, - value [0] EXPLICIT heim_any - }, + otherName [0] IMPLICIT OtherName, rfc822Name [1] IMPLICIT IA5String, dNSName [2] IMPLICIT IA5String, -- x400Address [3] IMPLICIT ORAddress,-- @@ -336,7 +387,7 @@ PolicyQualifierId ::= OBJECT IDENTIFIER -- ( id-qt-cps | id-qt-unotice ) PolicyQualifierInfo ::= SEQUENCE { policyQualifierId PolicyQualifierId, - qualifier heim_any -- ANY DEFINED BY policyQualifierId + qualifier HEIM_ANY -- ANY DEFINED BY policyQualifierId } PolicyQualifierInfos ::= SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo @@ -400,18 +451,18 @@ SubjectKeyIdentifier ::= KeyIdentifier id-x509-ce-basicConstraints OBJECT IDENTIFIER ::= { id-x509-ce 19 } BasicConstraints ::= SEQUENCE { - cA BOOLEAN OPTIONAL -- DEFAULT FALSE --, + cA BOOLEAN DEFAULT FALSE, pathLenConstraint INTEGER (0..4294967295) OPTIONAL } id-x509-ce-nameConstraints OBJECT IDENTIFIER ::= { id-x509-ce 30 } -BaseDistance ::= INTEGER -- (0..MAX) -- +BaseDistance ::= INTEGER (0..4294967295) GeneralSubtree ::= SEQUENCE { base GeneralName, - minimum [0] IMPLICIT -- BaseDistance -- INTEGER OPTIONAL -- DEFAULT 0 --, - maximum [1] IMPLICIT -- BaseDistance -- INTEGER OPTIONAL + minimum [0] IMPLICIT BaseDistance DEFAULT 0, + maximum [1] IMPLICIT BaseDistance OPTIONAL } GeneralSubtrees ::= SEQUENCE -- SIZE (1..MAX) -- OF GeneralSubtree @@ -462,9 +513,9 @@ DistributionPointName ::= CHOICE { } DistributionPoint ::= SEQUENCE { - distributionPoint [0] IMPLICIT heim_any -- DistributionPointName -- OPTIONAL, - reasons [1] IMPLICIT heim_any -- DistributionPointReasonFlags -- OPTIONAL, - cRLIssuer [2] IMPLICIT heim_any -- GeneralNames -- OPTIONAL + distributionPoint [0] IMPLICIT HEIM_ANY -- DistributionPointName -- OPTIONAL, + reasons [1] IMPLICIT HEIM_ANY -- DistributionPointReasonFlags -- OPTIONAL, + cRLIssuer [2] IMPLICIT HEIM_ANY -- GeneralNames -- OPTIONAL } CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint @@ -596,6 +647,36 @@ 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 } @@ -634,7 +715,6 @@ 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 { @@ -669,6 +749,350 @@ ProxyCertInfo ::= SEQUENCE { 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, + ekGenerationType [0] IMPLICIT EKGenerationType OPTIONAL, + ekGenerationLocation [1] IMPLICIT EKGenerationLocation OPTIONAL, + ekCertificateGenerationLocation [2] IMPLICIT EKCertificateGenerationLocation OPTIONAL, + -- These two are marked IMPLICIT, but... + ccInfo [3] CommonCriteriaMeasures OPTIONAL, + fipsLevel [4] FIPSLevel OPTIONAL, + iso9000Certified [5] IMPLICIT 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 +} + +-- Currently this crashes the ASN.1 compiler because it knows how to deal with +-- contents constraints that use ObjectClassFieldType references, but it +-- doesn't know how to deal with those as SEQUENCE/SET member types. +-- +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 +} +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 +} + +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 } diff --git a/lib/asn1/rfc4043.asn1 b/lib/asn1/rfc4043.asn1 deleted file mode 100644 index 5e85c59cc..000000000 --- a/lib/asn1/rfc4043.asn1 +++ /dev/null @@ -1,30 +0,0 @@ -PKIXpermanentidentifier88 {iso(1) identified-organization(3) dod(6) - internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) - id-mod-perm-id-88(28) } - -DEFINITIONS EXPLICIT TAGS ::= - - BEGIN - - -- EXPORTS ALL -- - -- IMPORTS id-pkix FROM rfc2459; but asn1_compile doesn't handle this - - - -- Permanent identifier Object Identifier and Syntax - - id-on OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) - dod(6) internet(1) security(5) mechanisms(5) pkix(7) 8 } - - id-on-permanentIdentifier OBJECT IDENTIFIER ::= { id-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 -} - -END diff --git a/lib/asn1/rfc4108.asn1 b/lib/asn1/rfc4108.asn1 index 7f3e16717..34f93966a 100644 --- a/lib/asn1/rfc4108.asn1 +++ b/lib/asn1/rfc4108.asn1 @@ -5,6 +5,9 @@ CMSFirmwareWrapper 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) @@ -195,8 +198,10 @@ id-on-hardwareModuleName OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) on(8) 4 } -HardwareModuleName ::= SEQUENCE { - hwType OBJECT IDENTIFIER, - hwSerialNum OCTET STRING } +-- 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/lib/asn1/symbol.h b/lib/asn1/symbol.h index f8a5627b9..b88386223 100644 --- a/lib/asn1/symbol.h +++ b/lib/asn1/symbol.h @@ -68,6 +68,8 @@ enum typetype { typedef enum typetype Typetype; struct type; +struct value; +struct typereference; struct value { enum { booleanvalue, @@ -82,6 +84,7 @@ struct value { char *stringvalue; struct objid *objectidentifiervalue; } u; + struct symbol *s; }; struct member { @@ -117,15 +120,82 @@ struct range { int64_t max; }; -enum ctype { CT_CONTENTS, CT_USER } ; +enum ctype { CT_CONTENTS, CT_USER, CT_TABLE_CONSTRAINT } ; 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; @@ -134,12 +204,18 @@ struct type { 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; } u; }; @@ -153,13 +229,17 @@ struct objid { struct symbol { char *name; char *gen_name; - enum { SUndefined, SValue, Stype } stype; + 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_declaration:1; unsigned int emitted_definition:1; unsigned int emitted_tag_enums:1; + unsigned int emitted_template:1; }; typedef struct symbol Symbol; diff --git a/lib/asn1/tcg.asn1 b/lib/asn1/tcg.asn1 index b0ed98d69..14129b06a 100644 --- a/lib/asn1/tcg.asn1 +++ b/lib/asn1/tcg.asn1 @@ -1,8 +1,5 @@ TCG DEFINITIONS ::= BEGIN -IMPORTS AlgorithmIdentifier FROM rfc2459; - - -- BEGIN Heimdal commentary -- -- Copy-pasted from section 4 of @@ -10,12 +7,17 @@ IMPORTS AlgorithmIdentifier FROM rfc2459; -- 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) -- @@ -37,123 +39,4 @@ IMPORTS AlgorithmIdentifier FROM rfc2459; -- -- END Heimdal commentary (though some minor Heimdal commentary appears below) ---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 Key Purposes 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} -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 { - internal (0), - injected (1), - internalRevocable(2), - 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 { - basic (0), - medium (1), - 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 ATTRIBUTE ::= {WITH SYNTAX TPMSpecification ID tcg-at-tpmSpecification } -TPMSpecification ::= SEQUENCE { - family UTF8String, -- (SIZE (1..STRMAX)) - level INTEGER, - revision INTEGER, - ... -} - ---manufacturer implementation model and version attributes --- TPMManufacturer ATTRIBUTE ::= {WITH SYNTAX UTF8String (SIZE (1..STRMAX)) ID tcg-at-tpmManufacturer } --- TPMModel ATTRIBUTE ::= {WITH SYNTAX UTF8String (SIZE (1..STRMAX)) ID tcg-at-tpmModel } --- TPMVersion ATTRIBUTE ::= {WITH SYNTAX UTF8String (SIZE (1..STRMAX)) ID tcg-at-tpmVersion } - ---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 ATTRIBUTE ::= {WITH SYNTAX TPMSecurityAssertions ID tcg—at-tpmSecurityAssertions} -TPMSecurityAssertions ::= SEQUENCE { - version TPMVersion DEFAULT 0, -- v1 - fieldUpgradable BOOLEAN DEFAULT FALSE, - ekGenerationType [0] IMPLICIT EKGenerationType OPTIONAL, - ekGenerationLocation [1] IMPLICIT EKGenerationLocation OPTIONAL, - ekCertificateGenerationLocation [2] IMPLICIT EKCertificateGenerationLocation OPTIONAL, - ccInfo [3] IMPLICIT CommonCriteriaMeasures OPTIONAL, - fipsLevel [4] IMPLICIT FIPSLevel OPTIONAL, - iso9000Certified [5] IMPLICIT BOOLEAN DEFAULT FALSE, - iso9000Uri IA5String OPTIONAL, -- (SIZE (1..URIMAX)) - ... -} - END diff --git a/lib/asn1/template.c b/lib/asn1/template.c index 84f4898d0..93225cda0 100644 --- a/lib/asn1/template.c +++ b/lib/asn1/template.c @@ -166,7 +166,8 @@ is_tagged(const struct asn1_template *t) * 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) + if (f->encode == (asn1_type_encode)encode_heim_any || + f->encode == (asn1_type_encode)encode_HEIM_ANY) return 0; abort(); /* XXX */ } @@ -197,11 +198,507 @@ inner_type_taglen(const struct asn1_template *t) * 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) + 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) + 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_ 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__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__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) + return 0; /* Do nothing, silently (probably 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[] = { + * { 0, 0, ((void*)17) }, // HEADER ENTRY, here 17 objects + * // then two entries per object: + * { A1_OP_OPENTYPE_ID, 0, (const void*)&asn1_oid_oidName }, + * { A1_OP_OPENTYPE, sizeof(SomeType), (const void*)&asn1_SomeType }, + * ... + * }; + * + * `i' will be a logical object offset, so i*2+1 will be the index of the + * A1_OP_OPENTYPE_ID entry for the current object, and i*2+2 will be 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[1 + mid * 2].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + return 0; + if (typeid_is_int) + c = typeid_int_cmp(vp, (intptr_t)tos[1 + mid * 2].ptr, + ttypeid_univ); + else if (typeid_is_oid) + c = der_heim_oid_cmp(vp, tos[1 + mid * 2].ptr); + if (c < 0) { + if (mid) + right = mid - 1; + else + break; + } 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[1 + i*2].tt & A1_OP_MASK) != A1_OP_OPENTYPE_ID) + return 0; + if (typeid_is_int && + typeid_int_cmp(DPO(data, ttypeid->offset), + (intptr_t)tos[1 + i*2].ptr, + ttypeid_univ)) + continue; + if (typeid_is_oid && + der_heim_oid_cmp(DPO(data, ttypeid->offset), tos[1 + i*2].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*2 + 2]; + + /* 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 ((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) { + 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(len, 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[i]->data, + d[i]->length, val[i], &sz); + if (ret) { + free(val[i]); + val[i] = NULL; + } + } + if (ret == ENOMEM) { + for (i = 0; i < len; i++) { + _asn1_free(tactual_type->ptr, val[i]); + free(val[i]); + } + free(val); + val = 0; + *lenp = 0; + } + if (ret != ENOMEM) + ret = 0; /* See above */ + *dp = val; + return ret; } } @@ -209,6 +706,7 @@ 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; @@ -224,6 +722,19 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, 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_NAME: break; case A1_OP_DEFVAL: tdefval = t; break; @@ -293,7 +804,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, } break; } - return ret; + return ret; /* Error decoding required field */ } p += newsize; len -= newsize; @@ -301,8 +812,8 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, } case A1_OP_TAG: { Der_type dertype; - size_t newsize; - size_t datalen, l; + size_t newsize = 0; + size_t datalen, l = 0; void *olddata = data; int is_indefinite = 0; int subflags = flags; @@ -360,7 +871,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, data = olddata; break; } - return ret; + return ret; /* Error decoding required field */ } p += l; len -= l; @@ -555,11 +1066,32 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, size_t datalen; unsigned int i; - /* provide a saner value as default, we should have a NO element value */ + /* + * Provide a saner value as default, we should have a NO element value. + * + * XXX We do have an element value for the ellipsis case: 0. All + * CHOICE discriminant enums start off at 1. + */ *element = 1; for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) { - /* should match first tag instead, store it in choice.tt */ + /* + * 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) { @@ -618,9 +1150,182 @@ _asn1_decode(const struct asn1_template *t, unsigned flags, 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)); + + lenp = DPO(data, topentype->offset); + if (*lenp == len && os[0]->length && os[1]->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[1 + (element-1)*2].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[1 + (element-1)*2].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)*2 + 2]; + + 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; @@ -629,6 +1334,17 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const 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: case A1_OP_TYPE_EXTERN: { @@ -690,7 +1406,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const } case A1_OP_TAG: { const void *olddata = data; - size_t l, datalen; + size_t l, datalen = 0; int replace_tag = 0; /* @@ -759,10 +1475,10 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const if (replace_tag) { unsigned char *pfree, *psave = p; Der_class found_class; - Der_type found_type; + Der_type found_type = 0; unsigned int found_tag; size_t lensave = len; - size_t oldtaglen; + 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 */ @@ -1016,9 +1732,174 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const 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*)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 (!typeid_is_int && !typeid_is_oid) + 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)); + + lenp = DPOC(data, topentype->offset); + if (*lenp == len && os[0]->length && os[1]->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[1 + (element - 1)*2].ptr); + sz -= _asn1_length_open_type_id(ttypeid, &no_oid); + } + + tactual_type = &tos[(element-1)*2 + 2]; + + /* 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; @@ -1026,6 +1907,15 @@ _asn1_length(const struct asn1_template *t, const void *data) 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: case A1_OP_TYPE_EXTERN: { @@ -1219,6 +2109,57 @@ _asn1_length(const struct asn1_template *t, const void *data) 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[2*(*elementp - 1) + 2].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) { @@ -1231,6 +2172,11 @@ _asn1_free(const struct asn1_template *t, void *data) 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: case A1_OP_TYPE_EXTERN: { @@ -1325,6 +2271,95 @@ _asn1_free(const struct asn1_template *t, void *data) } } +/* 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[2*(*efromp - 1) + 2]; + + 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; (*lentop)++, 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]); + } + + for (i = 0; ret && i < len; i++) { + if (valto[i]) { + _asn1_free(tactual_type->ptr, valto[i]); + free(valto[i]); + } + } + if (ret) + free(valto); + else + *dtop = valto; + return ret; +} + int _asn1_copy(const struct asn1_template *t, const void *from, void *to) { @@ -1342,6 +2377,11 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to) 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: case A1_OP_TYPE_EXTERN: { diff --git a/lib/asn1/test.asn1 b/lib/asn1/test.asn1 index 3696371c2..1fbd461e7 100644 --- a/lib/asn1/test.asn1 +++ b/lib/asn1/test.asn1 @@ -4,7 +4,7 @@ TEST DEFINITIONS ::= BEGIN -IMPORTS heim_any FROM heim; +IMPORTS HEIM_ANY FROM heim; -- Check that we handle out of order definitions. -- The compiler should emit the definition of TESTOutOfOrderBar before that of @@ -103,7 +103,7 @@ TESTAllocInner ::= SEQUENCE { TESTAlloc ::= SEQUENCE { tagless TESTAllocInner OPTIONAL, three [1] INTEGER (-2147483648..2147483647), - tagless2 heim_any OPTIONAL + tagless2 HEIM_ANY OPTIONAL } TESTOptional ::= SEQUENCE { @@ -117,22 +117,22 @@ TESTENCODEDBY ::= OCTET STRING ( ENCODED BY { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } ) -TESTDer OBJECT IDENTIFIER ::= { +testDer OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) asn(1) ber-derived(2) distinguished-encoding(1) } -TESTCONTAININGENCODEDBY ::= OCTET STRING ( CONTAINING INTEGER ENCODED BY +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 +testContainingEncodedBy2 ::= OCTET STRING ( + CONTAINING INTEGER ENCODED BY testDer ) -TESTValue1 INTEGER ::= 1 +testValue1 INTEGER ::= 1 -TESTUSERCONSTRAINED ::= OCTET STRING (CONSTRAINED BY { -- meh -- }) +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 }) @@ -250,4 +250,40 @@ TESTLargeBitString ::= BIT STRING { 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 +} + END diff --git a/lib/gssapi/mech/gssapi.asn1 b/lib/gssapi/mech/gssapi.asn1 index 1ba7b4063..96ca6bd1d 100644 --- a/lib/gssapi/mech/gssapi.asn1 +++ b/lib/gssapi/mech/gssapi.asn1 @@ -2,11 +2,11 @@ GSS-API DEFINITIONS ::= BEGIN -IMPORTS heim_any_set FROM heim; +IMPORTS HEIM_ANY_SET FROM heim; GSSAPIContextToken ::= [APPLICATION 0] IMPLICIT SEQUENCE { thisMech OBJECT IDENTIFIER, - innerContextToken heim_any_set + innerContextToken HEIM_ANY_SET } -END \ No newline at end of file +END diff --git a/lib/hdb/Makefile.am b/lib/hdb/Makefile.am index 9443532f5..342aaffbe 100644 --- a/lib/hdb/Makefile.am +++ b/lib/hdb/Makefile.am @@ -38,9 +38,9 @@ gen_files_hdb = \ asn1_HDB_EntryOrAlias.x \ asn1_KeyRotation.x \ asn1_KeyRotationFlags.x \ - asn1_hdb_entry.x \ - asn1_hdb_entry_alias.x \ - asn1_hdb_keyset.x \ + asn1_HDB_entry.x \ + asn1_HDB_entry_alias.x \ + asn1_HDB_keyset.x \ asn1_Keys.x CLEANFILES = $(BUILT_SOURCES) $(gen_files_hdb) \ diff --git a/lib/hdb/common.c b/lib/hdb/common.c index cd3a88946..d211fa2b9 100644 --- a/lib/hdb/common.c +++ b/lib/hdb/common.c @@ -65,7 +65,7 @@ hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value) size_t len = 0; int ret; - ASN1_MALLOC_ENCODE(hdb_entry, value->data, value->length, ent, &len, ret); + ASN1_MALLOC_ENCODE(HDB_entry, value->data, value->length, ent, &len, ret); if (ret == 0 && value->length != len) krb5_abortx(context, "internal asn.1 encoder error"); return ret; @@ -74,7 +74,7 @@ hdb_entry2value(krb5_context context, const hdb_entry *ent, krb5_data *value) int hdb_value2entry(krb5_context context, krb5_data *value, hdb_entry *ent) { - return decode_hdb_entry(value->data, value->length, ent, NULL); + return decode_HDB_entry(value->data, value->length, ent, NULL); } int @@ -85,7 +85,7 @@ hdb_entry_alias2value(krb5_context context, size_t len = 0; int ret; - ASN1_MALLOC_ENCODE(hdb_entry_alias, value->data, value->length, + ASN1_MALLOC_ENCODE(HDB_entry_alias, value->data, value->length, alias, &len, ret); if (ret == 0 && value->length != len) krb5_abortx(context, "internal asn.1 encoder error"); @@ -96,7 +96,7 @@ int hdb_value2entry_alias(krb5_context context, krb5_data *value, hdb_entry_alias *ent) { - return decode_hdb_entry_alias(value->data, value->length, ent, NULL); + return decode_HDB_entry_alias(value->data, value->length, ent, NULL); } /* @@ -205,7 +205,7 @@ fetch_entry_or_alias(krb5_context context, (flags & (HDB_F_CANON|HDB_F_GET_ANY)) == 0) { /* `principal' was alias but canon not req'd */ - free_hdb_entry(&entry->entry); + free_HDB_entry(&entry->entry); ret = HDB_ERR_NOENTRY; } @@ -300,7 +300,7 @@ hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key) code = hdb_entry_get_aliases(&oldentry, &aliases); if (code || aliases == NULL) { - free_hdb_entry(&oldentry); + free_HDB_entry(&oldentry); return code; } for (i = 0; i < aliases->aliases.len; i++) { @@ -312,11 +312,11 @@ hdb_remove_aliases(krb5_context context, HDB *db, krb5_data *key) krb5_data_free(&akey); } if (code) { - free_hdb_entry(&oldentry); + free_HDB_entry(&oldentry); return code; } } - free_hdb_entry(&oldentry); + free_HDB_entry(&oldentry); return 0; } @@ -790,7 +790,7 @@ derive_keys_for_kr(krb5_context context, if (ret == 0) ret = hdb_install_keyset(context, &h->entry, is_current_keyset, &dks); - free_hdb_keyset(&dks); + free_HDB_keyset(&dks); return ret; } @@ -1468,3 +1468,111 @@ hdb_fetch_kvno(krb5_context context, krb5_set_error_message(context, ret, "no such entry found in hdb"); return ret; } + +size_t ASN1CALL +length_hdb_keyset(HDB_keyset *data) +{ + return length_HDB_keyset(data); +} + +size_t ASN1CALL +length_hdb_entry(HDB_entry *data) +{ + return length_HDB_entry(data); +} + +size_t ASN1CALL +length_hdb_entry_alias(HDB_entry_alias *data) +{ + return length_HDB_entry_alias(data); +} + +void ASN1CALL +free_hdb_keyset(HDB_keyset *data) +{ + free_HDB_keyset(data); +} + +void ASN1CALL +free_hdb_entry(HDB_entry *data) +{ + free_HDB_entry(data); +} + +void ASN1CALL +free_hdb_entry_alias(HDB_entry_alias *data) +{ + free_HDB_entry_alias(data); +} + +size_t ASN1CALL +copy_hdb_keyset(const HDB_keyset *from, HDB_keyset *to) +{ + return copy_HDB_keyset(from, to); +} + +size_t ASN1CALL +copy_hdb_entry(const HDB_entry *from, HDB_entry *to) +{ + return copy_HDB_entry(from, to); +} + +size_t ASN1CALL +copy_hdb_entry_alias(const HDB_entry_alias *from, HDB_entry_alias *to) +{ + return copy_HDB_entry_alias(from, to); +} + +int ASN1CALL +decode_hdb_keyset(const unsigned char *p, + size_t len, + HDB_keyset *data, + size_t *size) +{ + return decode_HDB_keyset(p, len, data, size); +} + +int ASN1CALL +decode_hdb_entry(const unsigned char *p, + size_t len, + HDB_entry *data, + size_t *size) +{ + return decode_HDB_entry(p, len, data, size); +} + +int ASN1CALL +decode_hdb_entry_alias(const unsigned char *p, + size_t len, + HDB_entry_alias *data, + size_t *size) +{ + return decode_HDB_entry_alias(p, len, data, size); +} + +int ASN1CALL +encode_hdb_keyset(unsigned char *p, + size_t len, + const HDB_keyset *data, + size_t *size) +{ + return encode_HDB_keyset(p, len, data, size); +} + +int ASN1CALL +encode_hdb_entry(unsigned char *p, + size_t len, + const HDB_entry *data, + size_t *size) +{ + return encode_HDB_entry(p, len, data, size); +} + +int ASN1CALL +encode_hdb_entry_alias(unsigned char *p, + size_t len, + const HDB_entry_alias *data, + size_t *size) +{ + return encode_HDB_entry_alias(p, len, data, size); +} diff --git a/lib/hdb/hdb-keytab.c b/lib/hdb/hdb-keytab.c index b1cfa0e66..345dc18b7 100644 --- a/lib/hdb/hdb-keytab.c +++ b/lib/hdb/hdb-keytab.c @@ -163,7 +163,7 @@ hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, out: if (ret) { - free_hdb_entry(&entry->entry); + free_HDB_entry(&entry->entry); memset(&entry->entry, 0, sizeof(entry->entry)); } krb5_kt_free_entry(context, &ktentry); diff --git a/lib/hdb/hdb-mitdb.c b/lib/hdb/hdb-mitdb.c index 5bb439111..1ae013157 100644 --- a/lib/hdb/hdb-mitdb.c +++ b/lib/hdb/hdb-mitdb.c @@ -662,7 +662,7 @@ out: if (ret == HEIM_ERR_EOF) /* Better error code than "end of file" */ ret = HEIM_ERR_BAD_HDBENT_ENCODING; - free_hdb_entry(entry); + free_HDB_entry(entry); free_Key(&k); return ret; } diff --git a/lib/hdb/hdb.asn1 b/lib/hdb/hdb.asn1 index c6a8cbe4b..682aa6e7b 100644 --- a/lib/hdb/hdb.asn1 +++ b/lib/hdb/hdb.asn1 @@ -99,14 +99,14 @@ HDB-Ext-Aliases ::= SEQUENCE { Keys ::= SEQUENCE OF Key -hdb_keyset ::= SEQUENCE { +HDB_keyset ::= SEQUENCE { kvno[0] INTEGER (0..4294967295), keys[1] Keys, set-time[2] KerberosTime OPTIONAL, -- time this keyset was created/set ... } -HDB-Ext-KeySet ::= SEQUENCE OF hdb_keyset +HDB-Ext-KeySet ::= SEQUENCE OF HDB_keyset -- -- We need a function of current (or given, but it will always be current) time @@ -218,7 +218,7 @@ HDB-extensions ::= SEQUENCE OF HDB-extension -- Just for convenience, for encoding this as TL data in lib/kadm5 HDB-EncTypeList ::= SEQUENCE OF INTEGER (0..4294967295) -hdb_entry ::= SEQUENCE { +HDB_entry ::= SEQUENCE { principal[0] Principal OPTIONAL, -- this is optional only -- for compatibility with libkrb5 kvno[1] INTEGER (0..4294967295), @@ -236,13 +236,13 @@ hdb_entry ::= SEQUENCE { extensions[13] HDB-extensions OPTIONAL } -hdb_entry_alias ::= [APPLICATION 0] SEQUENCE { +HDB_entry_alias ::= [APPLICATION 0] SEQUENCE { principal[0] Principal OPTIONAL } HDB-EntryOrAlias ::= CHOICE { - entry hdb_entry, - alias hdb_entry_alias + entry HDB_entry, + alias HDB_entry_alias } END diff --git a/lib/hdb/hdb.c b/lib/hdb/hdb.c index e89c64aa1..0f8cef23f 100644 --- a/lib/hdb/hdb.c +++ b/lib/hdb/hdb.c @@ -406,7 +406,7 @@ hdb_free_entry(krb5_context context, hdb_entry_ex *ent) memset (k->key.keyvalue.data, 0, k->key.keyvalue.length); } - free_hdb_entry(&ent->entry); + free_HDB_entry(&ent->entry); } krb5_error_code diff --git a/lib/hdb/hdb.h b/lib/hdb/hdb.h index 1d9b98ce1..80c3020e8 100644 --- a/lib/hdb/hdb.h +++ b/lib/hdb/hdb.h @@ -44,6 +44,9 @@ #include #include +typedef HDB_keyset hdb_keyset; +typedef HDB_entry hdb_entry; +typedef HDB_entry_alias hdb_entry_alias; struct hdb_dbinfo; diff --git a/lib/hdb/keys.c b/lib/hdb/keys.c index d5d814dae..ae0b067f7 100644 --- a/lib/hdb/keys.c +++ b/lib/hdb/keys.c @@ -322,8 +322,8 @@ hdb_add_history_keyset(krb5_context context, for (i = 0; i < hist_keys->len; i++) { if (hist_keys->val[i].kvno == ks->kvno) { /* Replace existing */ - free_hdb_keyset(&hist_keys->val[i]); - ret = copy_hdb_keyset(ks, &hist_keys->val[i]); + free_HDB_keyset(&hist_keys->val[i]); + ret = copy_HDB_keyset(ks, &hist_keys->val[i]); break; } } @@ -422,7 +422,7 @@ hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key } out: - free_hdb_keyset(&keyset); + free_HDB_keyset(&keyset); free_HDB_extension(&ext); return ret; } @@ -462,7 +462,7 @@ hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry) for (i = 0; i < hist_keys->len; i++) { if (hist_keys->val[i].kvno == new_kvno) { found = 1; - ret = copy_hdb_keyset(&hist_keys->val[i], &keyset); + ret = copy_HDB_keyset(&hist_keys->val[i], &keyset); if (ret) goto out; ret = remove_HDB_Ext_KeySet(hist_keys, i); @@ -485,7 +485,7 @@ hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry) memset(&keyset.keys, 0, sizeof (keyset.keys)); out: - free_hdb_keyset(&keyset); + free_HDB_keyset(&keyset); return ret; } diff --git a/lib/hdb/libhdb-exports.def b/lib/hdb/libhdb-exports.def index 8645a2631..a124f93f6 100644 --- a/lib/hdb/libhdb-exports.def +++ b/lib/hdb/libhdb-exports.def @@ -1,5 +1,5 @@ EXPORTS - encode_hdb_keyset + encode_HDB_keyset _hdb_fetch_kvno _hdb_remove _hdb_store @@ -90,7 +90,7 @@ EXPORTS hdb_value2entry hdb_value2entry_alias hdb_write_master_key - length_hdb_keyset + length_HDB_keyset initialize_hdb_error_table_r hdb_kt_ops @@ -108,7 +108,9 @@ EXPORTS copy_Event copy_HDB_EncTypeList copy_hdb_entry + copy_HDB_entry copy_hdb_entry_alias + copy_HDB_entry_alias copy_HDB_EntryOrAlias copy_HDB_extensions copy_HDB_Ext_KeyRotation @@ -117,7 +119,9 @@ EXPORTS copy_Salt decode_HDB_EncTypeList decode_hdb_entry + decode_HDB_entry decode_hdb_entry_alias + decode_HDB_entry_alias decode_HDB_EntryOrAlias decode_HDB_Ext_Aliases decode_HDB_extension @@ -127,18 +131,23 @@ EXPORTS decode_Keys encode_HDB_EncTypeList encode_hdb_entry + encode_HDB_entry encode_hdb_entry_alias + encode_HDB_entry_alias encode_HDB_EntryOrAlias encode_HDB_Ext_Aliases encode_HDB_extension encode_HDB_Ext_KeyRotation encode_HDB_Ext_PKINIT_acl + encode_hdb_keyset encode_Key encode_Keys free_Event free_HDB_EncTypeList free_hdb_entry + free_HDB_entry free_hdb_entry_alias + free_HDB_entry_alias free_HDB_EntryOrAlias free_HDB_Ext_Aliases free_HDB_extension @@ -147,6 +156,7 @@ EXPORTS free_HDB_Ext_KeySet free_HDB_Ext_PKINIT_acl free_hdb_keyset + free_HDB_keyset free_Key free_Keys free_Salt @@ -156,12 +166,15 @@ EXPORTS KeyRotationFlags2int length_HDB_EncTypeList length_hdb_entry + length_HDB_entry length_hdb_entry_alias + length_HDB_entry_alias length_HDB_EntryOrAlias length_HDB_Ext_Aliases length_HDB_extension length_HDB_Ext_KeyRotation length_HDB_Ext_PKINIT_acl + length_hdb_keyset length_Key length_Keys remove_HDB_Ext_KeyRotation diff --git a/lib/hdb/test_concurrency.c b/lib/hdb/test_concurrency.c index 644f6e6ef..9c95e6390 100644 --- a/lib/hdb/test_concurrency.c +++ b/lib/hdb/test_concurrency.c @@ -101,7 +101,7 @@ threaded_reader(void *d) //(void) unlink(s->fname); krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name); } - free_hdb_entry(&entr.entry); + free_HDB_entry(&entr.entry); /* Tell the writer to go ahead and write */ printf("Reader thread iterated one entry; telling writer to write more\n"); @@ -124,7 +124,7 @@ threaded_reader(void *d) "Could not iterate while writing to HDB %s", s->hdb_name); } printf("Reader thread iterated another entry\n"); - free_hdb_entry(&entr.entry); + free_HDB_entry(&entr.entry); if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) { //(void) unlink(s->fname); krb5_warn(context, ret, @@ -188,7 +188,7 @@ forked_reader(struct tsync *s) krb5_err(context, 1, ret, "Could not iterate HDB %s", s->hdb_name); } printf("Reader process iterated one entry\n"); - free_hdb_entry(&entr.entry); + free_HDB_entry(&entr.entry); /* Tell the writer to go ahead and write */ printf("Reader process iterated one entry; telling writer to write more\n"); @@ -213,7 +213,7 @@ forked_reader(struct tsync *s) krb5_err(context, 1, ret, "Could not iterate while writing to HDB %s", s->hdb_name); } - free_hdb_entry(&entr.entry); + free_HDB_entry(&entr.entry); printf("Reader process iterated another entry\n"); if ((ret = dbr->hdb_nextkey(context, dbr, 0, &entr)) == 0) { //(void) unlink(s->fname); @@ -387,14 +387,14 @@ test_hdb_concurrency(char *name, const char *ext, int threaded) krb5_err(context, 1, ret, "Could not store entry for \"foo\" in HDB %s", name); } - free_hdb_entry(&entw.entry); + free_HDB_entry(&entw.entry); if ((ret = make_entry(context, &entw, "bar")) || (ret = dbw->hdb_store(context, dbw, 0, &entw))) { (void) unlink(fname_ext); krb5_err(context, 1, ret, "Could not store entry for \"foo\" in HDB %s", name); } - free_hdb_entry(&entw.entry); + free_HDB_entry(&entw.entry); /* Tell the reader to start reading */ readers_turn(&ts, child, threaded); @@ -407,7 +407,7 @@ test_hdb_concurrency(char *name, const char *ext, int threaded) "Could not store entry for \"foobar\" in HDB %s " "while iterating it", name); } - free_hdb_entry(&entw.entry); + free_HDB_entry(&entw.entry); /* Tell the reader to go again */ readers_turn(&ts, child, threaded); diff --git a/lib/hdb/test_dbinfo.c b/lib/hdb/test_dbinfo.c index 7119d762e..195fd4151 100644 --- a/lib/hdb/test_dbinfo.c +++ b/lib/hdb/test_dbinfo.c @@ -68,7 +68,7 @@ check_HDB_EntryOrAlias(krb5_context context) NULL); if (ret) krb5_err(context, 1, ret, "krb5_make_principal"); - ASN1_MALLOC_ENCODE(hdb_entry_alias, v.data, v.length, &alias, &len, ret); + ASN1_MALLOC_ENCODE(HDB_entry_alias, v.data, v.length, &alias, &len, ret); if (ret) krb5_err(context, 1, ret, "encode_HDB_EntryOrAlias"); if (v.length != len) @@ -79,7 +79,7 @@ check_HDB_EntryOrAlias(krb5_context context) if (v.length != len) abort(); free_HDB_EntryOrAlias(&eoa); - free_hdb_entry_alias(&alias); + free_HDB_entry_alias(&alias); krb5_data_free(&v); ret = krb5_make_principal(context, &entry.principal, "KTH.SE", "foo", @@ -88,7 +88,7 @@ check_HDB_EntryOrAlias(krb5_context context) krb5_err(context, 1, ret, "krb5_make_principal"); entry.kvno = 5; entry.flags.initial = 1; - ASN1_MALLOC_ENCODE(hdb_entry, v.data, v.length, &entry, &len, ret); + ASN1_MALLOC_ENCODE(HDB_entry, v.data, v.length, &entry, &len, ret); if (ret) krb5_err(context, 1, ret, "encode_HDB_EntryOrAlias"); if (v.length != len) @@ -99,7 +99,7 @@ check_HDB_EntryOrAlias(krb5_context context) if (v.length != len) abort(); free_HDB_EntryOrAlias(&eoa); - free_hdb_entry(&entry); + free_HDB_entry(&entry); krb5_data_free(&v); } diff --git a/lib/hdb/test_hdbkeys.c b/lib/hdb/test_hdbkeys.c index 7cf4629b6..d6bc31d4c 100644 --- a/lib/hdb/test_hdbkeys.c +++ b/lib/hdb/test_hdbkeys.c @@ -104,7 +104,7 @@ main(int argc, char **argv) krb5_free_principal (context, principal); - ASN1_MALLOC_ENCODE(hdb_keyset, data, length, &keyset, &len, ret); + ASN1_MALLOC_ENCODE(HDB_keyset, data, length, &keyset, &len, ret); if (ret) krb5_errx(context, 1, "encode keyset"); if (len != length) diff --git a/lib/hdb/version-script.map b/lib/hdb/version-script.map index 2de270bfe..0846f7337 100644 --- a/lib/hdb/version-script.map +++ b/lib/hdb/version-script.map @@ -92,6 +92,7 @@ HEIMDAL_HDB_1.0 { hdb_value2entry_alias; hdb_write_master_key; length_hdb_keyset; + length_HDB_keyset; hdb_interface_version; initialize_hdb_error_table_r; @@ -113,6 +114,8 @@ HEIMDAL_HDB_1.0 { copy_HDB_EncTypeList; copy_hdb_entry; copy_hdb_entry_alias; + copy_HDB_entry; + copy_HDB_entry_alias; copy_HDB_EntryOrAlias; copy_HDB_extensions; copy_HDB_Ext_KeyRotation; @@ -122,6 +125,8 @@ HEIMDAL_HDB_1.0 { decode_HDB_EncTypeList; decode_hdb_entry; decode_hdb_entry_alias; + decode_HDB_entry; + decode_HDB_entry_alias; decode_HDB_EntryOrAlias; decode_HDB_Ext_Aliases; decode_HDB_extension; @@ -132,18 +137,23 @@ HEIMDAL_HDB_1.0 { encode_HDB_EncTypeList; encode_hdb_entry; encode_hdb_entry_alias; + encode_HDB_entry; + encode_HDB_entry_alias; encode_HDB_EntryOrAlias; encode_HDB_Ext_Aliases; encode_HDB_extension; encode_HDB_Ext_KeyRotation; encode_HDB_Ext_PKINIT_acl; encode_hdb_keyset; + encode_HDB_keyset; encode_Key; encode_Keys; free_Event; free_HDB_EncTypeList; free_hdb_entry; free_hdb_entry_alias; + free_HDB_entry; + free_HDB_entry_alias; free_HDB_EntryOrAlias; free_HDB_Ext_Aliases; free_HDB_extension; @@ -152,6 +162,7 @@ HEIMDAL_HDB_1.0 { free_HDB_Ext_KeySet; free_HDB_Ext_PKINIT_acl; free_hdb_keyset; + free_HDB_keyset; free_Key; free_Keys; free_Salt; @@ -162,6 +173,8 @@ HEIMDAL_HDB_1.0 { length_HDB_EncTypeList; length_hdb_entry; length_hdb_entry_alias; + length_HDB_entry; + length_HDB_entry_alias; length_HDB_EntryOrAlias; length_HDB_Ext_Aliases; length_HDB_extension; diff --git a/lib/hx509/ca.c b/lib/hx509/ca.c index e93366fe4..75c273c01 100644 --- a/lib/hx509/ca.c +++ b/lib/hx509/ca.c @@ -1284,7 +1284,7 @@ hx509_ca_tbs_add_san_permanentIdentifier(hx509_context context, _hx509_abort("internal ASN.1 encoder error"); ret = hx509_ca_tbs_add_san_otherName(context, tbs, - &asn1_oid_id_on_permanentIdentifier, + &asn1_oid_id_pkix_on_permanentIdentifier, &os); free(os.data); return ret; @@ -1595,16 +1595,7 @@ add_extension(hx509_context context, memset(&ext, 0, sizeof(ext)); - if (critical_flag) { - ext.critical = malloc(sizeof(*ext.critical)); - if (ext.critical == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "Out of memory"); - goto out; - } - *ext.critical = TRUE; - } - + ext.critical = critical_flag; ret = der_copy_oid(oid, &ext.extnID); if (ret) { hx509_set_error_string(context, 0, ret, "Out of memory"); @@ -1975,13 +1966,12 @@ ca_sign(hx509_context context, /* Add BasicConstraints */ { BasicConstraints bc; - int aCA = 1; unsigned int path; memset(&bc, 0, sizeof(bc)); if (tbs->flags.ca) { - bc.cA = &aCA; + bc.cA = 1; if (tbs->pathLenConstraint >= 0) { path = tbs->pathLenConstraint; bc.pathLenConstraint = &path; diff --git a/lib/hx509/cert.c b/lib/hx509/cert.c index 355da4014..3fc30fcc8 100644 --- a/lib/hx509/cert.c +++ b/lib/hx509/cert.c @@ -1060,14 +1060,14 @@ check_basic_constraints(hx509_context context, const Certificate *cert, return ret; switch(type) { case PROXY_CERT: - if (bc.cA != NULL && *bc.cA) + if (bc.cA) ret = HX509_PARENT_IS_CA; break; case EE_CERT: ret = 0; break; case CA_CERT: - if (bc.cA == NULL || !*bc.cA) + if (!bc.cA) ret = HX509_PARENT_NOT_CA; else if (bc.pathLenConstraint) if (depth - 1 > *bc.pathLenConstraint) diff --git a/lib/hx509/cms.c b/lib/hx509/cms.c index 6e935fc40..0f17ce743 100644 --- a/lib/hx509/cms.c +++ b/lib/hx509/cms.c @@ -1510,7 +1510,7 @@ hx509_cms_create_signed(hx509_context context, sigctx.anchors = anchors; sigctx.pool = pool; - sigctx.sd.version = CMSVersion_v3; + sigctx.sd.version = cMSVersion_v3; der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType); diff --git a/lib/hx509/hx509.h b/lib/hx509/hx509.h index 325182a2d..ee9c27811 100644 --- a/lib/hx509/hx509.h +++ b/lib/hx509/hx509.h @@ -37,7 +37,6 @@ #define HEIMDAL_HX509_H 1 #include -#include #include #include #include diff --git a/lib/hx509/hx_locl.h b/lib/hx509/hx_locl.h index b8848919d..d653f7d98 100644 --- a/lib/hx509/hx_locl.h +++ b/lib/hx509/hx_locl.h @@ -59,7 +59,6 @@ #include #include -#include #include #include #include @@ -69,7 +68,6 @@ #include #include #include -#include #include diff --git a/lib/hx509/name.c b/lib/hx509/name.c index 855d7bdae..d90580183 100644 --- a/lib/hx509/name.c +++ b/lib/hx509/name.c @@ -1238,7 +1238,7 @@ struct { { &asn1_oid_id_pkinit_san, "KerberosPrincipalName", _hx509_unparse_KRB5PrincipalName }, - { &asn1_oid_id_on_permanentIdentifier, + { &asn1_oid_id_pkix_on_permanentIdentifier, "PermanentIdentifier", _hx509_unparse_PermanentIdentifier }, { &asn1_oid_id_on_hardwareModuleName, diff --git a/lib/hx509/print.c b/lib/hx509/print.c index c27f8ac98..065ee33aa 100644 --- a/lib/hx509/print.c +++ b/lib/hx509/print.c @@ -585,21 +585,16 @@ check_basicConstraints(hx509_validate_ctx ctx, printf("\tlength of der data isn't same as extension\n"); validate_print(ctx, HX509_VALIDATE_F_VERBOSE, - "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT "); + "\tis %sa CA\n", b.cA ? "" : "NOT "); if (b.pathLenConstraint) validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tpathLenConstraint: %d\n", *b.pathLenConstraint); if (b.cA) { - if (*b.cA) { - if (!e->critical) - validate_print(ctx, HX509_VALIDATE_F_VALIDATE, - "Is a CA and not BasicConstraints CRITICAL\n"); - status->isca = 1; - } - else - validate_print(ctx, HX509_VALIDATE_F_VALIDATE, - "cA is FALSE, not allowed to be\n"); + if (!e->critical) + validate_print(ctx, HX509_VALIDATE_F_VALIDATE, + "Is a CA and not BasicConstraints CRITICAL\n"); + status->isca = 1; } free_BasicConstraints(&b); diff --git a/lib/hx509/req.c b/lib/hx509/req.c index 1d5a2f39a..d56811984 100644 --- a/lib/hx509/req.c +++ b/lib/hx509/req.c @@ -530,10 +530,7 @@ get_exts(hx509_context context, memset(&e, 0, sizeof(e)); /* The critical field needs to be made DEFAULT FALSE... */ - if ((e.critical = malloc(sizeof(*e.critical))) == NULL) - ret = ENOMEM; - if (ret == 0) - *e.critical = 1; + e.critical = 1; if (ret == 0) ASN1_MALLOC_ENCODE(KeyUsage, e.extnValue.data, e.extnValue.length, &req->ku, &size, ret); @@ -547,10 +544,7 @@ get_exts(hx509_context context, Extension e; memset(&e, 0, sizeof(e)); - if ((e.critical = malloc(sizeof(*e.critical))) == NULL) - ret = ENOMEM; - if (ret == 0) - *e.critical = 1; + e.critical = 1; if (ret == 0) ASN1_MALLOC_ENCODE(ExtKeyUsage, e.extnValue.data, e.extnValue.length, @@ -570,17 +564,11 @@ get_exts(hx509_context context, * * The empty DN check could probably stand to be a function we export. */ - e.critical = NULL; + e.critical = FALSE; if (req->name && req->name->der_name.element == choice_Name_rdnSequence && - req->name->der_name.u.rdnSequence.len == 0) { - - if ((e.critical = malloc(sizeof(*e.critical))) == NULL) - ret = ENOMEM; - if (ret == 0) { - *e.critical = 1; - } - } + req->name->der_name.u.rdnSequence.len == 0) + e.critical = 1; if (ret == 0) ASN1_MALLOC_ENCODE(GeneralNames, e.extnValue.data, e.extnValue.length, @@ -1241,7 +1229,7 @@ san_map_type(GeneralName *san) { &asn1_oid_id_pkinit_san, HX509_SAN_TYPE_PKINIT }, { &asn1_oid_id_pkix_on_xmppAddr, HX509_SAN_TYPE_XMPP }, { &asn1_oid_id_pkinit_ms_san, HX509_SAN_TYPE_MS_UPN }, - { &asn1_oid_id_on_permanentIdentifier, HX509_SAN_TYPE_PERMANENT_ID }, + { &asn1_oid_id_pkix_on_permanentIdentifier, HX509_SAN_TYPE_PERMANENT_ID }, { &asn1_oid_id_on_hardwareModuleName, HX509_SAN_TYPE_HW_MODULE }, }; size_t i; diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 0c0926415..e78873db8 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -48,6 +48,8 @@ #include #include +typedef Krb5Int32 krb5int32; +typedef Krb5UInt32 krb5uint32; /* name confusion with MIT */ #ifndef KRB5KDC_ERR_KEY_EXP diff --git a/lib/krb5/krb5_locl.h b/lib/krb5/krb5_locl.h index 381aa12fe..e0651e591 100644 --- a/lib/krb5/krb5_locl.h +++ b/lib/krb5/krb5_locl.h @@ -122,6 +122,8 @@ struct mbuf; #include +typedef Krb5Int32 krb5int32; +typedef Krb5UInt32 krb5uint32; #include struct send_to_kdc; diff --git a/lib/krb5/rd_req.c b/lib/krb5/rd_req.c index fbced144e..1cd8b2658 100644 --- a/lib/krb5/rd_req.c +++ b/lib/krb5/rd_req.c @@ -146,7 +146,7 @@ check_transited(krb5_context context, Ticket *ticket, EncTicketPart *enc) if(enc->transited.tr_type == 0 && enc->transited.contents.length == 0) return 0; - if(enc->transited.tr_type != DOMAIN_X500_COMPRESS) + if(enc->transited.tr_type != domain_X500_Compress) return KRB5KDC_ERR_TRTYPE_NOSUPP; if(enc->transited.contents.length == 0)