diff --git a/0001-Fix-named-working-directory-permissions.patch b/0001-Fix-named-working-directory-permissions.patch new file mode 100644 index 0000000..1908d15 --- /dev/null +++ b/0001-Fix-named-working-directory-permissions.patch @@ -0,0 +1,176 @@ +From ba124045b9f39f8264a974c977beba6f15b1b1fb Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 11 Nov 2014 13:00:18 +0100 +Subject: [PATCH] Fix named working directory permissions + +Just adding dir to specfile doesnt work, because is not guarantee the +named is installed, during RPM installation. + +Ticket: https://fedorahosted.org/freeipa/ticket/4716 +Reviewed-By: Jan Cholasta +--- + freeipa.spec.in | 3 +-- + install/tools/ipa-upgradeconfig | 14 +++++++++++++ + ipaplatform/base/paths.py | 1 + + ipaserver/install/dnskeysyncinstance.py | 36 +++++++++++++++++++++++++++------ + 4 files changed, 46 insertions(+), 8 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index b2ff97a11dcbb675940086ab9af9aea9bf7988be..af367037eee27d45f0c825ad4518f269b2798045 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -426,7 +426,6 @@ mkdir -p %{buildroot}%{_usr}/share/ipa/html/ + /bin/touch %{buildroot}%{_usr}/share/ipa/html/preferences.html + mkdir -p %{buildroot}%{_initrddir} + mkdir %{buildroot}%{_sysconfdir}/sysconfig/ +-mkdir -p %{buildroot}%{_localstatedir}/named/dyndb-ldap/ipa/ + install -m 644 init/ipa_memcached.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa_memcached + install -m 644 init/ipa-dnskeysyncd.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa-dnskeysyncd + install -m 644 init/ipa-ods-exporter.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa-ods-exporter +@@ -666,7 +665,6 @@ fi + %config(noreplace) %{_sysconfdir}/sysconfig/ipa-ods-exporter + %dir %attr(0700,apache,apache) %{_localstatedir}/run/ipa_memcached/ + %dir %attr(0700,root,root) %{_localstatedir}/run/ipa/ +-%dir %attr(0770,named,named) %{_localstatedir}/named/dyndb-ldap/ipa/ + # NOTE: systemd specific section + %{_tmpfilesdir}/%{name}.conf + %attr(644,root,root) %{_unitdir}/ipa.service +@@ -780,6 +778,7 @@ fi + %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade + %attr(755,root,root) %dir %{_localstatedir}/lib/ipa/pki-ca + %ghost %{_localstatedir}/lib/ipa/pki-ca/publish ++%ghost %{_localstatedir}/named/dyndb-ldap/ipa + %attr(755,root,root) %{_libdir}/krb5/plugins/kdb/ipadb.so + %{_mandir}/man1/ipa-replica-conncheck.1.gz + %{_mandir}/man1/ipa-replica-install.1.gz +diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig +index 6556d8f313d3a9efeb32d4cba97cb82796459652..b0b574476ffc5ce6f075cf46177cc059483551ab 100644 +--- a/install/tools/ipa-upgradeconfig ++++ b/install/tools/ipa-upgradeconfig +@@ -30,6 +30,7 @@ import shutil + import pwd + import fileinput + import ConfigParser ++import grp + + from ipalib import api + import SSSDConfig +@@ -1161,6 +1162,18 @@ def mask_named_regular(): + return False + + ++def fix_dyndb_ldap_workdir_permissions(): ++ """Fix dyndb-ldap working dir permissions. DNSSEC daemons requires it""" ++ if sysupgrade.get_upgrade_state('dns', 'dyndb_ipa_workdir_perm'): ++ return ++ ++ if bindinstance.named_conf_exists(): ++ root_logger.info('[Fix bind-dyndb-ldap IPA working directory]') ++ dnskeysync = dnskeysyncinstance.DNSKeySyncInstance() ++ dnskeysync.set_dyndb_ldap_workdir_permissions() ++ ++ sysupgrade.set_upgrade_state('dns', 'dyndb_ipa_workdir_perm', True) ++ + + def fix_schema_file_syntax(): + """Fix syntax errors in schema files +@@ -1433,6 +1446,7 @@ def main(): + named_managed_keys_dir_option(), + named_root_key_include(), + mask_named_regular(), ++ fix_dyndb_ldap_workdir_permissions(), + ) + + if any(named_conf_changes): +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index e28147ab4aa1faa3859c38665a83f57fb67e96b2..c4cdc58d61caca7a0d80546bdd69915ac47a23bd 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -189,6 +189,7 @@ class BasePathNamespace(object): + BIN_WGET = "/usr/bin/wget" + ZIP = "/usr/bin/zip" + BIND_LDAP_SO = "/usr/lib/bind/ldap.so" ++ BIND_LDAP_DNS_IPA_WORKDIR = "/var/named/dyndb-ldap/ipa/" + BIND_LDAP_DNS_ZONE_WORKDIR = "/var/named/dyndb-ldap/ipa/master/" + USR_LIB_DIRSRV = "/usr/lib/dirsrv" + USR_LIB_SLAPD_INSTANCE_TEMPLATE = "/usr/lib/dirsrv/slapd-%s" +diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py +index 1dd9a0983fb689f14656431496dfd4b2bb2e30a9..5da65d87b1471710b762f90b9a33c453c7d809b7 100644 +--- a/ipaserver/install/dnskeysyncinstance.py ++++ b/ipaserver/install/dnskeysyncinstance.py +@@ -60,7 +60,6 @@ def dnssec_container_exists(fqdn, suffix, dm_password=None, ldapi=False, + + return ret + +- + class DNSKeySyncInstance(service.Service): + def __init__(self, fstore=None, dm_password=None, logger=root_logger, + ldapi=False): +@@ -84,6 +83,23 @@ class DNSKeySyncInstance(service.Service): + + suffix = ipautil.dn_attribute_property('_suffix') + ++ def set_dyndb_ldap_workdir_permissions(self): ++ """ ++ Setting up correct permissions to allow write/read access for daemons ++ """ ++ if self.named_uid is None: ++ self.named_uid = self.__get_named_uid() ++ ++ if self.named_gid is None: ++ self.named_gid = self.__get_named_gid() ++ ++ if not os.path.exists(paths.BIND_LDAP_DNS_IPA_WORKDIR): ++ os.mkdir(paths.BIND_LDAP_DNS_IPA_WORKDIR, 0770) ++ # dnssec daemons require to have access into the directory ++ os.chmod(paths.BIND_LDAP_DNS_IPA_WORKDIR, 0770) ++ os.chown(paths.BIND_LDAP_DNS_IPA_WORKDIR, self.named_uid, ++ self.named_gid) ++ + def remove_replica_public_keys(self, replica_fqdn): + ldap = api.Backend.ldap2 + dn_base = DN(('cn', 'keys'), ('cn', 'sec'), ('cn', 'dns'), api.env.basedn) +@@ -119,6 +135,8 @@ class DNSKeySyncInstance(service.Service): + self.ldap_connect() + # checking status step must be first + self.step("checking status", self.__check_dnssec_status) ++ self.step("setting up bind-dyndb-ldap working directory", ++ self.set_dyndb_ldap_workdir_permissions) + self.step("setting up kerberos principal", self.__setup_principal) + self.step("setting up SoftHSM", self.__setup_softhsm) + self.step("adding DNSSEC containers", self.__setup_dnssec_containers) +@@ -127,20 +145,26 @@ class DNSKeySyncInstance(service.Service): + # we need restart named after setting up this service + self.start_creation() + +- def __check_dnssec_status(self): ++ def __get_named_uid(self): + named = services.knownservices.named +- ods_enforcerd = services.knownservices.ods_enforcerd +- + try: +- self.named_uid = pwd.getpwnam(named.get_user_name()).pw_uid ++ return pwd.getpwnam(named.get_user_name()).pw_uid + except KeyError: + raise RuntimeError("Named UID not found") + ++ def __get_named_gid(self): ++ named = services.knownservices.named + try: +- self.named_gid = grp.getgrnam(named.get_group_name()).gr_gid ++ return grp.getgrnam(named.get_group_name()).gr_gid + except KeyError: + raise RuntimeError("Named GID not found") + ++ def __check_dnssec_status(self): ++ ods_enforcerd = services.knownservices.ods_enforcerd ++ ++ self.named_uid = self.__get_named_uid() ++ self.named_gid = self.__get_named_gid() ++ + try: + self.ods_uid = pwd.getpwnam(ods_enforcerd.get_user_name()).pw_uid + except KeyError: +-- +2.1.0 + diff --git a/0002-Show-warning-instead-of-error-if-CA-did-not-start.patch b/0002-Show-warning-instead-of-error-if-CA-did-not-start.patch new file mode 100644 index 0000000..684b922 --- /dev/null +++ b/0002-Show-warning-instead-of-error-if-CA-did-not-start.patch @@ -0,0 +1,32 @@ +From 3f3f49ea93f8ca0c2cdd569a78c952492e7b520a Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 18 Nov 2014 18:30:59 +0100 +Subject: [PATCH] Show warning instead of error if CA did not start + +This is just workaround, checking if CA is working raises false positive +exception during upgrade + +Ticket: https://fedorahosted.org/freeipa/ticket/4676 +Reviewed-By: Simo Sorce +--- + install/tools/ipa-upgradeconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig +index b0b574476ffc5ce6f075cf46177cc059483551ab..ffb51a97726d2212284f2bb2b939cefd674e24c4 100644 +--- a/install/tools/ipa-upgradeconfig ++++ b/install/tools/ipa-upgradeconfig +@@ -1471,6 +1471,10 @@ def main(): + ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) + except ipautil.CalledProcessError, e: + root_logger.error("Failed to restart %s: %s", ca.service_name, e) ++ # FIXME https://fedorahosted.org/freeipa/ticket/4676 ++ # workaround ++ except RuntimeError as e: ++ root_logger.warning(str(e)) + + set_sssd_domain_option('ipa_server_mode', 'True') + +-- +2.1.0 + diff --git a/0003-webui-fix-potential-XSS-vulnerabilities.patch b/0003-webui-fix-potential-XSS-vulnerabilities.patch new file mode 100644 index 0000000..7e98c47 --- /dev/null +++ b/0003-webui-fix-potential-XSS-vulnerabilities.patch @@ -0,0 +1,131 @@ +From af9fd4dfe2c18e52127480c959c35ad37b566095 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Mon, 10 Nov 2014 16:24:15 +0100 +Subject: [PATCH] webui: fix potential XSS vulnerabilities + +Escape user defined text to prevent XSS attacks. Extra precaution was taken +to escape also parts which are unlikely to contain user-defined text. + +fixes CVE-2014-7850 + +https://fedorahosted.org/freeipa/ticket/4742 + +Reviewed-By: Tomas Babej +--- + install/ui/src/freeipa/Application_controller.js | 4 ++-- + install/ui/src/freeipa/facet.js | 12 +++++++----- + install/ui/src/freeipa/ipa.js | 1 + + install/ui/src/freeipa/rule.js | 2 +- + install/ui/src/freeipa/widget.js | 4 ++-- + 5 files changed, 13 insertions(+), 10 deletions(-) + +diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js +index 094bd3da7c4806a316ebe2589b98a523410f4a5f..4bf76f8f56a8e34e330c35956b8922cc3c8f79e3 100644 +--- a/install/ui/src/freeipa/Application_controller.js ++++ b/install/ui/src/freeipa/Application_controller.js +@@ -252,12 +252,12 @@ define([ + var error_container = $('
', { + 'class': 'container facet-content facet-error' + }).appendTo($('.app-container .content').empty()); +- error_container.append('

'+name+'

'); ++ error_container.append($('

', { text: name })); + var details = $('
', { + 'class': 'error-details' + }).appendTo(error_container); + +- details.append('

Web UI got in unrecoverable state during "'+error.phase+'" phase.

'); ++ details.append($('

', { text: 'Web UI got in unrecoverable state during "' + error.phase + '" phase' })); + if (error.name) window.console.error(error.name); + if (error.results) { + var msg = error.results.message; +diff --git a/install/ui/src/freeipa/facet.js b/install/ui/src/freeipa/facet.js +index 43627d9d531ed700ff780a0773451eaf17b1cbdd..b0121c75fd584988883a3b5f7d1665a985a321fd 100644 +--- a/install/ui/src/freeipa/facet.js ++++ b/install/ui/src/freeipa/facet.js +@@ -895,12 +895,12 @@ exp.facet = IPA.facet = function(spec, no_init) { + title = title.replace('${error}', error_thrown.name); + + that.error_container.empty(); +- that.error_container.append('

'+title+'

'); ++ that.error_container.append($('

', { text: title })); + + var details = $('
', { + 'class': 'error-details' + }).appendTo(that.error_container); +- details.append('

'+error_thrown.message+'

'); ++ details.append($('

', { text: error_thrown.message })); + + $('

', { + text: text.get('@i18n:error_report.options') +@@ -932,7 +932,9 @@ exp.facet = IPA.facet = function(spec, no_init) { + } + ); + +- that.error_container.append('

'+text.get('@i18n:error_report.problem_persists')+'

'); ++ that.error_container.append($('

', { ++ text: text.get('@i18n:error_report.problem_persists') ++ })); + + that.show_error(); + }; +@@ -1214,7 +1216,7 @@ exp.facet_header = IPA.facet_header = function(spec) { + click: item.handler + }).appendTo(bc_item); + } else { +- bc_item.append(item.text); ++ bc_item.text(item.text); + } + return bc_item; + }; +@@ -1823,7 +1825,7 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) { + function(xhr, text_status, error_thrown) { + that.load_records([]); + var summary = that.table.summary.empty(); +- summary.append(error_thrown.name+': '+error_thrown.message); ++ summary.text(error_thrown.name+': '+error_thrown.message); + } + ); + }; +diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js +index 6d3aeaaaaca11dfdaf20935e5c9084c9ed106e6c..137f11e832ff8d0b6dd1b50060f8537c7b117616 100644 +--- a/install/ui/src/freeipa/ipa.js ++++ b/install/ui/src/freeipa/ipa.js +@@ -1133,6 +1133,7 @@ IPA.notify = function(message, type, timeout) { + + if (typeof message === 'string') { + message = text.get(message); ++ message = document.createTextNode(message); + } + + var notification_area = $('#notification .notification-area'); +diff --git a/install/ui/src/freeipa/rule.js b/install/ui/src/freeipa/rule.js +index 8a2b01963b74e1892ac15127ae0050b35fe6ac27..706827190261efda136f6d1489bdb13543c00f7a 100644 +--- a/install/ui/src/freeipa/rule.js ++++ b/install/ui/src/freeipa/rule.js +@@ -91,7 +91,7 @@ IPA.rule_radio_widget = function(spec) { + var param_info = IPA.get_entity_param(that.entity.name, that.name); + var title = param_info ? param_info.doc : that.name; + +- container.append(title + ': '); ++ container.append(document.createTextNode(title + ': ')); + that.widget_create(container); + that.owb_create(container); + if (that.undo) { +diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js +index 9240df8ef5402310ec9ceafd0b766def10c8cb48..1ef1a2bf22b735edcfcca44cfc1e69bc8d36a740 100644 +--- a/install/ui/src/freeipa/widget.js ++++ b/install/ui/src/freeipa/widget.js +@@ -4166,8 +4166,8 @@ IPA.link_widget = function(spec) { + + that.values = util.normalize_value(values); + that.value = that.values.slice(-1)[0] || ''; +- that.link.html(that.value); +- that.nonlink.html(that.value); ++ that.link.text(that.value); ++ that.nonlink.text(that.value); + that.update_link(); + that.check_entity_link(); + that.on_value_changed(values); +-- +2.1.0 + diff --git a/0004-Fix-filtering-of-enctypes-in-server-code.patch b/0004-Fix-filtering-of-enctypes-in-server-code.patch new file mode 100644 index 0000000..369645f --- /dev/null +++ b/0004-Fix-filtering-of-enctypes-in-server-code.patch @@ -0,0 +1,98 @@ +From b170851058d6712442d553ef3d11ecd21b282443 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Mon, 17 Nov 2014 21:05:56 -0500 +Subject: [PATCH 1/3] Fix filtering of enctypes in server code. + +The filtering was incorrect and would result in always discarding all values. +Also make sure there are no duplicates in the list. + +Partial fix for: +https://fedorahosted.org/freeipa/ticket/4718 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Nathaniel McCallum +--- + .../ipa-pwd-extop/ipa_pwd_extop.c | 60 ++++++++++++++++------ + 1 file changed, 43 insertions(+), 17 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +index f0346a343188930dfc90e19d2e5d38cb30741b90..b87ae0dc7a180008228f31293b49212df80584e8 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +@@ -125,6 +125,48 @@ static void filter_keys(struct ipapwd_krbcfg *krbcfg, + } + } + ++static void filter_enctypes(struct ipapwd_krbcfg *krbcfg, ++ krb5_key_salt_tuple *kenctypes, ++ int *num_kenctypes) ++{ ++ /* first filter for duplicates */ ++ for (int i = 0; i + 1 < *num_kenctypes; i++) { ++ for (int j = i + 1; j < *num_kenctypes; j++) { ++ if (kenctypes[i].ks_enctype == kenctypes[j].ks_enctype) { ++ /* duplicate, filter out */ ++ for (int k = j; k + 1 < *num_kenctypes; k++) { ++ kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype; ++ kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype; ++ } ++ (*num_kenctypes)--; ++ j--; ++ } ++ } ++ } ++ ++ /* then filter for supported */ ++ for (int i = 0; i < *num_kenctypes; i++) { ++ int j; ++ ++ /* Check if supported */ ++ for (j = 0; j < krbcfg->num_supp_encsalts; j++) { ++ if (kenctypes[i].ks_enctype == ++ krbcfg->supp_encsalts[j].ks_enctype) { ++ break; ++ } ++ } ++ if (j == krbcfg->num_supp_encsalts) { ++ /* Unsupported, filter out */ ++ for (int k = i; k + 1 < *num_kenctypes; k++) { ++ kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype; ++ kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype; ++ } ++ (*num_kenctypes)--; ++ i--; ++ } ++ } ++} ++ + static int ipapwd_to_ldap_pwpolicy_error(int ipapwderr) + { + switch (ipapwderr) { +@@ -1740,23 +1782,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) + goto free_and_return; + } + +- for (int i = 0; i < num_kenctypes; i++) { +- +- /* Check if supported */ +- for (int j = 0; j < krbcfg->num_supp_encsalts; j++) { +- if (kenctypes[i].ks_enctype == +- krbcfg->supp_encsalts[j].ks_enctype) { +- continue; +- } +- } +- /* Unsupported, filter out */ +- for (int j = i; j + 1 < num_kenctypes; j++) { +- kenctypes[j].ks_enctype = kenctypes[j + 1].ks_enctype; +- kenctypes[j].ks_salttype = kenctypes[j + 1].ks_salttype; +- } +- num_kenctypes--; +- i--; +- } ++ filter_enctypes(krbcfg, kenctypes, &num_kenctypes); + + /* check if we have any left */ + if (num_kenctypes == 0 && kenctypes != NULL) { +-- +2.1.0 + diff --git a/0005-Add-asn1c-generated-code-for-keytab-controls.patch b/0005-Add-asn1c-generated-code-for-keytab-controls.patch new file mode 100644 index 0000000..f0e19b6 --- /dev/null +++ b/0005-Add-asn1c-generated-code-for-keytab-controls.patch @@ -0,0 +1,13109 @@ +From c6afc489a1c9d86fd593bd47c4a8dae6d9a008d2 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Thu, 13 Nov 2014 11:31:09 -0500 +Subject: [PATCH 2/3] Add asn1c generated code for keytab controls + +Instead of manually encoding controls, use an actual asn1 compiler. +The file asn1/asn1c/ipa.asn1 will contain ipa modules. The generated code +is committed to the tree and built into a static library that is linked +to the code that uses it. + +The first module implements the GetKeytabControl control. + +Related: +https://fedorahosted.org/freeipa/ticket/4718 +https://fedorahosted.org/freeipa/ticket/4728 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Nathaniel McCallum +--- + .gitignore | 1 + + Makefile | 5 +- + asn1/Makefile.am | 8 + + asn1/README | 17 + + asn1/asn1c/BIT_STRING.c | 188 +++++ + asn1/asn1c/BIT_STRING.h | 33 + + asn1/asn1c/GKCurrentKeys.c | 61 ++ + asn1/asn1c/GKCurrentKeys.h | 37 + + asn1/asn1c/GKNewKeys.c | 126 ++++ + asn1/asn1c/GKNewKeys.h | 47 ++ + asn1/asn1c/GKReply.c | 115 +++ + asn1/asn1c/GKReply.h | 51 ++ + asn1/asn1c/GetKeytabControl.c | 77 ++ + asn1/asn1c/GetKeytabControl.h | 52 ++ + asn1/asn1c/INTEGER.c | 835 +++++++++++++++++++++ + asn1/asn1c/INTEGER.h | 65 ++ + asn1/asn1c/Int32.c | 127 ++++ + asn1/asn1c/Int32.h | 38 + + asn1/asn1c/KrbKey.c | 81 ++ + asn1/asn1c/KrbKey.h | 46 ++ + asn1/asn1c/Makefile.am | 93 +++ + asn1/asn1c/NativeEnumerated.c | 204 ++++++ + asn1/asn1c/NativeEnumerated.h | 32 + + asn1/asn1c/NativeInteger.c | 314 ++++++++ + asn1/asn1c/NativeInteger.h | 37 + + asn1/asn1c/OCTET_STRING.c | 1550 +++++++++++++++++++++++++++++++++++++++ + asn1/asn1c/OCTET_STRING.h | 80 ++ + asn1/asn1c/TypeValuePair.c | 71 ++ + asn1/asn1c/TypeValuePair.h | 39 + + asn1/asn1c/asn_SEQUENCE_OF.c | 41 ++ + asn1/asn1c/asn_SEQUENCE_OF.h | 52 ++ + asn1/asn1c/asn_SET_OF.c | 88 +++ + asn1/asn1c/asn_SET_OF.h | 62 ++ + asn1/asn1c/asn_application.h | 47 ++ + asn1/asn1c/asn_codecs.h | 109 +++ + asn1/asn1c/asn_codecs_prim.c | 295 ++++++++ + asn1/asn1c/asn_codecs_prim.h | 53 ++ + asn1/asn1c/asn_internal.h | 111 +++ + asn1/asn1c/asn_system.h | 104 +++ + asn1/asn1c/ber_decoder.c | 283 +++++++ + asn1/asn1c/ber_decoder.h | 63 ++ + asn1/asn1c/ber_tlv_length.c | 178 +++++ + asn1/asn1c/ber_tlv_length.h | 50 ++ + asn1/asn1c/ber_tlv_tag.c | 144 ++++ + asn1/asn1c/ber_tlv_tag.h | 60 ++ + asn1/asn1c/constr_CHOICE.c | 1101 +++++++++++++++++++++++++++ + asn1/asn1c/constr_CHOICE.h | 57 ++ + asn1/asn1c/constr_SEQUENCE.c | 1251 +++++++++++++++++++++++++++++++ + asn1/asn1c/constr_SEQUENCE.h | 60 ++ + asn1/asn1c/constr_SEQUENCE_OF.c | 208 ++++++ + asn1/asn1c/constr_SEQUENCE_OF.h | 33 + + asn1/asn1c/constr_SET_OF.c | 942 ++++++++++++++++++++++++ + asn1/asn1c/constr_SET_OF.h | 42 ++ + asn1/asn1c/constr_TYPE.c | 77 ++ + asn1/asn1c/constr_TYPE.h | 180 +++++ + asn1/asn1c/constraints.c | 93 +++ + asn1/asn1c/constraints.h | 63 ++ + asn1/asn1c/der_encoder.c | 199 +++++ + asn1/asn1c/der_encoder.h | 67 ++ + asn1/asn1c/ipa.asn1 | 37 + + asn1/asn1c/per_decoder.c | 55 ++ + asn1/asn1c/per_decoder.h | 44 ++ + asn1/asn1c/per_encoder.c | 95 +++ + asn1/asn1c/per_encoder.h | 49 ++ + asn1/asn1c/per_support.c | 318 ++++++++ + asn1/asn1c/per_support.h | 105 +++ + asn1/asn1c/xer_decoder.c | 363 +++++++++ + asn1/asn1c/xer_decoder.h | 106 +++ + asn1/asn1c/xer_encoder.c | 67 ++ + asn1/asn1c/xer_encoder.h | 59 ++ + asn1/asn1c/xer_support.c | 233 ++++++ + asn1/asn1c/xer_support.h | 55 ++ + asn1/configure.ac | 24 + + asn1/ipa_asn1.c | 229 ++++++ + asn1/ipa_asn1.h | 76 ++ + util/ipa_krb5.h | 1 + + 76 files changed, 12457 insertions(+), 2 deletions(-) + create mode 100644 asn1/Makefile.am + create mode 100644 asn1/README + create mode 100644 asn1/asn1c/BIT_STRING.c + create mode 100644 asn1/asn1c/BIT_STRING.h + create mode 100644 asn1/asn1c/GKCurrentKeys.c + create mode 100644 asn1/asn1c/GKCurrentKeys.h + create mode 100644 asn1/asn1c/GKNewKeys.c + create mode 100644 asn1/asn1c/GKNewKeys.h + create mode 100644 asn1/asn1c/GKReply.c + create mode 100644 asn1/asn1c/GKReply.h + create mode 100644 asn1/asn1c/GetKeytabControl.c + create mode 100644 asn1/asn1c/GetKeytabControl.h + create mode 100644 asn1/asn1c/INTEGER.c + create mode 100644 asn1/asn1c/INTEGER.h + create mode 100644 asn1/asn1c/Int32.c + create mode 100644 asn1/asn1c/Int32.h + create mode 100644 asn1/asn1c/KrbKey.c + create mode 100644 asn1/asn1c/KrbKey.h + create mode 100644 asn1/asn1c/Makefile.am + create mode 100644 asn1/asn1c/NativeEnumerated.c + create mode 100644 asn1/asn1c/NativeEnumerated.h + create mode 100644 asn1/asn1c/NativeInteger.c + create mode 100644 asn1/asn1c/NativeInteger.h + create mode 100644 asn1/asn1c/OCTET_STRING.c + create mode 100644 asn1/asn1c/OCTET_STRING.h + create mode 100644 asn1/asn1c/TypeValuePair.c + create mode 100644 asn1/asn1c/TypeValuePair.h + create mode 100644 asn1/asn1c/asn_SEQUENCE_OF.c + create mode 100644 asn1/asn1c/asn_SEQUENCE_OF.h + create mode 100644 asn1/asn1c/asn_SET_OF.c + create mode 100644 asn1/asn1c/asn_SET_OF.h + create mode 100644 asn1/asn1c/asn_application.h + create mode 100644 asn1/asn1c/asn_codecs.h + create mode 100644 asn1/asn1c/asn_codecs_prim.c + create mode 100644 asn1/asn1c/asn_codecs_prim.h + create mode 100644 asn1/asn1c/asn_internal.h + create mode 100644 asn1/asn1c/asn_system.h + create mode 100644 asn1/asn1c/ber_decoder.c + create mode 100644 asn1/asn1c/ber_decoder.h + create mode 100644 asn1/asn1c/ber_tlv_length.c + create mode 100644 asn1/asn1c/ber_tlv_length.h + create mode 100644 asn1/asn1c/ber_tlv_tag.c + create mode 100644 asn1/asn1c/ber_tlv_tag.h + create mode 100644 asn1/asn1c/constr_CHOICE.c + create mode 100644 asn1/asn1c/constr_CHOICE.h + create mode 100644 asn1/asn1c/constr_SEQUENCE.c + create mode 100644 asn1/asn1c/constr_SEQUENCE.h + create mode 100644 asn1/asn1c/constr_SEQUENCE_OF.c + create mode 100644 asn1/asn1c/constr_SEQUENCE_OF.h + create mode 100644 asn1/asn1c/constr_SET_OF.c + create mode 100644 asn1/asn1c/constr_SET_OF.h + create mode 100644 asn1/asn1c/constr_TYPE.c + create mode 100644 asn1/asn1c/constr_TYPE.h + create mode 100644 asn1/asn1c/constraints.c + create mode 100644 asn1/asn1c/constraints.h + create mode 100644 asn1/asn1c/der_encoder.c + create mode 100644 asn1/asn1c/der_encoder.h + create mode 100644 asn1/asn1c/ipa.asn1 + create mode 100644 asn1/asn1c/per_decoder.c + create mode 100644 asn1/asn1c/per_decoder.h + create mode 100644 asn1/asn1c/per_encoder.c + create mode 100644 asn1/asn1c/per_encoder.h + create mode 100644 asn1/asn1c/per_support.c + create mode 100644 asn1/asn1c/per_support.h + create mode 100644 asn1/asn1c/xer_decoder.c + create mode 100644 asn1/asn1c/xer_decoder.h + create mode 100644 asn1/asn1c/xer_encoder.c + create mode 100644 asn1/asn1c/xer_encoder.h + create mode 100644 asn1/asn1c/xer_support.c + create mode 100644 asn1/asn1c/xer_support.h + create mode 100644 asn1/configure.ac + create mode 100644 asn1/ipa_asn1.c + create mode 100644 asn1/ipa_asn1.h + +diff --git a/.gitignore b/.gitignore +index 5b3f401d26c172cf24a08014651e453439a5e9d1..c4c761903d29e1b9f62c7ece04dbaa187fb84de8 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -25,6 +25,7 @@ missing + stamp-h1 + libtool + build/ ++compile + + # Python compilation + *.pyc +diff --git a/Makefile b/Makefile +index d714aad813f8e08c264075545a9ce678eca37425..9321c81fe5deebdd5d8b3d7e406347fc5d159610 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + include VERSION + +-SUBDIRS=daemons install ipapython ipa-client +-CLIENTDIRS=ipapython ipa-client ++SUBDIRS=asn1 daemons install ipapython ipa-client ++CLIENTDIRS=ipapython ipa-client asn1 + + PRJ_PREFIX=freeipa + +@@ -80,6 +80,7 @@ bootstrap-autogen: version-update client-autogen + cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi + + client-autogen: version-update ++ cd asn1; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi + cd ipa-client; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi + cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi + +diff --git a/asn1/Makefile.am b/asn1/Makefile.am +new file mode 100644 +index 0000000000000000000000000000000000000000..03e92b2d6d73f89625d5613f039361a6e02866b9 +--- /dev/null ++++ b/asn1/Makefile.am +@@ -0,0 +1,8 @@ ++SUBDIRS = asn1c ++ ++AM_CPPFLAGS = -I../util -Iasn1c ++ ++noinst_LTLIBRARIES=libipaasn1.la ++noinst_HEADERS=ipa_asn1.h ++libipaasn1_la_SOURCES=ipa_asn1.c ++libipaasn1_la_LIBADD=asn1c/libasn1c.la +diff --git a/asn1/README b/asn1/README +new file mode 100644 +index 0000000000000000000000000000000000000000..ec9752f566a8b57b45d433bb46316c9aba325fa7 +--- /dev/null ++++ b/asn1/README +@@ -0,0 +1,17 @@ ++libipaasn1.a is a small static convenience library used by other ipa ++binaries and modules. At the moment it is not meant to be a public shared ++library and stable interface, but may become one in future. ++ ++The only files that should be manually modified are: ++* asn1c/ipa.asn1 - when new interfaces are added ++* ipa_asn1.[ch] - to add wrappers around interfaces ++ ++ipa_asn1.[ch] are the public interface and they SHOULD NOT export generated ++structures so that the autogenerated code can change w/o impacting any other ++code except the internal library functions. ++ ++To regenerate the automatically generated files run the following command: ++cd asn1c; ++make regenerate ++ ++Remember to commit and add any new file to asn1c/Makefile.am +diff --git a/asn1/asn1c/BIT_STRING.c b/asn1/asn1c/BIT_STRING.c +new file mode 100644 +index 0000000000000000000000000000000000000000..6469d4fd2c8782048e228c19e67950f3b2dc1305 +--- /dev/null ++++ b/asn1/asn1c/BIT_STRING.c +@@ -0,0 +1,188 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * BIT STRING basic type description. ++ */ ++static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) ++}; ++static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = { ++ sizeof(BIT_STRING_t), ++ offsetof(BIT_STRING_t, _asn_ctx), ++ 1, /* Special indicator that this is a BIT STRING type */ ++}; ++asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { ++ "BIT STRING", ++ "BIT_STRING", ++ OCTET_STRING_free, /* Implemented in terms of OCTET STRING */ ++ BIT_STRING_print, ++ BIT_STRING_constraint, ++ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ ++ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ ++ OCTET_STRING_decode_xer_binary, ++ BIT_STRING_encode_xer, ++ OCTET_STRING_decode_uper, /* Unaligned PER decoder */ ++ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_BIT_STRING_tags, ++ sizeof(asn_DEF_BIT_STRING_tags) ++ / sizeof(asn_DEF_BIT_STRING_tags[0]), ++ asn_DEF_BIT_STRING_tags, /* Same as above */ ++ sizeof(asn_DEF_BIT_STRING_tags) ++ / sizeof(asn_DEF_BIT_STRING_tags[0]), ++ 0, /* No PER visible constraints */ ++ 0, 0, /* No members */ ++ &asn_DEF_BIT_STRING_specs ++}; ++ ++/* ++ * BIT STRING generic constraint. ++ */ ++int ++BIT_STRING_constraint(asn_TYPE_descriptor_t *td, const void *sptr, ++ asn_app_constraint_failed_f *ctfailcb, void *app_key) { ++ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; ++ ++ if(st && st->buf) { ++ if(st->size == 1 && st->bits_unused) { ++ _ASN_CTFAIL(app_key, td, ++ "%s: invalid padding byte (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++ } else { ++ _ASN_CTFAIL(app_key, td, ++ "%s: value not given (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static char *_bit_pattern[16] = { ++ "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", ++ "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" ++}; ++ ++asn_enc_rval_t ++BIT_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_enc_rval_t er; ++ char scratch[128]; ++ char *p = scratch; ++ char *scend = scratch + (sizeof(scratch) - 10); ++ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; ++ int xcan = (flags & XER_F_CANONICAL); ++ uint8_t *buf; ++ uint8_t *end; ++ ++ if(!st || !st->buf) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = 0; ++ ++ buf = st->buf; ++ end = buf + st->size - 1; /* Last byte is special */ ++ ++ /* ++ * Binary dump ++ */ ++ for(; buf < end; buf++) { ++ int v = *buf; ++ int nline = xcan?0:(((buf - st->buf) % 8) == 0); ++ if(p >= scend || nline) { ++ er.encoded += p - scratch; ++ _ASN_CALLBACK(scratch, p - scratch); ++ p = scratch; ++ if(nline) _i_ASN_TEXT_INDENT(1, ilevel); ++ } ++ memcpy(p + 0, _bit_pattern[v >> 4], 4); ++ memcpy(p + 4, _bit_pattern[v & 0x0f], 4); ++ p += 8; ++ } ++ ++ if(!xcan && ((buf - st->buf) % 8) == 0) ++ _i_ASN_TEXT_INDENT(1, ilevel); ++ er.encoded += p - scratch; ++ _ASN_CALLBACK(scratch, p - scratch); ++ p = scratch; ++ ++ if(buf == end) { ++ int v = *buf; ++ int ubits = st->bits_unused; ++ int i; ++ for(i = 7; i >= ubits; i--) ++ *p++ = (v & (1 << i)) ? 0x31 : 0x30; ++ er.encoded += p - scratch; ++ _ASN_CALLBACK(scratch, p - scratch); ++ } ++ ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); ++ ++ _ASN_ENCODED_OK(er); ++cb_failed: ++ _ASN_ENCODE_FAILED; ++} ++ ++ ++/* ++ * BIT STRING specific contents printer. ++ */ ++int ++BIT_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ static const char *h2c = "0123456789ABCDEF"; ++ char scratch[64]; ++ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; ++ uint8_t *buf; ++ uint8_t *end; ++ char *p = scratch; ++ ++ (void)td; /* Unused argument */ ++ ++ if(!st || !st->buf) ++ return (cb("", 8, app_key) < 0) ? -1 : 0; ++ ++ ilevel++; ++ buf = st->buf; ++ end = buf + st->size; ++ ++ /* ++ * Hexadecimal dump. ++ */ ++ for(; buf < end; buf++) { ++ if((buf - st->buf) % 16 == 0 && (st->size > 16) ++ && buf != st->buf) { ++ _i_INDENT(1); ++ /* Dump the string */ ++ if(cb(scratch, p - scratch, app_key) < 0) return -1; ++ p = scratch; ++ } ++ *p++ = h2c[*buf >> 4]; ++ *p++ = h2c[*buf & 0x0F]; ++ *p++ = 0x20; ++ } ++ ++ if(p > scratch) { ++ p--; /* Eat the tailing space */ ++ ++ if((st->size > 16)) { ++ _i_INDENT(1); ++ } ++ ++ /* Dump the incomplete 16-bytes row */ ++ if(cb(scratch, p - scratch, app_key) < 0) ++ return -1; ++ } ++ ++ return 0; ++} ++ +diff --git a/asn1/asn1c/BIT_STRING.h b/asn1/asn1c/BIT_STRING.h +new file mode 100644 +index 0000000000000000000000000000000000000000..732e878bcad1694e685153934afd8ce91f869e83 +--- /dev/null ++++ b/asn1/asn1c/BIT_STRING.h +@@ -0,0 +1,33 @@ ++/*- ++ * Copyright (c) 2003 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _BIT_STRING_H_ ++#define _BIT_STRING_H_ ++ ++#include /* Some help from OCTET STRING */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct BIT_STRING_s { ++ uint8_t *buf; /* BIT STRING body */ ++ int size; /* Size of the above buffer */ ++ ++ int bits_unused;/* Unused trailing bits in the last octet (0..7) */ ++ ++ asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ ++} BIT_STRING_t; ++ ++extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; ++ ++asn_struct_print_f BIT_STRING_print; /* Human-readable output */ ++asn_constr_check_f BIT_STRING_constraint; ++xer_type_encoder_f BIT_STRING_encode_xer; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _BIT_STRING_H_ */ +diff --git a/asn1/asn1c/GKCurrentKeys.c b/asn1/asn1c/GKCurrentKeys.c +new file mode 100644 +index 0000000000000000000000000000000000000000..abcc53130d64259d0f2947b04412b4b769bb4360 +--- /dev/null ++++ b/asn1/asn1c/GKCurrentKeys.c +@@ -0,0 +1,61 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#include ++ ++#include "GKCurrentKeys.h" ++ ++static asn_TYPE_member_t asn_MBR_GKCurrentKeys_1[] = { ++ { ATF_NOFLAGS, 0, offsetof(struct GKCurrentKeys, serviceIdentity), ++ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_OCTET_STRING, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "serviceIdentity" ++ }, ++}; ++static ber_tlv_tag_t asn_DEF_GKCurrentKeys_tags_1[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) ++}; ++static asn_TYPE_tag2member_t asn_MAP_GKCurrentKeys_tag2el_1[] = { ++ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* serviceIdentity at 19 */ ++}; ++static asn_SEQUENCE_specifics_t asn_SPC_GKCurrentKeys_specs_1 = { ++ sizeof(struct GKCurrentKeys), ++ offsetof(struct GKCurrentKeys, _asn_ctx), ++ asn_MAP_GKCurrentKeys_tag2el_1, ++ 1, /* Count of tags in the map */ ++ 0, 0, 0, /* Optional elements (not needed) */ ++ -1, /* Start extensions */ ++ -1 /* Stop extensions */ ++}; ++asn_TYPE_descriptor_t asn_DEF_GKCurrentKeys = { ++ "GKCurrentKeys", ++ "GKCurrentKeys", ++ SEQUENCE_free, ++ SEQUENCE_print, ++ SEQUENCE_constraint, ++ SEQUENCE_decode_ber, ++ SEQUENCE_encode_der, ++ SEQUENCE_decode_xer, ++ SEQUENCE_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_GKCurrentKeys_tags_1, ++ sizeof(asn_DEF_GKCurrentKeys_tags_1) ++ /sizeof(asn_DEF_GKCurrentKeys_tags_1[0]), /* 1 */ ++ asn_DEF_GKCurrentKeys_tags_1, /* Same as above */ ++ sizeof(asn_DEF_GKCurrentKeys_tags_1) ++ /sizeof(asn_DEF_GKCurrentKeys_tags_1[0]), /* 1 */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_GKCurrentKeys_1, ++ 1, /* Elements count */ ++ &asn_SPC_GKCurrentKeys_specs_1 /* Additional specs */ ++}; ++ +diff --git a/asn1/asn1c/GKCurrentKeys.h b/asn1/asn1c/GKCurrentKeys.h +new file mode 100644 +index 0000000000000000000000000000000000000000..7ec4e4c60dd5c605bec311f713e33630dedaca58 +--- /dev/null ++++ b/asn1/asn1c/GKCurrentKeys.h +@@ -0,0 +1,37 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#ifndef _GKCurrentKeys_H_ ++#define _GKCurrentKeys_H_ ++ ++ ++#include ++ ++/* Including external dependencies */ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* GKCurrentKeys */ ++typedef struct GKCurrentKeys { ++ OCTET_STRING_t serviceIdentity; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++} GKCurrentKeys_t; ++ ++/* Implementation */ ++extern asn_TYPE_descriptor_t asn_DEF_GKCurrentKeys; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _GKCurrentKeys_H_ */ +diff --git a/asn1/asn1c/GKNewKeys.c b/asn1/asn1c/GKNewKeys.c +new file mode 100644 +index 0000000000000000000000000000000000000000..35ebcf245c25c02572377381ba3418f3f8488fd7 +--- /dev/null ++++ b/asn1/asn1c/GKNewKeys.c +@@ -0,0 +1,126 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#include ++ ++#include "GKNewKeys.h" ++ ++static asn_TYPE_member_t asn_MBR_enctypes_3[] = { ++ { ATF_POINTER, 0, 0, ++ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), ++ 0, ++ &asn_DEF_Int32, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "" ++ }, ++}; ++static ber_tlv_tag_t asn_DEF_enctypes_tags_3[] = { ++ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) ++}; ++static asn_SET_OF_specifics_t asn_SPC_enctypes_specs_3 = { ++ sizeof(struct enctypes), ++ offsetof(struct enctypes, _asn_ctx), ++ 0, /* XER encoding is XMLDelimitedItemList */ ++}; ++static /* Use -fall-defs-global to expose */ ++asn_TYPE_descriptor_t asn_DEF_enctypes_3 = { ++ "enctypes", ++ "enctypes", ++ SEQUENCE_OF_free, ++ SEQUENCE_OF_print, ++ SEQUENCE_OF_constraint, ++ SEQUENCE_OF_decode_ber, ++ SEQUENCE_OF_encode_der, ++ SEQUENCE_OF_decode_xer, ++ SEQUENCE_OF_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_enctypes_tags_3, ++ sizeof(asn_DEF_enctypes_tags_3) ++ /sizeof(asn_DEF_enctypes_tags_3[0]), /* 2 */ ++ asn_DEF_enctypes_tags_3, /* Same as above */ ++ sizeof(asn_DEF_enctypes_tags_3) ++ /sizeof(asn_DEF_enctypes_tags_3[0]), /* 2 */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_enctypes_3, ++ 1, /* Single element */ ++ &asn_SPC_enctypes_specs_3 /* Additional specs */ ++}; ++ ++static asn_TYPE_member_t asn_MBR_GKNewKeys_1[] = { ++ { ATF_NOFLAGS, 0, offsetof(struct GKNewKeys, serviceIdentity), ++ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_OCTET_STRING, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "serviceIdentity" ++ }, ++ { ATF_NOFLAGS, 0, offsetof(struct GKNewKeys, enctypes), ++ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_enctypes_3, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "enctypes" ++ }, ++ { ATF_POINTER, 1, offsetof(struct GKNewKeys, password), ++ (ASN_TAG_CLASS_CONTEXT | (2 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_OCTET_STRING, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "password" ++ }, ++}; ++static ber_tlv_tag_t asn_DEF_GKNewKeys_tags_1[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) ++}; ++static asn_TYPE_tag2member_t asn_MAP_GKNewKeys_tag2el_1[] = { ++ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* serviceIdentity at 13 */ ++ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* enctypes at 14 */ ++ { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* password at 15 */ ++}; ++static asn_SEQUENCE_specifics_t asn_SPC_GKNewKeys_specs_1 = { ++ sizeof(struct GKNewKeys), ++ offsetof(struct GKNewKeys, _asn_ctx), ++ asn_MAP_GKNewKeys_tag2el_1, ++ 3, /* Count of tags in the map */ ++ 0, 0, 0, /* Optional elements (not needed) */ ++ -1, /* Start extensions */ ++ -1 /* Stop extensions */ ++}; ++asn_TYPE_descriptor_t asn_DEF_GKNewKeys = { ++ "GKNewKeys", ++ "GKNewKeys", ++ SEQUENCE_free, ++ SEQUENCE_print, ++ SEQUENCE_constraint, ++ SEQUENCE_decode_ber, ++ SEQUENCE_encode_der, ++ SEQUENCE_decode_xer, ++ SEQUENCE_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_GKNewKeys_tags_1, ++ sizeof(asn_DEF_GKNewKeys_tags_1) ++ /sizeof(asn_DEF_GKNewKeys_tags_1[0]), /* 1 */ ++ asn_DEF_GKNewKeys_tags_1, /* Same as above */ ++ sizeof(asn_DEF_GKNewKeys_tags_1) ++ /sizeof(asn_DEF_GKNewKeys_tags_1[0]), /* 1 */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_GKNewKeys_1, ++ 3, /* Elements count */ ++ &asn_SPC_GKNewKeys_specs_1 /* Additional specs */ ++}; ++ +diff --git a/asn1/asn1c/GKNewKeys.h b/asn1/asn1c/GKNewKeys.h +new file mode 100644 +index 0000000000000000000000000000000000000000..2cd158dff9c36cd6f632448235e889f3c8ab937f +--- /dev/null ++++ b/asn1/asn1c/GKNewKeys.h +@@ -0,0 +1,47 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#ifndef _GKNewKeys_H_ ++#define _GKNewKeys_H_ ++ ++ ++#include ++ ++/* Including external dependencies */ ++#include ++#include "Int32.h" ++#include ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* GKNewKeys */ ++typedef struct GKNewKeys { ++ OCTET_STRING_t serviceIdentity; ++ struct enctypes { ++ A_SEQUENCE_OF(Int32_t) list; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++ } enctypes; ++ OCTET_STRING_t *password /* OPTIONAL */; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++} GKNewKeys_t; ++ ++/* Implementation */ ++extern asn_TYPE_descriptor_t asn_DEF_GKNewKeys; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _GKNewKeys_H_ */ +diff --git a/asn1/asn1c/GKReply.c b/asn1/asn1c/GKReply.c +new file mode 100644 +index 0000000000000000000000000000000000000000..220c791e2d84b2ea9d889307403bc2b64781f3ce +--- /dev/null ++++ b/asn1/asn1c/GKReply.c +@@ -0,0 +1,115 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#include ++ ++#include "GKReply.h" ++ ++static asn_TYPE_member_t asn_MBR_keys_3[] = { ++ { ATF_POINTER, 0, 0, ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), ++ 0, ++ &asn_DEF_KrbKey, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "" ++ }, ++}; ++static ber_tlv_tag_t asn_DEF_keys_tags_3[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) ++}; ++static asn_SET_OF_specifics_t asn_SPC_keys_specs_3 = { ++ sizeof(struct keys), ++ offsetof(struct keys, _asn_ctx), ++ 0, /* XER encoding is XMLDelimitedItemList */ ++}; ++static /* Use -fall-defs-global to expose */ ++asn_TYPE_descriptor_t asn_DEF_keys_3 = { ++ "keys", ++ "keys", ++ SEQUENCE_OF_free, ++ SEQUENCE_OF_print, ++ SEQUENCE_OF_constraint, ++ SEQUENCE_OF_decode_ber, ++ SEQUENCE_OF_encode_der, ++ SEQUENCE_OF_decode_xer, ++ SEQUENCE_OF_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_keys_tags_3, ++ sizeof(asn_DEF_keys_tags_3) ++ /sizeof(asn_DEF_keys_tags_3[0]), /* 1 */ ++ asn_DEF_keys_tags_3, /* Same as above */ ++ sizeof(asn_DEF_keys_tags_3) ++ /sizeof(asn_DEF_keys_tags_3[0]), /* 1 */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_keys_3, ++ 1, /* Single element */ ++ &asn_SPC_keys_specs_3 /* Additional specs */ ++}; ++ ++static asn_TYPE_member_t asn_MBR_GKReply_1[] = { ++ { ATF_NOFLAGS, 0, offsetof(struct GKReply, newkvno), ++ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), ++ 0, ++ &asn_DEF_Int32, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "newkvno" ++ }, ++ { ATF_NOFLAGS, 0, offsetof(struct GKReply, keys), ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), ++ 0, ++ &asn_DEF_keys_3, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "keys" ++ }, ++}; ++static ber_tlv_tag_t asn_DEF_GKReply_tags_1[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) ++}; ++static asn_TYPE_tag2member_t asn_MAP_GKReply_tag2el_1[] = { ++ { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 0 }, /* newkvno at 23 */ ++ { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 1, 0, 0 } /* keys at 25 */ ++}; ++static asn_SEQUENCE_specifics_t asn_SPC_GKReply_specs_1 = { ++ sizeof(struct GKReply), ++ offsetof(struct GKReply, _asn_ctx), ++ asn_MAP_GKReply_tag2el_1, ++ 2, /* Count of tags in the map */ ++ 0, 0, 0, /* Optional elements (not needed) */ ++ -1, /* Start extensions */ ++ -1 /* Stop extensions */ ++}; ++asn_TYPE_descriptor_t asn_DEF_GKReply = { ++ "GKReply", ++ "GKReply", ++ SEQUENCE_free, ++ SEQUENCE_print, ++ SEQUENCE_constraint, ++ SEQUENCE_decode_ber, ++ SEQUENCE_encode_der, ++ SEQUENCE_decode_xer, ++ SEQUENCE_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_GKReply_tags_1, ++ sizeof(asn_DEF_GKReply_tags_1) ++ /sizeof(asn_DEF_GKReply_tags_1[0]), /* 1 */ ++ asn_DEF_GKReply_tags_1, /* Same as above */ ++ sizeof(asn_DEF_GKReply_tags_1) ++ /sizeof(asn_DEF_GKReply_tags_1[0]), /* 1 */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_GKReply_1, ++ 2, /* Elements count */ ++ &asn_SPC_GKReply_specs_1 /* Additional specs */ ++}; ++ +diff --git a/asn1/asn1c/GKReply.h b/asn1/asn1c/GKReply.h +new file mode 100644 +index 0000000000000000000000000000000000000000..7f058f6bf481ee2e570138f06fdef3d913949e9f +--- /dev/null ++++ b/asn1/asn1c/GKReply.h +@@ -0,0 +1,51 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#ifndef _GKReply_H_ ++#define _GKReply_H_ ++ ++ ++#include ++ ++/* Including external dependencies */ ++#include "Int32.h" ++#include ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Forward declarations */ ++struct KrbKey; ++ ++/* GKReply */ ++typedef struct GKReply { ++ Int32_t newkvno; ++ struct keys { ++ A_SEQUENCE_OF(struct KrbKey) list; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++ } keys; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++} GKReply_t; ++ ++/* Implementation */ ++extern asn_TYPE_descriptor_t asn_DEF_GKReply; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++/* Referred external types */ ++#include "KrbKey.h" ++ ++#endif /* _GKReply_H_ */ +diff --git a/asn1/asn1c/GetKeytabControl.c b/asn1/asn1c/GetKeytabControl.c +new file mode 100644 +index 0000000000000000000000000000000000000000..65b55d1ef34e31b81ef7b751608da4cc6c12020c +--- /dev/null ++++ b/asn1/asn1c/GetKeytabControl.c +@@ -0,0 +1,77 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#include ++ ++#include "GetKeytabControl.h" ++ ++static asn_TYPE_member_t asn_MBR_GetKeytabControl_1[] = { ++ { ATF_NOFLAGS, 0, offsetof(struct GetKeytabControl, choice.newkeys), ++ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_GKNewKeys, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "newkeys" ++ }, ++ { ATF_NOFLAGS, 0, offsetof(struct GetKeytabControl, choice.curkeys), ++ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_GKCurrentKeys, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "curkeys" ++ }, ++ { ATF_NOFLAGS, 0, offsetof(struct GetKeytabControl, choice.reply), ++ (ASN_TAG_CLASS_CONTEXT | (2 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_GKReply, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "reply" ++ }, ++}; ++static asn_TYPE_tag2member_t asn_MAP_GetKeytabControl_tag2el_1[] = { ++ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* newkeys at 7 */ ++ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* curkeys at 8 */ ++ { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* reply at 10 */ ++}; ++static asn_CHOICE_specifics_t asn_SPC_GetKeytabControl_specs_1 = { ++ sizeof(struct GetKeytabControl), ++ offsetof(struct GetKeytabControl, _asn_ctx), ++ offsetof(struct GetKeytabControl, present), ++ sizeof(((struct GetKeytabControl *)0)->present), ++ asn_MAP_GetKeytabControl_tag2el_1, ++ 3, /* Count of tags in the map */ ++ 0, ++ -1 /* Extensions start */ ++}; ++asn_TYPE_descriptor_t asn_DEF_GetKeytabControl = { ++ "GetKeytabControl", ++ "GetKeytabControl", ++ CHOICE_free, ++ CHOICE_print, ++ CHOICE_constraint, ++ CHOICE_decode_ber, ++ CHOICE_encode_der, ++ CHOICE_decode_xer, ++ CHOICE_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ CHOICE_outmost_tag, ++ 0, /* No effective tags (pointer) */ ++ 0, /* No effective tags (count) */ ++ 0, /* No tags (pointer) */ ++ 0, /* No tags (count) */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_GetKeytabControl_1, ++ 3, /* Elements count */ ++ &asn_SPC_GetKeytabControl_specs_1 /* Additional specs */ ++}; ++ +diff --git a/asn1/asn1c/GetKeytabControl.h b/asn1/asn1c/GetKeytabControl.h +new file mode 100644 +index 0000000000000000000000000000000000000000..5f5fcd22e74f65e9356be886520b8ddd3cac348c +--- /dev/null ++++ b/asn1/asn1c/GetKeytabControl.h +@@ -0,0 +1,52 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#ifndef _GetKeytabControl_H_ ++#define _GetKeytabControl_H_ ++ ++ ++#include ++ ++/* Including external dependencies */ ++#include "GKNewKeys.h" ++#include "GKCurrentKeys.h" ++#include "GKReply.h" ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Dependencies */ ++typedef enum GetKeytabControl_PR { ++ GetKeytabControl_PR_NOTHING, /* No components present */ ++ GetKeytabControl_PR_newkeys, ++ GetKeytabControl_PR_curkeys, ++ GetKeytabControl_PR_reply ++} GetKeytabControl_PR; ++ ++/* GetKeytabControl */ ++typedef struct GetKeytabControl { ++ GetKeytabControl_PR present; ++ union GetKeytabControl_u { ++ GKNewKeys_t newkeys; ++ GKCurrentKeys_t curkeys; ++ GKReply_t reply; ++ } choice; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++} GetKeytabControl_t; ++ ++/* Implementation */ ++extern asn_TYPE_descriptor_t asn_DEF_GetKeytabControl; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _GetKeytabControl_H_ */ +diff --git a/asn1/asn1c/INTEGER.c b/asn1/asn1c/INTEGER.c +new file mode 100644 +index 0000000000000000000000000000000000000000..9c8b9ed3a5d778c30185842ca04cc5d8f9ca058b +--- /dev/null ++++ b/asn1/asn1c/INTEGER.c +@@ -0,0 +1,835 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include /* Encoder and decoder of a primitive type */ ++#include ++ ++/* ++ * INTEGER basic type description. ++ */ ++static ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) ++}; ++asn_TYPE_descriptor_t asn_DEF_INTEGER = { ++ "INTEGER", ++ "INTEGER", ++ ASN__PRIMITIVE_TYPE_free, ++ INTEGER_print, ++ asn_generic_no_constraint, ++ ber_decode_primitive, ++ INTEGER_encode_der, ++ INTEGER_decode_xer, ++ INTEGER_encode_xer, ++ INTEGER_decode_uper, /* Unaligned PER decoder */ ++ INTEGER_encode_uper, /* Unaligned PER encoder */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_INTEGER_tags, ++ sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), ++ asn_DEF_INTEGER_tags, /* Same as above */ ++ sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), ++ 0, /* No PER visible constraints */ ++ 0, 0, /* No members */ ++ 0 /* No specifics */ ++}; ++ ++/* ++ * Encode INTEGER type using DER. ++ */ ++asn_enc_rval_t ++INTEGER_encode_der(asn_TYPE_descriptor_t *td, void *sptr, ++ int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ INTEGER_t *st = (INTEGER_t *)sptr; ++ ++ ASN_DEBUG("%s %s as INTEGER (tm=%d)", ++ cb?"Encoding":"Estimating", td->name, tag_mode); ++ ++ /* ++ * Canonicalize integer in the buffer. ++ * (Remove too long sign extension, remove some first 0x00 bytes) ++ */ ++ if(st->buf) { ++ uint8_t *buf = st->buf; ++ uint8_t *end1 = buf + st->size - 1; ++ int shift; ++ ++ /* Compute the number of superfluous leading bytes */ ++ for(; buf < end1; buf++) { ++ /* ++ * If the contents octets of an integer value encoding ++ * consist of more than one octet, then the bits of the ++ * first octet and bit 8 of the second octet: ++ * a) shall not all be ones; and ++ * b) shall not all be zero. ++ */ ++ switch(*buf) { ++ case 0x00: if((buf[1] & 0x80) == 0) ++ continue; ++ break; ++ case 0xff: if((buf[1] & 0x80)) ++ continue; ++ break; ++ } ++ break; ++ } ++ ++ /* Remove leading superfluous bytes from the integer */ ++ shift = buf - st->buf; ++ if(shift) { ++ uint8_t *nb = st->buf; ++ uint8_t *end; ++ ++ st->size -= shift; /* New size, minus bad bytes */ ++ end = nb + st->size; ++ ++ for(; nb < end; nb++, buf++) ++ *nb = *buf; ++ } ++ ++ } /* if(1) */ ++ ++ return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key); ++} ++ ++static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop); ++ ++/* ++ * INTEGER specific human-readable output. ++ */ ++static ssize_t ++INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { ++ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; ++ char scratch[32]; /* Enough for 64-bit integer */ ++ uint8_t *buf = st->buf; ++ uint8_t *buf_end = st->buf + st->size; ++ signed long accum; ++ ssize_t wrote = 0; ++ char *p; ++ int ret; ++ ++ /* ++ * Advance buf pointer until the start of the value's body. ++ * This will make us able to process large integers using simple case, ++ * when the actual value is small ++ * (0x0000000000abcdef would yield a fine 0x00abcdef) ++ */ ++ /* Skip the insignificant leading bytes */ ++ for(; buf < buf_end-1; buf++) { ++ switch(*buf) { ++ case 0x00: if((buf[1] & 0x80) == 0) continue; break; ++ case 0xff: if((buf[1] & 0x80) != 0) continue; break; ++ } ++ break; ++ } ++ ++ /* Simple case: the integer size is small */ ++ if((size_t)(buf_end - buf) <= sizeof(accum)) { ++ const asn_INTEGER_enum_map_t *el; ++ size_t scrsize; ++ char *scr; ++ ++ if(buf == buf_end) { ++ accum = 0; ++ } else { ++ accum = (*buf & 0x80) ? -1 : 0; ++ for(; buf < buf_end; buf++) ++ accum = (accum << 8) | *buf; ++ } ++ ++ el = INTEGER_map_value2enum(specs, accum); ++ if(el) { ++ scrsize = el->enum_len + 32; ++ scr = (char *)alloca(scrsize); ++ if(plainOrXER == 0) ++ ret = snprintf(scr, scrsize, ++ "%ld (%s)", accum, el->enum_name); ++ else ++ ret = snprintf(scr, scrsize, ++ "<%s/>", el->enum_name); ++ } else if(plainOrXER && specs && specs->strict_enumeration) { ++ ASN_DEBUG("ASN.1 forbids dealing with " ++ "unknown value of ENUMERATED type"); ++ errno = EPERM; ++ return -1; ++ } else { ++ scrsize = sizeof(scratch); ++ scr = scratch; ++ ret = snprintf(scr, scrsize, "%ld", accum); ++ } ++ assert(ret > 0 && (size_t)ret < scrsize); ++ return (cb(scr, ret, app_key) < 0) ? -1 : ret; ++ } else if(plainOrXER && specs && specs->strict_enumeration) { ++ /* ++ * Here and earlier, we cannot encode the ENUMERATED values ++ * if there is no corresponding identifier. ++ */ ++ ASN_DEBUG("ASN.1 forbids dealing with " ++ "unknown value of ENUMERATED type"); ++ errno = EPERM; ++ return -1; ++ } ++ ++ /* Output in the long xx:yy:zz... format */ ++ /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ ++ for(p = scratch; buf < buf_end; buf++) { ++ static const char *h2c = "0123456789ABCDEF"; ++ if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { ++ /* Flush buffer */ ++ if(cb(scratch, p - scratch, app_key) < 0) ++ return -1; ++ wrote += p - scratch; ++ p = scratch; ++ } ++ *p++ = h2c[*buf >> 4]; ++ *p++ = h2c[*buf & 0x0F]; ++ *p++ = 0x3a; /* ":" */ ++ } ++ if(p != scratch) ++ p--; /* Remove the last ":" */ ++ ++ wrote += p - scratch; ++ return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote; ++} ++ ++/* ++ * INTEGER specific human-readable output. ++ */ ++int ++INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ const INTEGER_t *st = (const INTEGER_t *)sptr; ++ ssize_t ret; ++ ++ (void)td; ++ (void)ilevel; ++ ++ if(!st || !st->buf) ++ ret = cb("", 8, app_key); ++ else ++ ret = INTEGER__dump(td, st, cb, app_key, 0); ++ ++ return (ret < 0) ? -1 : 0; ++} ++ ++struct e2v_key { ++ const char *start; ++ const char *stop; ++ asn_INTEGER_enum_map_t *vemap; ++ unsigned int *evmap; ++}; ++static int ++INTEGER__compar_enum2value(const void *kp, const void *am) { ++ const struct e2v_key *key = (const struct e2v_key *)kp; ++ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; ++ const char *ptr, *end, *name; ++ ++ /* Remap the element (sort by different criterion) */ ++ el = key->vemap + key->evmap[el - key->vemap]; ++ ++ /* Compare strings */ ++ for(ptr = key->start, end = key->stop, name = el->enum_name; ++ ptr < end; ptr++, name++) { ++ if(*ptr != *name) ++ return *(const unsigned char *)ptr ++ - *(const unsigned char *)name; ++ } ++ return name[0] ? -1 : 0; ++} ++ ++static const asn_INTEGER_enum_map_t * ++INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) { ++ asn_INTEGER_enum_map_t *el_found; ++ int count = specs ? specs->map_count : 0; ++ struct e2v_key key; ++ const char *lp; ++ ++ if(!count) return NULL; ++ ++ /* Guaranteed: assert(lstart < lstop); */ ++ /* Figure out the tag name */ ++ for(lstart++, lp = lstart; lp < lstop; lp++) { ++ switch(*lp) { ++ case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */ ++ case 0x2f: /* '/' */ case 0x3e: /* '>' */ ++ break; ++ default: ++ continue; ++ } ++ break; ++ } ++ if(lp == lstop) return NULL; /* No tag found */ ++ lstop = lp; ++ ++ key.start = lstart; ++ key.stop = lstop; ++ key.vemap = specs->value2enum; ++ key.evmap = specs->enum2value; ++ el_found = (asn_INTEGER_enum_map_t *)bsearch(&key, ++ specs->value2enum, count, sizeof(specs->value2enum[0]), ++ INTEGER__compar_enum2value); ++ if(el_found) { ++ /* Remap enum2value into value2enum */ ++ el_found = key.vemap + key.evmap[el_found - key.vemap]; ++ } ++ return el_found; ++} ++ ++static int ++INTEGER__compar_value2enum(const void *kp, const void *am) { ++ long a = *(const long *)kp; ++ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; ++ long b = el->nat_value; ++ if(a < b) return -1; ++ else if(a == b) return 0; ++ else return 1; ++} ++ ++const asn_INTEGER_enum_map_t * ++INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) { ++ int count = specs ? specs->map_count : 0; ++ if(!count) return 0; ++ return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum, ++ count, sizeof(specs->value2enum[0]), ++ INTEGER__compar_value2enum); ++} ++ ++static int ++INTEGER_st_prealloc(INTEGER_t *st, int min_size) { ++ void *p = MALLOC(min_size + 1); ++ if(p) { ++ void *b = st->buf; ++ st->size = 0; ++ st->buf = p; ++ FREEMEM(b); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++/* ++ * Decode the chunk of XML text encoding INTEGER. ++ */ ++static enum xer_pbd_rval ++INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { ++ INTEGER_t *st = (INTEGER_t *)sptr; ++ long sign = 1; ++ long value; ++ const char *lp; ++ const char *lstart = (const char *)chunk_buf; ++ const char *lstop = lstart + chunk_size; ++ enum { ++ ST_SKIPSPACE, ++ ST_SKIPSPHEX, ++ ST_WAITDIGITS, ++ ST_DIGITS, ++ ST_HEXDIGIT1, ++ ST_HEXDIGIT2, ++ ST_HEXCOLON, ++ ST_EXTRASTUFF ++ } state = ST_SKIPSPACE; ++ ++ if(chunk_size) ++ ASN_DEBUG("INTEGER body %d 0x%2x..0x%2x", ++ chunk_size, *lstart, lstop[-1]); ++ ++ /* ++ * We may have received a tag here. It will be processed inline. ++ * Use strtoul()-like code and serialize the result. ++ */ ++ for(value = 0, lp = lstart; lp < lstop; lp++) { ++ int lv = *lp; ++ switch(lv) { ++ case 0x09: case 0x0a: case 0x0d: case 0x20: ++ switch(state) { ++ case ST_SKIPSPACE: ++ case ST_SKIPSPHEX: ++ continue; ++ case ST_HEXCOLON: ++ if(xer_is_whitespace(lp, lstop - lp)) { ++ lp = lstop - 1; ++ continue; ++ } ++ break; ++ default: ++ break; ++ } ++ break; ++ case 0x2d: /* '-' */ ++ if(state == ST_SKIPSPACE) { ++ sign = -1; ++ state = ST_WAITDIGITS; ++ continue; ++ } ++ break; ++ case 0x2b: /* '+' */ ++ if(state == ST_SKIPSPACE) { ++ state = ST_WAITDIGITS; ++ continue; ++ } ++ break; ++ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: ++ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: ++ switch(state) { ++ case ST_DIGITS: break; ++ case ST_SKIPSPHEX: /* Fall through */ ++ case ST_HEXDIGIT1: ++ value = (lv - 0x30) << 4; ++ state = ST_HEXDIGIT2; ++ continue; ++ case ST_HEXDIGIT2: ++ value += (lv - 0x30); ++ state = ST_HEXCOLON; ++ st->buf[st->size++] = value; ++ continue; ++ case ST_HEXCOLON: ++ return XPBD_BROKEN_ENCODING; ++ default: ++ state = ST_DIGITS; ++ break; ++ } ++ ++ { ++ long new_value = value * 10; ++ ++ if(new_value / 10 != value) ++ /* Overflow */ ++ return XPBD_DECODER_LIMIT; ++ ++ value = new_value + (lv - 0x30); ++ /* Check for two's complement overflow */ ++ if(value < 0) { ++ /* Check whether it is a LONG_MIN */ ++ if(sign == -1 ++ && (unsigned long)value ++ == ~((unsigned long)-1 >> 1)) { ++ sign = 1; ++ } else { ++ /* Overflow */ ++ return XPBD_DECODER_LIMIT; ++ } ++ } ++ } ++ continue; ++ case 0x3c: /* '<' */ ++ if(state == ST_SKIPSPACE) { ++ const asn_INTEGER_enum_map_t *el; ++ el = INTEGER_map_enum2value( ++ (asn_INTEGER_specifics_t *) ++ td->specifics, lstart, lstop); ++ if(el) { ++ ASN_DEBUG("Found \"%s\" => %ld", ++ el->enum_name, el->nat_value); ++ state = ST_DIGITS; ++ value = el->nat_value; ++ lp = lstop - 1; ++ continue; ++ } ++ ASN_DEBUG("Unknown identifier for INTEGER"); ++ } ++ return XPBD_BROKEN_ENCODING; ++ case 0x3a: /* ':' */ ++ if(state == ST_HEXCOLON) { ++ /* This colon is expected */ ++ state = ST_HEXDIGIT1; ++ continue; ++ } else if(state == ST_DIGITS) { ++ /* The colon here means that we have ++ * decoded the first two hexadecimal ++ * places as a decimal value. ++ * Switch decoding mode. */ ++ ASN_DEBUG("INTEGER re-evaluate as hex form"); ++ if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) ++ return XPBD_SYSTEM_FAILURE; ++ state = ST_SKIPSPHEX; ++ lp = lstart - 1; ++ continue; ++ } else { ++ ASN_DEBUG("state %d at %d", state, lp - lstart); ++ break; ++ } ++ /* [A-Fa-f] */ ++ case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46: ++ case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: ++ switch(state) { ++ case ST_SKIPSPHEX: ++ case ST_SKIPSPACE: /* Fall through */ ++ case ST_HEXDIGIT1: ++ value = lv - ((lv < 0x61) ? 0x41 : 0x61); ++ value += 10; ++ value <<= 4; ++ state = ST_HEXDIGIT2; ++ continue; ++ case ST_HEXDIGIT2: ++ value += lv - ((lv < 0x61) ? 0x41 : 0x61); ++ value += 10; ++ st->buf[st->size++] = value; ++ state = ST_HEXCOLON; ++ continue; ++ case ST_DIGITS: ++ ASN_DEBUG("INTEGER re-evaluate as hex form"); ++ if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) ++ return XPBD_SYSTEM_FAILURE; ++ state = ST_SKIPSPHEX; ++ lp = lstart - 1; ++ continue; ++ default: ++ break; ++ } ++ break; ++ } ++ ++ /* Found extra non-numeric stuff */ ++ ASN_DEBUG("Found non-numeric 0x%2x at %d", ++ lv, lp - lstart); ++ state = ST_EXTRASTUFF; ++ break; ++ } ++ ++ switch(state) { ++ case ST_DIGITS: ++ /* Everything is cool */ ++ break; ++ case ST_HEXCOLON: ++ st->buf[st->size] = 0; /* Just in case termination */ ++ return XPBD_BODY_CONSUMED; ++ case ST_HEXDIGIT1: ++ case ST_HEXDIGIT2: ++ case ST_SKIPSPHEX: ++ return XPBD_BROKEN_ENCODING; ++ default: ++ if(xer_is_whitespace(lp, lstop - lp)) { ++ if(state != ST_EXTRASTUFF) ++ return XPBD_NOT_BODY_IGNORE; ++ break; ++ } else { ++ ASN_DEBUG("INTEGER: No useful digits (state %d)", ++ state); ++ return XPBD_BROKEN_ENCODING; /* No digits */ ++ } ++ break; ++ } ++ ++ value *= sign; /* Change sign, if needed */ ++ ++ if(asn_long2INTEGER(st, value)) ++ return XPBD_SYSTEM_FAILURE; ++ ++ return XPBD_BODY_CONSUMED; ++} ++ ++asn_dec_rval_t ++INTEGER_decode_xer(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, ++ const void *buf_ptr, size_t size) { ++ ++ return xer_decode_primitive(opt_codec_ctx, td, ++ sptr, sizeof(INTEGER_t), opt_mname, ++ buf_ptr, size, INTEGER__xer_body_decode); ++} ++ ++asn_enc_rval_t ++INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ const INTEGER_t *st = (const INTEGER_t *)sptr; ++ asn_enc_rval_t er; ++ ++ (void)ilevel; ++ (void)flags; ++ ++ if(!st || !st->buf) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = INTEGER__dump(td, st, cb, app_key, 1); ++ if(er.encoded < 0) _ASN_ENCODE_FAILED; ++ ++ _ASN_ENCODED_OK(er); ++} ++ ++asn_dec_rval_t ++INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_dec_rval_t rval = { RC_OK, 0 }; ++ INTEGER_t *st = (INTEGER_t *)*sptr; ++ asn_per_constraint_t *ct; ++ int repeat; ++ ++ (void)opt_codec_ctx; ++ ++ if(!st) { ++ st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ if(!constraints) constraints = td->per_constraints; ++ ct = constraints ? &constraints->value : 0; ++ ++ if(ct && ct->flags & APC_EXTENSIBLE) { ++ int inext = per_get_few_bits(pd, 1); ++ if(inext < 0) _ASN_DECODE_STARVED; ++ if(inext) ct = 0; ++ } ++ ++ FREEMEM(st->buf); ++ if(ct) { ++ if(ct->flags & APC_SEMI_CONSTRAINED) { ++ st->buf = (uint8_t *)CALLOC(1, 2); ++ if(!st->buf) _ASN_DECODE_FAILED; ++ st->size = 1; ++ } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { ++ size_t size = (ct->range_bits + 7) >> 3; ++ st->buf = (uint8_t *)MALLOC(1 + size + 1); ++ if(!st->buf) _ASN_DECODE_FAILED; ++ st->size = size; ++ } else { ++ st->size = 0; ++ } ++ } else { ++ st->size = 0; ++ } ++ ++ /* X.691, #12.2.2 */ ++ if(ct && ct->flags != APC_UNCONSTRAINED) { ++ /* #10.5.6 */ ++ ASN_DEBUG("Integer with range %d bits", ct->range_bits); ++ if(ct->range_bits >= 0) { ++ long value = per_get_few_bits(pd, ct->range_bits); ++ if(value < 0) _ASN_DECODE_STARVED; ++ ASN_DEBUG("Got value %ld + low %ld", ++ value, ct->lower_bound); ++ value += ct->lower_bound; ++ if(asn_long2INTEGER(st, value)) ++ _ASN_DECODE_FAILED; ++ return rval; ++ } ++ } else { ++ ASN_DEBUG("Decoding unconstrained integer %s", td->name); ++ } ++ ++ /* X.691, #12.2.3, #12.2.4 */ ++ do { ++ ssize_t len; ++ void *p; ++ int ret; ++ ++ /* Get the PER length */ ++ len = uper_get_length(pd, -1, &repeat); ++ if(len < 0) _ASN_DECODE_STARVED; ++ ++ p = REALLOC(st->buf, st->size + len + 1); ++ if(!p) _ASN_DECODE_FAILED; ++ st->buf = (uint8_t *)p; ++ ++ ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); ++ if(ret < 0) _ASN_DECODE_STARVED; ++ st->size += len; ++ } while(repeat); ++ st->buf[st->size] = 0; /* JIC */ ++ ++ /* #12.2.3 */ ++ if(ct && ct->lower_bound) { ++ /* ++ * TODO: replace by in-place arithmetics. ++ */ ++ long value; ++ if(asn_INTEGER2long(st, &value)) ++ _ASN_DECODE_FAILED; ++ if(asn_long2INTEGER(st, value + ct->lower_bound)) ++ _ASN_DECODE_FAILED; ++ } ++ ++ return rval; ++} ++ ++asn_enc_rval_t ++INTEGER_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_enc_rval_t er; ++ INTEGER_t *st = (INTEGER_t *)sptr; ++ const uint8_t *buf; ++ const uint8_t *end; ++ asn_per_constraint_t *ct; ++ long value = 0; ++ ++ if(!st || st->size == 0) _ASN_ENCODE_FAILED; ++ ++ if(!constraints) constraints = td->per_constraints; ++ ct = constraints ? &constraints->value : 0; ++ ++ er.encoded = 0; ++ ++ if(ct) { ++ int inext = 0; ++ if(asn_INTEGER2long(st, &value)) ++ _ASN_ENCODE_FAILED; ++ /* Check proper range */ ++ if(ct->flags & APC_SEMI_CONSTRAINED) { ++ if(value < ct->lower_bound) ++ inext = 1; ++ } else if(ct->range_bits >= 0) { ++ if(value < ct->lower_bound ++ || value > ct->upper_bound) ++ inext = 1; ++ } ++ ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", ++ value, st->buf[0], st->size, ++ ct->lower_bound, ct->upper_bound, ++ inext ? "ext" : "fix"); ++ if(ct->flags & APC_EXTENSIBLE) { ++ if(per_put_few_bits(po, inext, 1)) ++ _ASN_ENCODE_FAILED; ++ if(inext) ct = 0; ++ } else if(inext) { ++ _ASN_ENCODE_FAILED; ++ } ++ } ++ ++ ++ /* X.691, #12.2.2 */ ++ if(ct && ct->range_bits >= 0) { ++ /* #10.5.6 */ ++ ASN_DEBUG("Encoding integer with range %d bits", ++ ct->range_bits); ++ if(per_put_few_bits(po, value - ct->lower_bound, ++ ct->range_bits)) ++ _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ if(ct && ct->lower_bound) { ++ ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); ++ /* TODO: adjust lower bound */ ++ _ASN_ENCODE_FAILED; ++ } ++ ++ for(buf = st->buf, end = st->buf + st->size; buf < end;) { ++ ssize_t mayEncode = uper_put_length(po, end - buf); ++ if(mayEncode < 0) ++ _ASN_ENCODE_FAILED; ++ if(per_put_many_bits(po, buf, 8 * mayEncode)) ++ _ASN_ENCODE_FAILED; ++ buf += mayEncode; ++ } ++ ++ _ASN_ENCODED_OK(er); ++} ++ ++int ++asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { ++ uint8_t *b, *end; ++ size_t size; ++ long l; ++ ++ /* Sanity checking */ ++ if(!iptr || !iptr->buf || !lptr) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* Cache the begin/end of the buffer */ ++ b = iptr->buf; /* Start of the INTEGER buffer */ ++ size = iptr->size; ++ end = b + size; /* Where to stop */ ++ ++ if(size > sizeof(long)) { ++ uint8_t *end1 = end - 1; ++ /* ++ * Slightly more advanced processing, ++ * able to >sizeof(long) bytes, ++ * when the actual value is small ++ * (0x0000000000abcdef would yield a fine 0x00abcdef) ++ */ ++ /* Skip out the insignificant leading bytes */ ++ for(; b < end1; b++) { ++ switch(*b) { ++ case 0x00: if((b[1] & 0x80) == 0) continue; break; ++ case 0xff: if((b[1] & 0x80) != 0) continue; break; ++ } ++ break; ++ } ++ ++ size = end - b; ++ if(size > sizeof(long)) { ++ /* Still cannot fit the long */ ++ errno = ERANGE; ++ return -1; ++ } ++ } ++ ++ /* Shortcut processing of a corner case */ ++ if(end == b) { ++ *lptr = 0; ++ return 0; ++ } ++ ++ /* Perform the sign initialization */ ++ /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */ ++ if((*b >> 7)) l = -1; else l = 0; ++ ++ /* Conversion engine */ ++ for(; b < end; b++) ++ l = (l << 8) | *b; ++ ++ *lptr = l; ++ return 0; ++} ++ ++int ++asn_long2INTEGER(INTEGER_t *st, long value) { ++ uint8_t *buf, *bp; ++ uint8_t *p; ++ uint8_t *pstart; ++ uint8_t *pend1; ++ int littleEndian = 1; /* Run-time detection */ ++ int add; ++ ++ if(!st) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ buf = (uint8_t *)MALLOC(sizeof(value)); ++ if(!buf) return -1; ++ ++ if(*(char *)&littleEndian) { ++ pstart = (uint8_t *)&value + sizeof(value) - 1; ++ pend1 = (uint8_t *)&value; ++ add = -1; ++ } else { ++ pstart = (uint8_t *)&value; ++ pend1 = pstart + sizeof(value) - 1; ++ add = 1; ++ } ++ ++ /* ++ * If the contents octet consists of more than one octet, ++ * then bits of the first octet and bit 8 of the second octet: ++ * a) shall not all be ones; and ++ * b) shall not all be zero. ++ */ ++ for(p = pstart; p != pend1; p += add) { ++ switch(*p) { ++ case 0x00: if((*(p+add) & 0x80) == 0) ++ continue; ++ break; ++ case 0xff: if((*(p+add) & 0x80)) ++ continue; ++ break; ++ } ++ break; ++ } ++ /* Copy the integer body */ ++ for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add) ++ *bp++ = *p; ++ ++ if(st->buf) FREEMEM(st->buf); ++ st->buf = buf; ++ st->size = bp - buf; ++ ++ return 0; ++} +diff --git a/asn1/asn1c/INTEGER.h b/asn1/asn1c/INTEGER.h +new file mode 100644 +index 0000000000000000000000000000000000000000..62832b12e1271e1f27a5edd5b4a0f82986ff2fc3 +--- /dev/null ++++ b/asn1/asn1c/INTEGER.h +@@ -0,0 +1,65 @@ ++/*- ++ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _INTEGER_H_ ++#define _INTEGER_H_ ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; ++ ++extern asn_TYPE_descriptor_t asn_DEF_INTEGER; ++ ++/* Map with to integer value association */ ++typedef struct asn_INTEGER_enum_map_s { ++ long nat_value; /* associated native integer value */ ++ size_t enum_len; /* strlen("tag") */ ++ const char *enum_name; /* "tag" */ ++} asn_INTEGER_enum_map_t; ++ ++/* This type describes an enumeration for INTEGER and ENUMERATED types */ ++typedef struct asn_INTEGER_specifics_s { ++ asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ ++ unsigned int *enum2value; /* "tag" => N; sorted by tag */ ++ int map_count; /* Elements in either map */ ++ int extension; /* This map is extensible */ ++ int strict_enumeration; /* Enumeration set is fixed */ ++} asn_INTEGER_specifics_t; ++ ++asn_struct_print_f INTEGER_print; ++ber_type_decoder_f INTEGER_decode_ber; ++der_type_encoder_f INTEGER_encode_der; ++xer_type_decoder_f INTEGER_decode_xer; ++xer_type_encoder_f INTEGER_encode_xer; ++per_type_decoder_f INTEGER_decode_uper; ++per_type_encoder_f INTEGER_encode_uper; ++ ++/*********************************** ++ * Some handy conversion routines. * ++ ***********************************/ ++ ++/* ++ * Returns 0 if it was possible to convert, -1 otherwise. ++ * -1/EINVAL: Mandatory argument missing ++ * -1/ERANGE: Value encoded is out of range for long representation ++ * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). ++ */ ++int asn_INTEGER2long(const INTEGER_t *i, long *l); ++int asn_long2INTEGER(INTEGER_t *i, long l); ++ ++/* ++ * Convert the integer value into the corresponding enumeration map entry. ++ */ ++const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _INTEGER_H_ */ +diff --git a/asn1/asn1c/Int32.c b/asn1/asn1c/Int32.c +new file mode 100644 +index 0000000000000000000000000000000000000000..600934beed3fcff4527de4969c1d3effd272355e +--- /dev/null ++++ b/asn1/asn1c/Int32.c +@@ -0,0 +1,127 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#include ++ ++#include "Int32.h" ++ ++int ++Int32_constraint(asn_TYPE_descriptor_t *td, const void *sptr, ++ asn_app_constraint_failed_f *ctfailcb, void *app_key) { ++ long value; ++ ++ if(!sptr) { ++ _ASN_CTFAIL(app_key, td, sptr, ++ "%s: value not given (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++ ++ value = *(const long *)sptr; ++ ++ if((value >= -2147483648 && value <= 2147483647)) { ++ /* Constraint check succeeded */ ++ return 0; ++ } else { ++ _ASN_CTFAIL(app_key, td, sptr, ++ "%s: constraint failed (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++} ++ ++/* ++ * This type is implemented using NativeInteger, ++ * so here we adjust the DEF accordingly. ++ */ ++static void ++Int32_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { ++ td->free_struct = asn_DEF_NativeInteger.free_struct; ++ td->print_struct = asn_DEF_NativeInteger.print_struct; ++ td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; ++ td->der_encoder = asn_DEF_NativeInteger.der_encoder; ++ td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; ++ td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; ++ td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; ++ td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; ++ if(!td->per_constraints) ++ td->per_constraints = asn_DEF_NativeInteger.per_constraints; ++ td->elements = asn_DEF_NativeInteger.elements; ++ td->elements_count = asn_DEF_NativeInteger.elements_count; ++ td->specifics = asn_DEF_NativeInteger.specifics; ++} ++ ++void ++Int32_free(asn_TYPE_descriptor_t *td, ++ void *struct_ptr, int contents_only) { ++ Int32_1_inherit_TYPE_descriptor(td); ++ td->free_struct(td, struct_ptr, contents_only); ++} ++ ++int ++Int32_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, ++ int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { ++ Int32_1_inherit_TYPE_descriptor(td); ++ return td->print_struct(td, struct_ptr, ilevel, cb, app_key); ++} ++ ++asn_dec_rval_t ++Int32_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **structure, const void *bufptr, size_t size, int tag_mode) { ++ Int32_1_inherit_TYPE_descriptor(td); ++ return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); ++} ++ ++asn_enc_rval_t ++Int32_encode_der(asn_TYPE_descriptor_t *td, ++ void *structure, int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ Int32_1_inherit_TYPE_descriptor(td); ++ return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); ++} ++ ++asn_dec_rval_t ++Int32_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **structure, const char *opt_mname, const void *bufptr, size_t size) { ++ Int32_1_inherit_TYPE_descriptor(td); ++ return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); ++} ++ ++asn_enc_rval_t ++Int32_encode_xer(asn_TYPE_descriptor_t *td, void *structure, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ Int32_1_inherit_TYPE_descriptor(td); ++ return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); ++} ++ ++static ber_tlv_tag_t asn_DEF_Int32_tags_1[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) ++}; ++asn_TYPE_descriptor_t asn_DEF_Int32 = { ++ "Int32", ++ "Int32", ++ Int32_free, ++ Int32_print, ++ Int32_constraint, ++ Int32_decode_ber, ++ Int32_encode_der, ++ Int32_decode_xer, ++ Int32_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_Int32_tags_1, ++ sizeof(asn_DEF_Int32_tags_1) ++ /sizeof(asn_DEF_Int32_tags_1[0]), /* 1 */ ++ asn_DEF_Int32_tags_1, /* Same as above */ ++ sizeof(asn_DEF_Int32_tags_1) ++ /sizeof(asn_DEF_Int32_tags_1[0]), /* 1 */ ++ 0, /* No PER visible constraints */ ++ 0, 0, /* No members */ ++ 0 /* No specifics */ ++}; ++ +diff --git a/asn1/asn1c/Int32.h b/asn1/asn1c/Int32.h +new file mode 100644 +index 0000000000000000000000000000000000000000..9ee672ec9b5d49cfaddd2bf0bfb5ab2c5015d498 +--- /dev/null ++++ b/asn1/asn1c/Int32.h +@@ -0,0 +1,38 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#ifndef _Int32_H_ ++#define _Int32_H_ ++ ++ ++#include ++ ++/* Including external dependencies */ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Int32 */ ++typedef long Int32_t; ++ ++/* Implementation */ ++extern asn_TYPE_descriptor_t asn_DEF_Int32; ++asn_struct_free_f Int32_free; ++asn_struct_print_f Int32_print; ++asn_constr_check_f Int32_constraint; ++ber_type_decoder_f Int32_decode_ber; ++der_type_encoder_f Int32_encode_der; ++xer_type_decoder_f Int32_decode_xer; ++xer_type_encoder_f Int32_encode_xer; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _Int32_H_ */ +diff --git a/asn1/asn1c/KrbKey.c b/asn1/asn1c/KrbKey.c +new file mode 100644 +index 0000000000000000000000000000000000000000..3abbdf1b6e42ee759c149b6cbfa4b53695a2f0a3 +--- /dev/null ++++ b/asn1/asn1c/KrbKey.c +@@ -0,0 +1,81 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#include ++ ++#include "KrbKey.h" ++ ++static asn_TYPE_member_t asn_MBR_KrbKey_1[] = { ++ { ATF_NOFLAGS, 0, offsetof(struct KrbKey, key), ++ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_TypeValuePair, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "key" ++ }, ++ { ATF_POINTER, 2, offsetof(struct KrbKey, salt), ++ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_TypeValuePair, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "salt" ++ }, ++ { ATF_POINTER, 1, offsetof(struct KrbKey, s2kparams), ++ (ASN_TAG_CLASS_CONTEXT | (2 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_OCTET_STRING, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "s2kparams" ++ }, ++}; ++static ber_tlv_tag_t asn_DEF_KrbKey_tags_1[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) ++}; ++static asn_TYPE_tag2member_t asn_MAP_KrbKey_tag2el_1[] = { ++ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* key at 28 */ ++ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* salt at 29 */ ++ { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* s2kparams at 30 */ ++}; ++static asn_SEQUENCE_specifics_t asn_SPC_KrbKey_specs_1 = { ++ sizeof(struct KrbKey), ++ offsetof(struct KrbKey, _asn_ctx), ++ asn_MAP_KrbKey_tag2el_1, ++ 3, /* Count of tags in the map */ ++ 0, 0, 0, /* Optional elements (not needed) */ ++ -1, /* Start extensions */ ++ -1 /* Stop extensions */ ++}; ++asn_TYPE_descriptor_t asn_DEF_KrbKey = { ++ "KrbKey", ++ "KrbKey", ++ SEQUENCE_free, ++ SEQUENCE_print, ++ SEQUENCE_constraint, ++ SEQUENCE_decode_ber, ++ SEQUENCE_encode_der, ++ SEQUENCE_decode_xer, ++ SEQUENCE_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_KrbKey_tags_1, ++ sizeof(asn_DEF_KrbKey_tags_1) ++ /sizeof(asn_DEF_KrbKey_tags_1[0]), /* 1 */ ++ asn_DEF_KrbKey_tags_1, /* Same as above */ ++ sizeof(asn_DEF_KrbKey_tags_1) ++ /sizeof(asn_DEF_KrbKey_tags_1[0]), /* 1 */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_KrbKey_1, ++ 3, /* Elements count */ ++ &asn_SPC_KrbKey_specs_1 /* Additional specs */ ++}; ++ +diff --git a/asn1/asn1c/KrbKey.h b/asn1/asn1c/KrbKey.h +new file mode 100644 +index 0000000000000000000000000000000000000000..3134be528d1b9848b17d5eaee941aeef6fbd91b6 +--- /dev/null ++++ b/asn1/asn1c/KrbKey.h +@@ -0,0 +1,46 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#ifndef _KrbKey_H_ ++#define _KrbKey_H_ ++ ++ ++#include ++ ++/* Including external dependencies */ ++#include "TypeValuePair.h" ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Forward declarations */ ++struct TypeValuePair; ++ ++/* KrbKey */ ++typedef struct KrbKey { ++ TypeValuePair_t key; ++ struct TypeValuePair *salt /* OPTIONAL */; ++ OCTET_STRING_t *s2kparams /* OPTIONAL */; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++} KrbKey_t; ++ ++/* Implementation */ ++extern asn_TYPE_descriptor_t asn_DEF_KrbKey; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++/* Referred external types */ ++#include "TypeValuePair.h" ++ ++#endif /* _KrbKey_H_ */ +diff --git a/asn1/asn1c/Makefile.am b/asn1/asn1c/Makefile.am +new file mode 100644 +index 0000000000000000000000000000000000000000..e4ed6ab79fa776131b5baaaf7b5d254850c966c2 +--- /dev/null ++++ b/asn1/asn1c/Makefile.am +@@ -0,0 +1,93 @@ ++NULL = ++ ++ASN1C_SOURCES = \ ++ INTEGER.c \ ++ NativeEnumerated.c \ ++ NativeInteger.c \ ++ asn_SEQUENCE_OF.c \ ++ asn_SET_OF.c \ ++ constr_CHOICE.c \ ++ constr_SEQUENCE.c \ ++ constr_SEQUENCE_OF.c \ ++ constr_SET_OF.c \ ++ OCTET_STRING.c \ ++ BIT_STRING.c \ ++ asn_codecs_prim.c \ ++ ber_tlv_length.c \ ++ ber_tlv_tag.c \ ++ ber_decoder.c \ ++ der_encoder.c \ ++ constr_TYPE.c \ ++ constraints.c \ ++ xer_support.c \ ++ xer_decoder.c \ ++ xer_encoder.c \ ++ per_support.c \ ++ per_decoder.c \ ++ per_encoder.c \ ++ $(NULL) ++ ++ASN1C_HEADERS = ++ INTEGER.h \ ++ NativeEnumerated.h \ ++ NativeInteger.h \ ++ asn_SEQUENCE_OF.h \ ++ asn_SET_OF.h \ ++ constr_CHOICE.h \ ++ constr_SEQUENCE.h \ ++ constr_SEQUENCE_OF.h \ ++ constr_SET_OF.h \ ++ asn_application.h \ ++ asn_system.h \ ++ asn_codecs.h \ ++ asn_internal.h \ ++ OCTET_STRING.h \ ++ BIT_STRING.h \ ++ asn_codecs_prim.h \ ++ ber_tlv_length.h \ ++ ber_tlv_tag.h \ ++ ber_decoder.h \ ++ der_encoder.h \ ++ constr_TYPE.h \ ++ constraints.h \ ++ xer_support.h \ ++ xer_decoder.h \ ++ xer_encoder.h \ ++ per_support.h \ ++ per_decoder.h \ ++ per_encoder.h \ ++ $(NULL) ++ ++ASN1Cdir = . ++ ++IPAASN1_SOURCES= \ ++ Int32.c \ ++ GetKeytabControl.c \ ++ GKNewKeys.c \ ++ GKCurrentKeys.c \ ++ GKReply.c \ ++ KrbKey.c \ ++ TypeValuePair.c \ ++ $(NULL) ++ ++IPAASN1_HEADERS= \ ++ Int32.h \ ++ GetKeytabControl.h \ ++ GKNewKeys.h \ ++ GKCurrentKeys.h \ ++ GKReply.h \ ++ KrbKey.h \ ++ TypeValuePair.h \ ++ $(NULL) ++ ++IPAASN1dir = . ++ ++AM_CPPFLAGS = -I../../util ++ ++noinst_LTLIBRARIES=libasn1c.la ++noinst_HEADERS=$(ASN1C_HEADERS) $(IPAASN1_HEADERS) ++libasn1c_la_SOURCES=$(ASN1C_SOURCES) $(IPAASN1_SOURCES) ++ ++regenerate: ++ asn1c -fskeletons-copy -fnative-types ipa.asn1 ++ rm -f converter-sample.c Makefile.am.sample +diff --git a/asn1/asn1c/NativeEnumerated.c b/asn1/asn1c/NativeEnumerated.c +new file mode 100644 +index 0000000000000000000000000000000000000000..e3af1ca49b2c722513876e70219bb0ac8e74cbd9 +--- /dev/null ++++ b/asn1/asn1c/NativeEnumerated.c +@@ -0,0 +1,204 @@ ++/*- ++ * Copyright (c) 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * Read the NativeInteger.h for the explanation wrt. differences between ++ * INTEGER and NativeInteger. ++ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this ++ * implementation deals with the standard (machine-specific) representation ++ * of them instead of using the platform-independent buffer. ++ */ ++#include ++#include ++ ++/* ++ * NativeEnumerated basic type description. ++ */ ++static ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (10 << 2)) ++}; ++asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { ++ "ENUMERATED", /* The ASN.1 type is still ENUMERATED */ ++ "ENUMERATED", ++ NativeInteger_free, ++ NativeInteger_print, ++ asn_generic_no_constraint, ++ NativeInteger_decode_ber, ++ NativeInteger_encode_der, ++ NativeInteger_decode_xer, ++ NativeEnumerated_encode_xer, ++ NativeEnumerated_decode_uper, ++ NativeEnumerated_encode_uper, ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_NativeEnumerated_tags, ++ sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), ++ asn_DEF_NativeEnumerated_tags, /* Same as above */ ++ sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), ++ 0, /* No PER visible constraints */ ++ 0, 0, /* No members */ ++ 0 /* No specifics */ ++}; ++ ++asn_enc_rval_t ++NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ const long *native = (const long *)sptr; ++ const asn_INTEGER_enum_map_t *el; ++ ++ (void)ilevel; ++ (void)flags; ++ ++ if(!native) _ASN_ENCODE_FAILED; ++ ++ el = INTEGER_map_value2enum(specs, *native); ++ if(el) { ++ size_t srcsize = el->enum_len + 5; ++ char *src = (char *)alloca(srcsize); ++ ++ er.encoded = snprintf(src, srcsize, "<%s/>", el->enum_name); ++ assert(er.encoded > 0 && (size_t)er.encoded < srcsize); ++ if(cb(src, er.encoded, app_key) < 0) _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } else { ++ ASN_DEBUG("ASN.1 forbids dealing with " ++ "unknown value of ENUMERATED type"); ++ _ASN_ENCODE_FAILED; ++ } ++} ++ ++asn_dec_rval_t ++NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, ++ void **sptr, asn_per_data_t *pd) { ++ asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; ++ asn_dec_rval_t rval = { RC_OK, 0 }; ++ long *native = (long *)*sptr; ++ asn_per_constraint_t *ct; ++ long value; ++ ++ (void)opt_codec_ctx; ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else _ASN_DECODE_FAILED; /* Mandatory! */ ++ if(!specs) _ASN_DECODE_FAILED; ++ ++ if(!native) { ++ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); ++ if(!native) _ASN_DECODE_FAILED; ++ } ++ ++ ASN_DEBUG("Decoding %s as NativeEnumerated", td->name); ++ ++ if(ct->flags & APC_EXTENSIBLE) { ++ int inext = per_get_few_bits(pd, 1); ++ if(inext < 0) _ASN_DECODE_STARVED; ++ if(inext) ct = 0; ++ } ++ ++ if(ct && ct->range_bits >= 0) { ++ value = per_get_few_bits(pd, ct->range_bits); ++ if(value < 0) _ASN_DECODE_STARVED; ++ if(value >= (specs->extension ++ ? specs->extension - 1 : specs->map_count)) ++ _ASN_DECODE_FAILED; ++ } else { ++ if(!specs->extension) ++ _ASN_DECODE_FAILED; ++ /* ++ * X.691, #10.6: normally small non-negative whole number; ++ */ ++ value = uper_get_nsnnwn(pd); ++ if(value < 0) _ASN_DECODE_STARVED; ++ value += specs->extension - 1; ++ if(value >= specs->map_count) ++ _ASN_DECODE_FAILED; ++ } ++ ++ *native = specs->value2enum[value].nat_value; ++ ASN_DEBUG("Decoded %s = %ld", td->name, *native); ++ ++ return rval; ++} ++ ++static int ++NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { ++ const asn_INTEGER_enum_map_t *a = ap; ++ const asn_INTEGER_enum_map_t *b = bp; ++ if(a->nat_value == b->nat_value) ++ return 0; ++ if(a->nat_value < b->nat_value) ++ return -1; ++ return 1; ++} ++ ++asn_enc_rval_t ++NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ long native, value; ++ asn_per_constraint_t *ct; ++ int inext = 0; ++ asn_INTEGER_enum_map_t key; ++ asn_INTEGER_enum_map_t *kf; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ if(!specs) _ASN_ENCODE_FAILED; ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else _ASN_ENCODE_FAILED; /* Mandatory! */ ++ ++ ASN_DEBUG("Encoding %s as NativeEnumerated", td->name); ++ ++ er.encoded = 0; ++ ++ native = *(long *)sptr; ++ if(native < 0) _ASN_ENCODE_FAILED; ++ ++ key.nat_value = native; ++ kf = bsearch(&key, specs->value2enum, specs->map_count, ++ sizeof(key), NativeEnumerated__compar_value2enum); ++ if(!kf) { ++ ASN_DEBUG("No element corresponds to %ld", native); ++ _ASN_ENCODE_FAILED; ++ } ++ value = kf - specs->value2enum; ++ ++ if(ct->range_bits >= 0) { ++ int cmpWith = specs->extension ++ ? specs->extension - 1 : specs->map_count; ++ if(value >= cmpWith) ++ inext = 1; ++ } ++ if(ct->flags & APC_EXTENSIBLE) { ++ if(per_put_few_bits(po, inext, 0)) ++ _ASN_ENCODE_FAILED; ++ ct = 0; ++ } else if(inext) { ++ _ASN_ENCODE_FAILED; ++ } ++ ++ if(ct && ct->range_bits >= 0) { ++ if(per_put_few_bits(po, value, ct->range_bits)) ++ _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ if(!specs->extension) ++ _ASN_ENCODE_FAILED; ++ ++ /* ++ * X.691, #10.6: normally small non-negative whole number; ++ */ ++ if(uper_put_nsnnwn(po, value - (specs->extension - 1))) ++ _ASN_ENCODE_FAILED; ++ ++ _ASN_ENCODED_OK(er); ++} ++ +diff --git a/asn1/asn1c/NativeEnumerated.h b/asn1/asn1c/NativeEnumerated.h +new file mode 100644 +index 0000000000000000000000000000000000000000..c59bb1ba9438f85d3c42c99bba3a02aa917f0837 +--- /dev/null ++++ b/asn1/asn1c/NativeEnumerated.h +@@ -0,0 +1,32 @@ ++/*- ++ * Copyright (c) 2004, 2005, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * This type differs from the standard ENUMERATED in that it is modelled using ++ * the fixed machine type (long, int, short), so it can hold only values of ++ * limited length. There is no type (i.e., NativeEnumerated_t, any integer type ++ * will do). ++ * This type may be used when integer range is limited by subtype constraints. ++ */ ++#ifndef _NativeEnumerated_H_ ++#define _NativeEnumerated_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; ++ ++xer_type_encoder_f NativeEnumerated_encode_xer; ++per_type_decoder_f NativeEnumerated_decode_uper; ++per_type_encoder_f NativeEnumerated_encode_uper; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _NativeEnumerated_H_ */ +diff --git a/asn1/asn1c/NativeInteger.c b/asn1/asn1c/NativeInteger.c +new file mode 100644 +index 0000000000000000000000000000000000000000..34599f6186cd77d38106e171ec3b24cb29638afa +--- /dev/null ++++ b/asn1/asn1c/NativeInteger.c +@@ -0,0 +1,314 @@ ++/*- ++ * Copyright (c) 2004, 2005, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * Read the NativeInteger.h for the explanation wrt. differences between ++ * INTEGER and NativeInteger. ++ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this ++ * implementation deals with the standard (machine-specific) representation ++ * of them instead of using the platform-independent buffer. ++ */ ++#include ++#include ++ ++/* ++ * NativeInteger basic type description. ++ */ ++static ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) ++}; ++asn_TYPE_descriptor_t asn_DEF_NativeInteger = { ++ "INTEGER", /* The ASN.1 type is still INTEGER */ ++ "INTEGER", ++ NativeInteger_free, ++ NativeInteger_print, ++ asn_generic_no_constraint, ++ NativeInteger_decode_ber, ++ NativeInteger_encode_der, ++ NativeInteger_decode_xer, ++ NativeInteger_encode_xer, ++ NativeInteger_decode_uper, /* Unaligned PER decoder */ ++ NativeInteger_encode_uper, /* Unaligned PER encoder */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_NativeInteger_tags, ++ sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), ++ asn_DEF_NativeInteger_tags, /* Same as above */ ++ sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), ++ 0, /* No PER visible constraints */ ++ 0, 0, /* No members */ ++ 0 /* No specifics */ ++}; ++ ++/* ++ * Decode INTEGER type. ++ */ ++asn_dec_rval_t ++NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, ++ void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) { ++ long *native = (long *)*nint_ptr; ++ asn_dec_rval_t rval; ++ ber_tlv_len_t length; ++ ++ /* ++ * If the structure is not there, allocate it. ++ */ ++ if(native == NULL) { ++ native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); ++ if(native == NULL) { ++ rval.code = RC_FAIL; ++ rval.consumed = 0; ++ return rval; ++ } ++ } ++ ++ ASN_DEBUG("Decoding %s as INTEGER (tm=%d)", ++ td->name, tag_mode); ++ ++ /* ++ * Check tags. ++ */ ++ rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, ++ tag_mode, 0, &length, 0); ++ if(rval.code != RC_OK) ++ return rval; ++ ++ ASN_DEBUG("%s length is %d bytes", td->name, (int)length); ++ ++ /* ++ * Make sure we have this length. ++ */ ++ buf_ptr = ((const char *)buf_ptr) + rval.consumed; ++ size -= rval.consumed; ++ if(length > (ber_tlv_len_t)size) { ++ rval.code = RC_WMORE; ++ rval.consumed = 0; ++ return rval; ++ } ++ ++ /* ++ * ASN.1 encoded INTEGER: buf_ptr, length ++ * Fill the native, at the same time checking for overflow. ++ * If overflow occured, return with RC_FAIL. ++ */ ++ { ++ INTEGER_t tmp; ++ union { ++ const void *constbuf; ++ void *nonconstbuf; ++ } unconst_buf; ++ long l; ++ ++ unconst_buf.constbuf = buf_ptr; ++ tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; ++ tmp.size = length; ++ ++ if(asn_INTEGER2long(&tmp, &l)) { ++ rval.code = RC_FAIL; ++ rval.consumed = 0; ++ return rval; ++ } ++ ++ *native = l; ++ } ++ ++ rval.code = RC_OK; ++ rval.consumed += length; ++ ++ ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)", ++ (long)rval.consumed, (long)length, td->name, (long)*native); ++ ++ return rval; ++} ++ ++/* ++ * Encode the NativeInteger using the standard INTEGER type DER encoder. ++ */ ++asn_enc_rval_t ++NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr, ++ int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ unsigned long native = *(unsigned long *)ptr; /* Disable sign ext. */ ++ asn_enc_rval_t erval; ++ INTEGER_t tmp; ++ ++#ifdef WORDS_BIGENDIAN /* Opportunistic optimization */ ++ ++ tmp.buf = (uint8_t *)&native; ++ tmp.size = sizeof(native); ++ ++#else /* Works even if WORDS_BIGENDIAN is not set where should've been */ ++ uint8_t buf[sizeof(native)]; ++ uint8_t *p; ++ ++ /* Prepare a fake INTEGER */ ++ for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8) ++ *p = native; ++ ++ tmp.buf = buf; ++ tmp.size = sizeof(buf); ++#endif /* WORDS_BIGENDIAN */ ++ ++ /* Encode fake INTEGER */ ++ erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key); ++ if(erval.encoded == -1) { ++ assert(erval.structure_ptr == &tmp); ++ erval.structure_ptr = ptr; ++ } ++ return erval; ++} ++ ++/* ++ * Decode the chunk of XML text encoding INTEGER. ++ */ ++asn_dec_rval_t ++NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, ++ const void *buf_ptr, size_t size) { ++ asn_dec_rval_t rval; ++ INTEGER_t st; ++ void *st_ptr = (void *)&st; ++ long *native = (long *)*sptr; ++ ++ if(!native) { ++ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); ++ if(!native) _ASN_DECODE_FAILED; ++ } ++ ++ memset(&st, 0, sizeof(st)); ++ rval = INTEGER_decode_xer(opt_codec_ctx, td, &st_ptr, ++ opt_mname, buf_ptr, size); ++ if(rval.code == RC_OK) { ++ long l; ++ if(asn_INTEGER2long(&st, &l)) { ++ rval.code = RC_FAIL; ++ rval.consumed = 0; ++ } else { ++ *native = l; ++ } ++ } else { ++ /* ++ * Cannot restart from the middle; ++ * there is no place to save state in the native type. ++ * Request a continuation from the very beginning. ++ */ ++ rval.consumed = 0; ++ } ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &st); ++ return rval; ++} ++ ++ ++asn_enc_rval_t ++NativeInteger_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ char scratch[32]; /* Enough for 64-bit int */ ++ asn_enc_rval_t er; ++ const long *native = (const long *)sptr; ++ ++ (void)ilevel; ++ (void)flags; ++ ++ if(!native) _ASN_ENCODE_FAILED; ++ ++ er.encoded = snprintf(scratch, sizeof(scratch), "%ld", *native); ++ if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch) ++ || cb(scratch, er.encoded, app_key) < 0) ++ _ASN_ENCODE_FAILED; ++ ++ _ASN_ENCODED_OK(er); ++} ++ ++asn_dec_rval_t ++NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ ++ asn_dec_rval_t rval; ++ long *native = (long *)*sptr; ++ INTEGER_t tmpint; ++ void *tmpintptr = &tmpint; ++ ++ (void)opt_codec_ctx; ++ ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name); ++ ++ if(!native) { ++ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); ++ if(!native) _ASN_DECODE_FAILED; ++ } ++ ++ memset(&tmpint, 0, sizeof tmpint); ++ rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints, ++ &tmpintptr, pd); ++ if(rval.code == RC_OK) { ++ if(asn_INTEGER2long(&tmpint, native)) ++ rval.code = RC_FAIL; ++ else ++ ASN_DEBUG("NativeInteger %s got value %ld", ++ td->name, *native); ++ } ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); ++ ++ return rval; ++} ++ ++asn_enc_rval_t ++NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_enc_rval_t er; ++ long native; ++ INTEGER_t tmpint; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ ++ native = *(long *)sptr; ++ ++ ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); ++ ++ memset(&tmpint, 0, sizeof(tmpint)); ++ if(asn_long2INTEGER(&tmpint, native)) ++ _ASN_ENCODE_FAILED; ++ er = INTEGER_encode_uper(td, constraints, &tmpint, po); ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); ++ return er; ++} ++ ++/* ++ * INTEGER specific human-readable output. ++ */ ++int ++NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ const long *native = (const long *)sptr; ++ char scratch[32]; /* Enough for 64-bit int */ ++ int ret; ++ ++ (void)td; /* Unused argument */ ++ (void)ilevel; /* Unused argument */ ++ ++ if(native) { ++ ret = snprintf(scratch, sizeof(scratch), "%ld", *native); ++ assert(ret > 0 && (size_t)ret < sizeof(scratch)); ++ return (cb(scratch, ret, app_key) < 0) ? -1 : 0; ++ } else { ++ return (cb("", 8, app_key) < 0) ? -1 : 0; ++ } ++} ++ ++void ++NativeInteger_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { ++ ++ if(!td || !ptr) ++ return; ++ ++ ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)", ++ td->name, contents_only, ptr); ++ ++ if(!contents_only) { ++ FREEMEM(ptr); ++ } ++} ++ +diff --git a/asn1/asn1c/NativeInteger.h b/asn1/asn1c/NativeInteger.h +new file mode 100644 +index 0000000000000000000000000000000000000000..4e63a8355d12b7c90ce53a23a43cb5583f811257 +--- /dev/null ++++ b/asn1/asn1c/NativeInteger.h +@@ -0,0 +1,37 @@ ++/*- ++ * Copyright (c) 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * This type differs from the standard INTEGER in that it is modelled using ++ * the fixed machine type (long, int, short), so it can hold only values of ++ * limited length. There is no type (i.e., NativeInteger_t, any integer type ++ * will do). ++ * This type may be used when integer range is limited by subtype constraints. ++ */ ++#ifndef _NativeInteger_H_ ++#define _NativeInteger_H_ ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; ++ ++asn_struct_free_f NativeInteger_free; ++asn_struct_print_f NativeInteger_print; ++ber_type_decoder_f NativeInteger_decode_ber; ++der_type_encoder_f NativeInteger_encode_der; ++xer_type_decoder_f NativeInteger_decode_xer; ++xer_type_encoder_f NativeInteger_encode_xer; ++per_type_decoder_f NativeInteger_decode_uper; ++per_type_encoder_f NativeInteger_encode_uper; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _NativeInteger_H_ */ +diff --git a/asn1/asn1c/OCTET_STRING.c b/asn1/asn1c/OCTET_STRING.c +new file mode 100644 +index 0000000000000000000000000000000000000000..3a83bd98c5b30a10b5fb12b78bd4f317e8abb27a +--- /dev/null ++++ b/asn1/asn1c/OCTET_STRING.c +@@ -0,0 +1,1550 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include /* for .bits_unused member */ ++#include ++ ++/* ++ * OCTET STRING basic type description. ++ */ ++static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) ++}; ++static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { ++ sizeof(OCTET_STRING_t), ++ offsetof(OCTET_STRING_t, _asn_ctx), ++ 0 ++}; ++static asn_per_constraint_t asn_DEF_OCTET_STRING_constraint = { ++ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 ++}; ++asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { ++ "OCTET STRING", /* Canonical name */ ++ "OCTET_STRING", /* XML tag name */ ++ OCTET_STRING_free, ++ OCTET_STRING_print, /* non-ascii stuff, generally */ ++ asn_generic_no_constraint, ++ OCTET_STRING_decode_ber, ++ OCTET_STRING_encode_der, ++ OCTET_STRING_decode_xer_hex, ++ OCTET_STRING_encode_xer, ++ OCTET_STRING_decode_uper, /* Unaligned PER decoder */ ++ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_OCTET_STRING_tags, ++ sizeof(asn_DEF_OCTET_STRING_tags) ++ / sizeof(asn_DEF_OCTET_STRING_tags[0]), ++ asn_DEF_OCTET_STRING_tags, /* Same as above */ ++ sizeof(asn_DEF_OCTET_STRING_tags) ++ / sizeof(asn_DEF_OCTET_STRING_tags[0]), ++ 0, /* No PER visible constraints */ ++ 0, 0, /* No members */ ++ &asn_DEF_OCTET_STRING_specs ++}; ++ ++#undef _CH_PHASE ++#undef NEXT_PHASE ++#undef PREV_PHASE ++#define _CH_PHASE(ctx, inc) do { \ ++ if(ctx->phase == 0) \ ++ ctx->context = 0; \ ++ ctx->phase += inc; \ ++ } while(0) ++#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) ++#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) ++ ++#undef ADVANCE ++#define ADVANCE(num_bytes) do { \ ++ size_t num = (num_bytes); \ ++ buf_ptr = ((const char *)buf_ptr) + num; \ ++ size -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++#undef RETURN ++#define RETURN(_code) do { \ ++ asn_dec_rval_t tmprval; \ ++ tmprval.code = _code; \ ++ tmprval.consumed = consumed_myself; \ ++ return tmprval; \ ++ } while(0) ++ ++#undef APPEND ++#define APPEND(bufptr, bufsize) do { \ ++ size_t _bs = (bufsize); /* Append size */ \ ++ size_t _ns = ctx->context; /* Allocated now */ \ ++ size_t _es = st->size + _bs; /* Expected size */ \ ++ /* int is really a typeof(st->size): */ \ ++ if((int)_es < 0) RETURN(RC_FAIL); \ ++ if(_ns <= _es) { \ ++ void *ptr; \ ++ /* Be nice and round to the memory allocator */ \ ++ do { _ns = _ns ? _ns << 1 : 16; } \ ++ while(_ns <= _es); \ ++ /* int is really a typeof(st->size): */ \ ++ if((int)_ns < 0) RETURN(RC_FAIL); \ ++ ptr = REALLOC(st->buf, _ns); \ ++ if(ptr) { \ ++ st->buf = (uint8_t *)ptr; \ ++ ctx->context = _ns; \ ++ } else { \ ++ RETURN(RC_FAIL); \ ++ } \ ++ ASN_DEBUG("Reallocating into %ld", (long)_ns); \ ++ } \ ++ memcpy(st->buf + st->size, bufptr, _bs); \ ++ /* Convenient nul-termination */ \ ++ st->buf[_es] = '\0'; \ ++ st->size = _es; \ ++ } while(0) ++ ++/* ++ * Internal variant of the OCTET STRING. ++ */ ++typedef enum OS_type { ++ _TT_GENERIC = 0, /* Just a random OCTET STRING */ ++ _TT_BIT_STRING = 1, /* BIT STRING type, a special case */ ++ _TT_ANY = 2 /* ANY type, a special case too */ ++} OS_type_e; ++ ++/* ++ * The main reason why ASN.1 is still alive is that too much time and effort ++ * is necessary for learning it more or less adequately, thus creating a gut ++ * necessity to demonstrate that aquired skill everywhere afterwards. ++ * No, I am not going to explain what the following stuff is. ++ */ ++struct _stack_el { ++ ber_tlv_len_t left; /* What's left to read (or -1) */ ++ ber_tlv_len_t got; /* What was actually processed */ ++ int cont_level; /* Depth of subcontainment */ ++ int want_nulls; /* Want null "end of content" octets? */ ++ int bits_chopped; /* Flag in BIT STRING mode */ ++ ber_tlv_tag_t tag; /* For debugging purposes */ ++ struct _stack_el *prev; ++ struct _stack_el *next; ++}; ++struct _stack { ++ struct _stack_el *tail; ++ struct _stack_el *cur_ptr; ++}; ++ ++static struct _stack_el * ++OS__add_stack_el(struct _stack *st) { ++ struct _stack_el *nel; ++ ++ /* ++ * Reuse the old stack frame or allocate a new one. ++ */ ++ if(st->cur_ptr && st->cur_ptr->next) { ++ nel = st->cur_ptr->next; ++ nel->bits_chopped = 0; ++ nel->got = 0; ++ /* Retain the nel->cont_level, it's correct. */ ++ } else { ++ nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el)); ++ if(nel == NULL) ++ return NULL; ++ ++ if(st->tail) { ++ /* Increase a subcontainment depth */ ++ nel->cont_level = st->tail->cont_level + 1; ++ st->tail->next = nel; ++ } ++ nel->prev = st->tail; ++ st->tail = nel; ++ } ++ ++ st->cur_ptr = nel; ++ ++ return nel; ++} ++ ++static struct _stack * ++_new_stack() { ++ return (struct _stack *)CALLOC(1, sizeof(struct _stack)); ++} ++ ++/* ++ * Decode OCTET STRING type. ++ */ ++asn_dec_rval_t ++OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, ++ void **sptr, const void *buf_ptr, size_t size, int tag_mode) { ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ BIT_STRING_t *st = (BIT_STRING_t *)*sptr; ++ asn_dec_rval_t rval; ++ asn_struct_ctx_t *ctx; ++ ssize_t consumed_myself = 0; ++ struct _stack *stck; /* Expectations stack structure */ ++ struct _stack_el *sel = 0; /* Stack element */ ++ int tlv_constr; ++ OS_type_e type_variant = (OS_type_e)specs->subvariant; ++ ++ ASN_DEBUG("Decoding %s as %s (frame %ld)", ++ td->name, ++ (type_variant == _TT_GENERIC) ? ++ "OCTET STRING" : "OS-SpecialCase", ++ (long)size); ++ ++ /* ++ * Create the string if does not exist. ++ */ ++ if(st == NULL) { ++ st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); ++ if(st == NULL) RETURN(RC_FAIL); ++ } ++ ++ /* Restore parsing context */ ++ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); ++ ++ switch(ctx->phase) { ++ case 0: ++ /* ++ * Check tags. ++ */ ++ rval = ber_check_tags(opt_codec_ctx, td, ctx, ++ buf_ptr, size, tag_mode, -1, ++ &ctx->left, &tlv_constr); ++ if(rval.code != RC_OK) ++ return rval; ++ ++ if(tlv_constr) { ++ /* ++ * Complex operation, requires stack of expectations. ++ */ ++ ctx->ptr = _new_stack(); ++ if(ctx->ptr) { ++ stck = (struct _stack *)ctx->ptr; ++ } else { ++ RETURN(RC_FAIL); ++ } ++ } else { ++ /* ++ * Jump into stackless primitive decoding. ++ */ ++ _CH_PHASE(ctx, 3); ++ if(type_variant == _TT_ANY && tag_mode != 1) ++ APPEND(buf_ptr, rval.consumed); ++ ADVANCE(rval.consumed); ++ goto phase3; ++ } ++ ++ NEXT_PHASE(ctx); ++ /* Fall through */ ++ case 1: ++ phase1: ++ /* ++ * Fill the stack with expectations. ++ */ ++ stck = (struct _stack *)ctx->ptr; ++ sel = stck->cur_ptr; ++ do { ++ ber_tlv_tag_t tlv_tag; ++ ber_tlv_len_t tlv_len; ++ ber_tlv_tag_t expected_tag; ++ ssize_t tl, ll, tlvl; ++ /* This one works even if (sel->left == -1) */ ++ ssize_t Left = ((!sel||(size_t)sel->left >= size) ++ ?(ssize_t)size:sel->left); ++ ++ ++ ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel, ++ (long)(sel?sel->left:0), ++ (long)(sel?sel->want_nulls:0), ++ (long)(sel?sel->got:0) ++ ); ++ if(sel && sel->left <= 0 && sel->want_nulls == 0) { ++ if(sel->prev) { ++ struct _stack_el *prev = sel->prev; ++ if(prev->left != -1) { ++ if(prev->left < sel->got) ++ RETURN(RC_FAIL); ++ prev->left -= sel->got; ++ } ++ prev->got += sel->got; ++ sel = stck->cur_ptr = prev; ++ if(!sel) break; ++ tlv_constr = 1; ++ continue; ++ } else { ++ sel = stck->cur_ptr = 0; ++ break; /* Nothing to wait */ ++ } ++ } ++ ++ tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag); ++ ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld", ++ (long)size, (long)Left, sel?"":"!", ++ (long)(sel?sel->left:0), ++ (long)(sel?sel->want_nulls:0), ++ (long)tl); ++ switch(tl) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ } ++ ++ tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr); ++ ++ ll = ber_fetch_length(tlv_constr, ++ (const char *)buf_ptr + tl,Left - tl,&tlv_len); ++ ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld", ++ ber_tlv_tag_string(tlv_tag), tlv_constr, ++ (long)Left, (long)tl, (long)tlv_len, (long)ll); ++ switch(ll) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ } ++ ++ if(sel && sel->want_nulls ++ && ((const uint8_t *)buf_ptr)[0] == 0 ++ && ((const uint8_t *)buf_ptr)[1] == 0) ++ { ++ ++ ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); ++ ++ if(type_variant == _TT_ANY ++ && (tag_mode != 1 || sel->cont_level)) ++ APPEND("\0\0", 2); ++ ++ ADVANCE(2); ++ sel->got += 2; ++ if(sel->left != -1) { ++ sel->left -= 2; /* assert(sel->left >= 2) */ ++ } ++ ++ sel->want_nulls--; ++ if(sel->want_nulls == 0) { ++ /* Move to the next expectation */ ++ sel->left = 0; ++ tlv_constr = 1; ++ } ++ ++ continue; ++ } ++ ++ /* ++ * Set up expected tags, ++ * depending on ASN.1 type being decoded. ++ */ ++ switch(type_variant) { ++ case _TT_BIT_STRING: ++ /* X.690: 8.6.4.1, NOTE 2 */ ++ /* Fall through */ ++ case _TT_GENERIC: ++ default: ++ if(sel) { ++ int level = sel->cont_level; ++ if(level < td->all_tags_count) { ++ expected_tag = td->all_tags[level]; ++ break; ++ } else if(td->all_tags_count) { ++ expected_tag = td->all_tags ++ [td->all_tags_count - 1]; ++ break; ++ } ++ /* else, Fall through */ ++ } ++ /* Fall through */ ++ case _TT_ANY: ++ expected_tag = tlv_tag; ++ break; ++ } ++ ++ ++ if(tlv_tag != expected_tag) { ++ char buf[2][32]; ++ ber_tlv_tag_snprint(tlv_tag, ++ buf[0], sizeof(buf[0])); ++ ber_tlv_tag_snprint(td->tags[td->tags_count-1], ++ buf[1], sizeof(buf[1])); ++ ASN_DEBUG("Tag does not match expectation: %s != %s", ++ buf[0], buf[1]); ++ RETURN(RC_FAIL); ++ } ++ ++ tlvl = tl + ll; /* Combined length of T and L encoding */ ++ if((tlv_len + tlvl) < 0) { ++ /* tlv_len value is too big */ ++ ASN_DEBUG("TLV encoding + length (%ld) is too big", ++ (long)tlv_len); ++ RETURN(RC_FAIL); ++ } ++ ++ /* ++ * Append a new expectation. ++ */ ++ sel = OS__add_stack_el(stck); ++ if(!sel) RETURN(RC_FAIL); ++ ++ sel->tag = tlv_tag; ++ ++ sel->want_nulls = (tlv_len==-1); ++ if(sel->prev && sel->prev->left != -1) { ++ /* Check that the parent frame is big enough */ ++ if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len)) ++ RETURN(RC_FAIL); ++ if(tlv_len == -1) ++ sel->left = sel->prev->left - tlvl; ++ else ++ sel->left = tlv_len; ++ } else { ++ sel->left = tlv_len; ++ } ++ if(type_variant == _TT_ANY ++ && (tag_mode != 1 || sel->cont_level)) ++ APPEND(buf_ptr, tlvl); ++ sel->got += tlvl; ++ ADVANCE(tlvl); ++ ++ ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d", ++ (long)sel->got, (long)sel->left, ++ sel->want_nulls, sel->cont_level); ++ ++ } while(tlv_constr); ++ if(sel == NULL) { ++ /* Finished operation, "phase out" */ ++ ASN_DEBUG("Phase out"); ++ _CH_PHASE(ctx, +3); ++ break; ++ } ++ ++ NEXT_PHASE(ctx); ++ /* Fall through */ ++ case 2: ++ stck = (struct _stack *)ctx->ptr; ++ sel = stck->cur_ptr; ++ ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d", ++ (long)sel->left, (long)size, (long)sel->got, ++ sel->want_nulls); ++ { ++ ber_tlv_len_t len; ++ ++ assert(sel->left >= 0); ++ ++ len = ((ber_tlv_len_t)size < sel->left) ++ ? (ber_tlv_len_t)size : sel->left; ++ if(len > 0) { ++ if(type_variant == _TT_BIT_STRING ++ && sel->bits_chopped == 0) { ++ /* Put the unused-bits-octet away */ ++ st->bits_unused = *(const uint8_t *)buf_ptr; ++ APPEND(((const char *)buf_ptr+1), (len - 1)); ++ sel->bits_chopped = 1; ++ } else { ++ APPEND(buf_ptr, len); ++ } ++ ADVANCE(len); ++ sel->left -= len; ++ sel->got += len; ++ } ++ ++ if(sel->left) { ++ ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n", ++ (long)sel->left, (long)size, sel->want_nulls); ++ RETURN(RC_WMORE); ++ } ++ ++ PREV_PHASE(ctx); ++ goto phase1; ++ } ++ break; ++ case 3: ++ phase3: ++ /* ++ * Primitive form, no stack required. ++ */ ++ assert(ctx->left >= 0); ++ ++ if(size < (size_t)ctx->left) { ++ if(!size) RETURN(RC_WMORE); ++ if(type_variant == _TT_BIT_STRING && !ctx->context) { ++ st->bits_unused = *(const uint8_t *)buf_ptr; ++ ctx->left--; ++ ADVANCE(1); ++ } ++ APPEND(buf_ptr, size); ++ assert(ctx->context > 0); ++ ctx->left -= size; ++ ADVANCE(size); ++ RETURN(RC_WMORE); ++ } else { ++ if(type_variant == _TT_BIT_STRING ++ && !ctx->context && ctx->left) { ++ st->bits_unused = *(const uint8_t *)buf_ptr; ++ ctx->left--; ++ ADVANCE(1); ++ } ++ APPEND(buf_ptr, ctx->left); ++ ADVANCE(ctx->left); ++ ctx->left = 0; ++ ++ NEXT_PHASE(ctx); ++ } ++ break; ++ } ++ ++ if(sel) { ++ ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld", ++ sel->prev, sel->want_nulls, ++ (long)sel->left, (long)sel->got, (long)size); ++ if(sel->prev || sel->want_nulls > 1 || sel->left > 0) { ++ RETURN(RC_WMORE); ++ } ++ } ++ ++ /* ++ * BIT STRING-specific processing. ++ */ ++ if(type_variant == _TT_BIT_STRING && st->size) { ++ /* Finalize BIT STRING: zero out unused bits. */ ++ st->buf[st->size-1] &= 0xff << st->bits_unused; ++ } ++ ++ ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", ++ (long)consumed_myself, td->name, ++ (type_variant == _TT_GENERIC) ? (char *)st->buf : "", ++ (long)st->size); ++ ++ ++ RETURN(RC_OK); ++} ++ ++/* ++ * Encode OCTET STRING type using DER. ++ */ ++asn_enc_rval_t ++OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, ++ int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_enc_rval_t er; ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ BIT_STRING_t *st = (BIT_STRING_t *)sptr; ++ OS_type_e type_variant = (OS_type_e)specs->subvariant; ++ int fix_last_byte = 0; ++ ++ ASN_DEBUG("%s %s as OCTET STRING", ++ cb?"Estimating":"Encoding", td->name); ++ ++ /* ++ * Write tags. ++ */ ++ if(type_variant != _TT_ANY || tag_mode == 1) { ++ er.encoded = der_write_tags(td, ++ (type_variant == _TT_BIT_STRING) + st->size, ++ tag_mode, type_variant == _TT_ANY, tag, cb, app_key); ++ if(er.encoded == -1) { ++ er.failed_type = td; ++ er.structure_ptr = sptr; ++ return er; ++ } ++ } else { ++ /* Disallow: [] IMPLICIT ANY */ ++ assert(type_variant != _TT_ANY || tag_mode != -1); ++ er.encoded = 0; ++ } ++ ++ if(!cb) { ++ er.encoded += (type_variant == _TT_BIT_STRING) + st->size; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ /* ++ * Prepare to deal with the last octet of BIT STRING. ++ */ ++ if(type_variant == _TT_BIT_STRING) { ++ uint8_t b = st->bits_unused & 0x07; ++ if(b && st->size) fix_last_byte = 1; ++ _ASN_CALLBACK(&b, 1); ++ er.encoded++; ++ } ++ ++ /* Invoke callback for the main part of the buffer */ ++ _ASN_CALLBACK(st->buf, st->size - fix_last_byte); ++ ++ /* The last octet should be stripped off the unused bits */ ++ if(fix_last_byte) { ++ uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused); ++ _ASN_CALLBACK(&b, 1); ++ } ++ ++ er.encoded += st->size; ++ _ASN_ENCODED_OK(er); ++cb_failed: ++ _ASN_ENCODE_FAILED; ++} ++ ++asn_enc_rval_t ++OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ static const char *h2c = "0123456789ABCDEF"; ++ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; ++ asn_enc_rval_t er; ++ char scratch[16 * 3 + 4]; ++ char *p = scratch; ++ uint8_t *buf; ++ uint8_t *end; ++ size_t i; ++ ++ if(!st || !st->buf) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = 0; ++ ++ /* ++ * Dump the contents of the buffer in hexadecimal. ++ */ ++ buf = st->buf; ++ end = buf + st->size; ++ if(flags & XER_F_CANONICAL) { ++ char *scend = scratch + (sizeof(scratch) - 2); ++ for(; buf < end; buf++) { ++ if(p >= scend) { ++ _ASN_CALLBACK(scratch, p - scratch); ++ er.encoded += p - scratch; ++ p = scratch; ++ } ++ *p++ = h2c[(*buf >> 4) & 0x0F]; ++ *p++ = h2c[*buf & 0x0F]; ++ } ++ ++ _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ ++ er.encoded += p - scratch; ++ } else { ++ for(i = 0; buf < end; buf++, i++) { ++ if(!(i % 16) && (i || st->size > 16)) { ++ _ASN_CALLBACK(scratch, p-scratch); ++ er.encoded += (p-scratch); ++ p = scratch; ++ _i_ASN_TEXT_INDENT(1, ilevel); ++ } ++ *p++ = h2c[(*buf >> 4) & 0x0F]; ++ *p++ = h2c[*buf & 0x0F]; ++ *p++ = 0x20; ++ } ++ if(p - scratch) { ++ p--; /* Remove the tail space */ ++ _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ ++ er.encoded += p - scratch; ++ if(st->size > 16) ++ _i_ASN_TEXT_INDENT(1, ilevel-1); ++ } ++ } ++ ++ _ASN_ENCODED_OK(er); ++cb_failed: ++ _ASN_ENCODE_FAILED; ++} ++ ++static struct OCTET_STRING__xer_escape_table_s { ++ char *string; ++ int size; ++} OCTET_STRING__xer_escape_table[] = { ++#define OSXET(s) { s, sizeof(s) - 1 } ++ OSXET("\074\156\165\154\057\076"), /* */ ++ OSXET("\074\163\157\150\057\076"), /* */ ++ OSXET("\074\163\164\170\057\076"), /* */ ++ OSXET("\074\145\164\170\057\076"), /* */ ++ OSXET("\074\145\157\164\057\076"), /* */ ++ OSXET("\074\145\156\161\057\076"), /* */ ++ OSXET("\074\141\143\153\057\076"), /* */ ++ OSXET("\074\142\145\154\057\076"), /* */ ++ OSXET("\074\142\163\057\076"), /* */ ++ OSXET("\011"), /* \t */ ++ OSXET("\012"), /* \n */ ++ OSXET("\074\166\164\057\076"), /* */ ++ OSXET("\074\146\146\057\076"), /* */ ++ OSXET("\015"), /* \r */ ++ OSXET("\074\163\157\057\076"), /* */ ++ OSXET("\074\163\151\057\076"), /* */ ++ OSXET("\074\144\154\145\057\076"), /* */ ++ OSXET("\074\144\143\061\057\076"), /* */ ++ OSXET("\074\144\143\062\057\076"), /* */ ++ OSXET("\074\144\143\063\057\076"), /* */ ++ OSXET("\074\144\143\064\057\076"), /* */ ++ OSXET("\074\156\141\153\057\076"), /* */ ++ OSXET("\074\163\171\156\057\076"), /* */ ++ OSXET("\074\145\164\142\057\076"), /* */ ++ OSXET("\074\143\141\156\057\076"), /* */ ++ OSXET("\074\145\155\057\076"), /* */ ++ OSXET("\074\163\165\142\057\076"), /* */ ++ OSXET("\074\145\163\143\057\076"), /* */ ++ OSXET("\074\151\163\064\057\076"), /* */ ++ OSXET("\074\151\163\063\057\076"), /* */ ++ OSXET("\074\151\163\062\057\076"), /* */ ++ OSXET("\074\151\163\061\057\076"), /* */ ++ { 0, 0 }, /* " " */ ++ { 0, 0 }, /* ! */ ++ { 0, 0 }, /* \" */ ++ { 0, 0 }, /* # */ ++ { 0, 0 }, /* $ */ ++ { 0, 0 }, /* % */ ++ OSXET("\046\141\155\160\073"), /* & */ ++ { 0, 0 }, /* ' */ ++ {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */ ++ {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */ ++ {0,0},{0,0},{0,0},{0,0}, /* 89:; */ ++ OSXET("\046\154\164\073"), /* < */ ++ { 0, 0 }, /* = */ ++ OSXET("\046\147\164\073"), /* > */ ++}; ++ ++static int ++OS__check_escaped_control_char(const void *buf, int size) { ++ size_t i; ++ /* ++ * Inefficient algorithm which translates the escape sequences ++ * defined above into characters. Returns -1 if not found. ++ * TODO: replace by a faster algorithm (bsearch(), hash or ++ * nested table lookups). ++ */ ++ for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { ++ struct OCTET_STRING__xer_escape_table_s *el; ++ el = &OCTET_STRING__xer_escape_table[i]; ++ if(el->size == size && memcmp(buf, el->string, size) == 0) ++ return i; ++ } ++ return -1; ++} ++ ++static int ++OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) { ++ /* ++ * This might be one of the escape sequences ++ * for control characters. Check it out. ++ * #11.15.5 ++ */ ++ int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size); ++ if(control_char >= 0) { ++ OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr; ++ void *p = REALLOC(st->buf, st->size + 2); ++ if(p) { ++ st->buf = (uint8_t *)p; ++ st->buf[st->size++] = control_char; ++ st->buf[st->size] = '\0'; /* nul-termination */ ++ return 0; ++ } ++ } ++ ++ return -1; /* No, it's not */ ++} ++ ++asn_enc_rval_t ++OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; ++ asn_enc_rval_t er; ++ uint8_t *buf, *end; ++ uint8_t *ss; /* Sequence start */ ++ ssize_t encoded_len = 0; ++ ++ (void)ilevel; /* Unused argument */ ++ (void)flags; /* Unused argument */ ++ ++ if(!st || !st->buf) ++ _ASN_ENCODE_FAILED; ++ ++ buf = st->buf; ++ end = buf + st->size; ++ for(ss = buf; buf < end; buf++) { ++ unsigned int ch = *buf; ++ int s_len; /* Special encoding sequence length */ ++ ++ /* ++ * Escape certain characters: X.680/11.15 ++ */ ++ if(ch < sizeof(OCTET_STRING__xer_escape_table) ++ /sizeof(OCTET_STRING__xer_escape_table[0]) ++ && (s_len = OCTET_STRING__xer_escape_table[ch].size)) { ++ if(((buf - ss) && cb(ss, buf - ss, app_key) < 0) ++ || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, ++ app_key) < 0) ++ _ASN_ENCODE_FAILED; ++ encoded_len += (buf - ss) + s_len; ++ ss = buf + 1; ++ } ++ } ++ ++ encoded_len += (buf - ss); ++ if((buf - ss) && cb(ss, buf - ss, app_key) < 0) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = encoded_len; ++ _ASN_ENCODED_OK(er); ++} ++ ++/* ++ * Convert from hexadecimal format (cstring): "AB CD EF" ++ */ ++static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { ++ OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; ++ const char *chunk_stop = (const char *)chunk_buf; ++ const char *p = chunk_stop; ++ const char *pend = p + chunk_size; ++ unsigned int clv = 0; ++ int half = 0; /* Half bit */ ++ uint8_t *buf; ++ ++ /* Reallocate buffer according to high cap estimation */ ++ ssize_t _ns = st->size + (chunk_size + 1) / 2; ++ void *nptr = REALLOC(st->buf, _ns + 1); ++ if(!nptr) return -1; ++ st->buf = (uint8_t *)nptr; ++ buf = st->buf + st->size; ++ ++ /* ++ * If something like " a b c " appears here, the " a b":3 will be ++ * converted, and the rest skipped. That is, unless buf_size is greater ++ * than chunk_size, then it'll be equivalent to "ABC0". ++ */ ++ for(; p < pend; p++) { ++ int ch = *(const unsigned char *)p; ++ switch(ch) { ++ case 0x09: case 0x0a: case 0x0c: case 0x0d: ++ case 0x20: ++ /* Ignore whitespace */ ++ continue; ++ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ ++ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ ++ clv = (clv << 4) + (ch - 0x30); ++ break; ++ case 0x41: case 0x42: case 0x43: /* ABC */ ++ case 0x44: case 0x45: case 0x46: /* DEF */ ++ clv = (clv << 4) + (ch - 0x41 + 10); ++ break; ++ case 0x61: case 0x62: case 0x63: /* abc */ ++ case 0x64: case 0x65: case 0x66: /* def */ ++ clv = (clv << 4) + (ch - 0x61 + 10); ++ break; ++ default: ++ *buf = 0; /* JIC */ ++ return -1; ++ } ++ if(half++) { ++ half = 0; ++ *buf++ = clv; ++ chunk_stop = p + 1; ++ } ++ } ++ ++ /* ++ * Check partial decoding. ++ */ ++ if(half) { ++ if(have_more) { ++ /* ++ * Partial specification is fine, ++ * because no more more PXER_TEXT data is available. ++ */ ++ *buf++ = clv << 4; ++ chunk_stop = p; ++ } ++ } else { ++ chunk_stop = p; ++ } ++ ++ st->size = buf - st->buf; /* Adjust the buffer size */ ++ assert(st->size <= _ns); ++ st->buf[st->size] = 0; /* Courtesy termination */ ++ ++ return (chunk_stop - (const char *)chunk_buf); /* Converted size */ ++} ++ ++/* ++ * Convert from binary format: "00101011101" ++ */ ++static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { ++ BIT_STRING_t *st = (BIT_STRING_t *)sptr; ++ const char *p = (const char *)chunk_buf; ++ const char *pend = p + chunk_size; ++ int bits_unused = st->bits_unused & 0x7; ++ uint8_t *buf; ++ ++ /* Reallocate buffer according to high cap estimation */ ++ ssize_t _ns = st->size + (chunk_size + 7) / 8; ++ void *nptr = REALLOC(st->buf, _ns + 1); ++ if(!nptr) return -1; ++ st->buf = (uint8_t *)nptr; ++ buf = st->buf + st->size; ++ ++ (void)have_more; ++ ++ if(bits_unused == 0) ++ bits_unused = 8; ++ else if(st->size) ++ buf--; ++ ++ /* ++ * Convert series of 0 and 1 into the octet string. ++ */ ++ for(; p < pend; p++) { ++ int ch = *(const unsigned char *)p; ++ switch(ch) { ++ case 0x09: case 0x0a: case 0x0c: case 0x0d: ++ case 0x20: ++ /* Ignore whitespace */ ++ break; ++ case 0x30: ++ case 0x31: ++ if(bits_unused-- <= 0) { ++ *++buf = 0; /* Clean the cell */ ++ bits_unused = 7; ++ } ++ *buf |= (ch&1) << bits_unused; ++ break; ++ default: ++ st->bits_unused = bits_unused; ++ return -1; ++ } ++ } ++ ++ if(bits_unused == 8) { ++ st->size = buf - st->buf; ++ st->bits_unused = 0; ++ } else { ++ st->size = buf - st->buf + 1; ++ st->bits_unused = bits_unused; ++ } ++ ++ assert(st->size <= _ns); ++ st->buf[st->size] = 0; /* Courtesy termination */ ++ ++ return chunk_size; /* Converted in full */ ++} ++ ++/* ++ * Something like strtod(), but with stricter rules. ++ */ ++static int ++OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { ++ int32_t val = 0; ++ const char *p; ++ ++ for(p = buf; p < end; p++) { ++ int ch = *p; ++ ++ /* Strange huge value */ ++ if((val * base + base) < 0) ++ return -1; ++ ++ switch(ch) { ++ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ ++ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ ++ val = val * base + (ch - 0x30); ++ break; ++ case 0x41: case 0x42: case 0x43: /* ABC */ ++ case 0x44: case 0x45: case 0x46: /* DEF */ ++ val = val * base + (ch - 0x41 + 10); ++ break; ++ case 0x61: case 0x62: case 0x63: /* abc */ ++ case 0x64: case 0x65: case 0x66: /* def */ ++ val = val * base + (ch - 0x61 + 10); ++ break; ++ case 0x3b: /* ';' */ ++ *ret_value = val; ++ return (p - buf) + 1; ++ default: ++ return -1; /* Character set error */ ++ } ++ } ++ ++ *ret_value = -1; ++ return (p - buf); ++} ++ ++/* ++ * Convert from the plain UTF-8 format, expanding entity references: "2 < 3" ++ */ ++static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { ++ OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; ++ const char *p = (const char *)chunk_buf; ++ const char *pend = p + chunk_size; ++ uint8_t *buf; ++ ++ /* Reallocate buffer */ ++ ssize_t _ns = st->size + chunk_size; ++ void *nptr = REALLOC(st->buf, _ns + 1); ++ if(!nptr) return -1; ++ st->buf = (uint8_t *)nptr; ++ buf = st->buf + st->size; ++ ++ /* ++ * Convert series of 0 and 1 into the octet string. ++ */ ++ for(; p < pend; p++) { ++ int ch = *(const unsigned char *)p; ++ int len; /* Length of the rest of the chunk */ ++ ++ if(ch != 0x26 /* '&' */) { ++ *buf++ = ch; ++ continue; /* That was easy... */ ++ } ++ ++ /* ++ * Process entity reference. ++ */ ++ len = chunk_size - (p - (const char *)chunk_buf); ++ if(len == 1 /* "&" */) goto want_more; ++ if(p[1] == 0x23 /* '#' */) { ++ const char *pval; /* Pointer to start of digits */ ++ int32_t val = 0; /* Entity reference value */ ++ int base; ++ ++ if(len == 2 /* "&#" */) goto want_more; ++ if(p[2] == 0x78 /* 'x' */) ++ pval = p + 3, base = 16; ++ else ++ pval = p + 2, base = 10; ++ len = OS__strtoent(base, pval, p + len, &val); ++ if(len == -1) { ++ /* Invalid charset. Just copy verbatim. */ ++ *buf++ = ch; ++ continue; ++ } ++ if(!len || pval[len-1] != 0x3b) goto want_more; ++ assert(val > 0); ++ p += (pval - p) + len - 1; /* Advance past entref */ ++ ++ if(val < 0x80) { ++ *buf++ = (char)val; ++ } else if(val < 0x800) { ++ *buf++ = 0xc0 | ((val >> 6)); ++ *buf++ = 0x80 | ((val & 0x3f)); ++ } else if(val < 0x10000) { ++ *buf++ = 0xe0 | ((val >> 12)); ++ *buf++ = 0x80 | ((val >> 6) & 0x3f); ++ *buf++ = 0x80 | ((val & 0x3f)); ++ } else if(val < 0x200000) { ++ *buf++ = 0xf0 | ((val >> 18)); ++ *buf++ = 0x80 | ((val >> 12) & 0x3f); ++ *buf++ = 0x80 | ((val >> 6) & 0x3f); ++ *buf++ = 0x80 | ((val & 0x3f)); ++ } else if(val < 0x4000000) { ++ *buf++ = 0xf8 | ((val >> 24)); ++ *buf++ = 0x80 | ((val >> 18) & 0x3f); ++ *buf++ = 0x80 | ((val >> 12) & 0x3f); ++ *buf++ = 0x80 | ((val >> 6) & 0x3f); ++ *buf++ = 0x80 | ((val & 0x3f)); ++ } else { ++ *buf++ = 0xfc | ((val >> 30) & 0x1); ++ *buf++ = 0x80 | ((val >> 24) & 0x3f); ++ *buf++ = 0x80 | ((val >> 18) & 0x3f); ++ *buf++ = 0x80 | ((val >> 12) & 0x3f); ++ *buf++ = 0x80 | ((val >> 6) & 0x3f); ++ *buf++ = 0x80 | ((val & 0x3f)); ++ } ++ } else { ++ /* ++ * Ugly, limited parsing of & > < ++ */ ++ char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len); ++ if(!sc) goto want_more; ++ if((sc - p) == 4 ++ && p[1] == 0x61 /* 'a' */ ++ && p[2] == 0x6d /* 'm' */ ++ && p[3] == 0x70 /* 'p' */) { ++ *buf++ = 0x26; ++ p = sc; ++ continue; ++ } ++ if((sc - p) == 3) { ++ if(p[1] == 0x6c) { ++ *buf = 0x3c; /* '<' */ ++ } else if(p[1] == 0x67) { ++ *buf = 0x3e; /* '>' */ ++ } else { ++ /* Unsupported entity reference */ ++ *buf++ = ch; ++ continue; ++ } ++ if(p[2] != 0x74) { ++ /* Unsupported entity reference */ ++ *buf++ = ch; ++ continue; ++ } ++ buf++; ++ p = sc; ++ continue; ++ } ++ /* Unsupported entity reference */ ++ *buf++ = ch; ++ } ++ ++ continue; ++ want_more: ++ if(have_more) { ++ /* ++ * We know that no more data (of the same type) ++ * is coming. Copy the rest verbatim. ++ */ ++ *buf++ = ch; ++ continue; ++ } ++ chunk_size = (p - (const char *)chunk_buf); ++ /* Processing stalled: need more data */ ++ break; ++ } ++ ++ st->size = buf - st->buf; ++ assert(st->size <= _ns); ++ st->buf[st->size] = 0; /* Courtesy termination */ ++ ++ return chunk_size; /* Converted in full */ ++} ++ ++/* ++ * Decode OCTET STRING from the XML element's body. ++ */ ++static asn_dec_rval_t ++OCTET_STRING__decode_xer(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, void **sptr, ++ const char *opt_mname, const void *buf_ptr, size_t size, ++ int (*opt_unexpected_tag_decoder) ++ (void *struct_ptr, const void *chunk_buf, size_t chunk_size), ++ ssize_t (*body_receiver) ++ (void *struct_ptr, const void *chunk_buf, size_t chunk_size, ++ int have_more) ++) { ++ OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; ++ asn_struct_ctx_t *ctx; /* Per-structure parser context */ ++ asn_dec_rval_t rval; /* Return value from the decoder */ ++ int st_allocated; ++ ++ /* ++ * Create the string if does not exist. ++ */ ++ if(!st) { ++ st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); ++ *sptr = (void *)st; ++ if(!st) goto sta_failed; ++ st_allocated = 1; ++ } else { ++ st_allocated = 0; ++ } ++ if(!st->buf) { ++ /* This is separate from above section */ ++ st->buf = (uint8_t *)CALLOC(1, 1); ++ if(!st->buf) { ++ if(st_allocated) { ++ *sptr = 0; ++ goto stb_failed; ++ } else { ++ goto sta_failed; ++ } ++ } ++ } ++ ++ /* Restore parsing context */ ++ ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset); ++ ++ return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag, ++ buf_ptr, size, opt_unexpected_tag_decoder, body_receiver); ++ ++stb_failed: ++ FREEMEM(st); ++sta_failed: ++ rval.code = RC_FAIL; ++ rval.consumed = 0; ++ return rval; ++} ++ ++/* ++ * Decode OCTET STRING from the hexadecimal data. ++ */ ++asn_dec_rval_t ++OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, void **sptr, ++ const char *opt_mname, const void *buf_ptr, size_t size) { ++ return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, ++ buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal); ++} ++ ++/* ++ * Decode OCTET STRING from the binary (0/1) data. ++ */ ++asn_dec_rval_t ++OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, void **sptr, ++ const char *opt_mname, const void *buf_ptr, size_t size) { ++ return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, ++ buf_ptr, size, 0, OCTET_STRING__convert_binary); ++} ++ ++/* ++ * Decode OCTET STRING from the string (ASCII/UTF-8) data. ++ */ ++asn_dec_rval_t ++OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, void **sptr, ++ const char *opt_mname, const void *buf_ptr, size_t size) { ++ return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, ++ buf_ptr, size, ++ OCTET_STRING__handle_control_chars, ++ OCTET_STRING__convert_entrefs); ++} ++ ++asn_dec_rval_t ++OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, ++ void **sptr, asn_per_data_t *pd) { ++ ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ asn_per_constraint_t *ct = constraints ? &constraints->size ++ : (td->per_constraints ++ ? &td->per_constraints->size ++ : &asn_DEF_OCTET_STRING_constraint); ++ asn_dec_rval_t rval = { RC_OK, 0 }; ++ BIT_STRING_t *st = (BIT_STRING_t *)*sptr; ++ ssize_t consumed_myself = 0; ++ int repeat; ++ int unit_bits = (specs->subvariant != 1) * 7 + 1; ++ ++ (void)opt_codec_ctx; ++ ++ /* ++ * Allocate the string. ++ */ ++ if(!st) { ++ st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); ++ if(!st) RETURN(RC_FAIL); ++ } ++ ++ ASN_DEBUG("PER Decoding %s %ld .. %ld bits %d", ++ ct->flags & APC_EXTENSIBLE ? "extensible" : "fixed", ++ ct->lower_bound, ct->upper_bound, ct->effective_bits); ++ ++ if(ct->flags & APC_EXTENSIBLE) { ++ int inext = per_get_few_bits(pd, 1); ++ if(inext < 0) RETURN(RC_WMORE); ++ if(inext) ct = &asn_DEF_OCTET_STRING_constraint; ++ consumed_myself = 0; ++ } ++ ++ if(ct->effective_bits >= 0 ++ && (!st->buf || st->size < ct->upper_bound)) { ++ FREEMEM(st->buf); ++ if(unit_bits == 1) { ++ st->size = (ct->upper_bound + 7) >> 3; ++ } else { ++ st->size = ct->upper_bound; ++ } ++ st->buf = (uint8_t *)MALLOC(st->size + 1); ++ if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } ++ } ++ ++ /* X.691, #16.5: zero-length encoding */ ++ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ ++ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ ++ if(ct->effective_bits == 0) { ++ int ret = per_get_many_bits(pd, st->buf, 0, ++ unit_bits * ct->upper_bound); ++ if(ret < 0) RETURN(RC_WMORE); ++ consumed_myself += unit_bits * ct->upper_bound; ++ st->buf[st->size] = 0; ++ if(unit_bits == 1 && (ct->upper_bound & 0x7)) ++ st->bits_unused = 8 - (ct->upper_bound & 0x7); ++ RETURN(RC_OK); ++ } ++ ++ st->size = 0; ++ do { ++ ssize_t len_bytes; ++ ssize_t len_bits; ++ void *p; ++ int ret; ++ ++ /* Get the PER length */ ++ len_bits = uper_get_length(pd, ct->effective_bits, &repeat); ++ if(len_bits < 0) RETURN(RC_WMORE); ++ len_bits += ct->lower_bound; ++ ++ ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", ++ (long)ct->effective_bits, (long)len_bits, ++ repeat ? "repeat" : "once", td->name); ++ if(unit_bits == 1) { ++ len_bytes = (len_bits + 7) >> 3; ++ if(len_bits & 0x7) ++ st->bits_unused = 8 - (len_bits & 0x7); ++ /* len_bits be multiple of 16K if repeat is set */ ++ } else { ++ len_bytes = len_bits; ++ len_bits = len_bytes << 3; ++ } ++ p = REALLOC(st->buf, st->size + len_bytes + 1); ++ if(!p) RETURN(RC_FAIL); ++ st->buf = (uint8_t *)p; ++ ++ ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits); ++ if(ret < 0) RETURN(RC_WMORE); ++ st->size += len_bytes; ++ } while(repeat); ++ st->buf[st->size] = 0; /* nul-terminate */ ++ ++ return rval; ++} ++ ++asn_enc_rval_t ++OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ asn_per_constraint_t *ct = constraints ? &constraints->size ++ : (td->per_constraints ++ ? &td->per_constraints->size ++ : &asn_DEF_OCTET_STRING_constraint); ++ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; ++ int unit_bits = (specs->subvariant != 1) * 7 + 1; ++ asn_enc_rval_t er; ++ int ct_extensible = ct->flags & APC_EXTENSIBLE; ++ int inext = 0; /* Lies not within extension root */ ++ int sizeinunits = st->size; ++ const uint8_t *buf; ++ int ret; ++ ++ if(!st || !st->buf) ++ _ASN_ENCODE_FAILED; ++ ++ if(unit_bits == 1) { ++ ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", ++ sizeinunits, st->bits_unused); ++ sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07); ++ } ++ ++ ASN_DEBUG("Encoding %s into %d units of %d bits" ++ " (%d..%d, effective %d)%s", ++ td->name, sizeinunits, unit_bits, ++ ct->lower_bound, ct->upper_bound, ++ ct->effective_bits, ct_extensible ? " EXT" : ""); ++ ++ /* Figure out wheter size lies within PER visible consrtaint */ ++ ++ if(ct->effective_bits >= 0) { ++ if(sizeinunits < ct->lower_bound ++ || sizeinunits > ct->upper_bound) { ++ if(ct_extensible) { ++ ct = &asn_DEF_OCTET_STRING_constraint; ++ inext = 1; ++ } else ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ inext = 0; ++ } ++ ++ if(ct_extensible) { ++ /* Declare whether length is [not] within extension root */ ++ if(per_put_few_bits(po, inext, 1)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ /* X.691, #16.5: zero-length encoding */ ++ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ ++ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ ++ if(ct->effective_bits >= 0) { ++ ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", ++ st->size, sizeinunits - ct->lower_bound, ++ ct->effective_bits); ++ ret = per_put_few_bits(po, sizeinunits - ct->lower_bound, ++ ct->effective_bits); ++ if(ret) _ASN_ENCODE_FAILED; ++ ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits); ++ if(ret) _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ ASN_DEBUG("Encoding %d bytes", st->size); ++ ++ if(sizeinunits == 0) { ++ if(uper_put_length(po, 0)) ++ _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ buf = st->buf; ++ while(sizeinunits) { ++ ssize_t maySave = uper_put_length(po, sizeinunits); ++ if(maySave < 0) _ASN_ENCODE_FAILED; ++ ++ ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits); ++ ++ ret = per_put_many_bits(po, buf, maySave * unit_bits); ++ if(ret) _ASN_ENCODE_FAILED; ++ ++ if(unit_bits == 1) ++ buf += maySave >> 3; ++ else ++ buf += maySave; ++ sizeinunits -= maySave; ++ assert(!(maySave & 0x07) || !sizeinunits); ++ } ++ ++ _ASN_ENCODED_OK(er); ++} ++ ++int ++OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ static const char *h2c = "0123456789ABCDEF"; ++ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; ++ char scratch[16 * 3 + 4]; ++ char *p = scratch; ++ uint8_t *buf; ++ uint8_t *end; ++ size_t i; ++ ++ (void)td; /* Unused argument */ ++ ++ if(!st || !st->buf) return (cb("", 8, app_key) < 0) ? -1 : 0; ++ ++ /* ++ * Dump the contents of the buffer in hexadecimal. ++ */ ++ buf = st->buf; ++ end = buf + st->size; ++ for(i = 0; buf < end; buf++, i++) { ++ if(!(i % 16) && (i || st->size > 16)) { ++ if(cb(scratch, p - scratch, app_key) < 0) ++ return -1; ++ _i_INDENT(1); ++ p = scratch; ++ } ++ *p++ = h2c[(*buf >> 4) & 0x0F]; ++ *p++ = h2c[*buf & 0x0F]; ++ *p++ = 0x20; ++ } ++ ++ if(p > scratch) { ++ p--; /* Remove the tail space */ ++ if(cb(scratch, p - scratch, app_key) < 0) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int ++OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, ++ int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { ++ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; ++ ++ (void)td; /* Unused argument */ ++ (void)ilevel; /* Unused argument */ ++ ++ if(st && st->buf) { ++ return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; ++ } else { ++ return (cb("", 8, app_key) < 0) ? -1 : 0; ++ } ++} ++ ++void ++OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { ++ OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ asn_struct_ctx_t *ctx = (asn_struct_ctx_t *) ++ ((char *)st + specs->ctx_offset); ++ struct _stack *stck; ++ ++ if(!td || !st) ++ return; ++ ++ ASN_DEBUG("Freeing %s as OCTET STRING", td->name); ++ ++ if(st->buf) { ++ FREEMEM(st->buf); ++ } ++ ++ /* ++ * Remove decode-time stack. ++ */ ++ stck = (struct _stack *)ctx->ptr; ++ if(stck) { ++ while(stck->tail) { ++ struct _stack_el *sel = stck->tail; ++ stck->tail = sel->prev; ++ FREEMEM(sel); ++ } ++ FREEMEM(stck); ++ } ++ ++ if(!contents_only) { ++ FREEMEM(st); ++ } ++} ++ ++/* ++ * Conversion routines. ++ */ ++int ++OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { ++ void *buf; ++ ++ if(st == 0 || (str == 0 && len)) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* ++ * Clear the OCTET STRING. ++ */ ++ if(str == NULL) { ++ FREEMEM(st->buf); ++ st->buf = 0; ++ st->size = 0; ++ return 0; ++ } ++ ++ /* Determine the original string size, if not explicitly given */ ++ if(len < 0) ++ len = strlen(str); ++ ++ /* Allocate and fill the memory */ ++ buf = MALLOC(len + 1); ++ if(buf == NULL) ++ return -1; ++ ++ memcpy(buf, str, len); ++ ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */ ++ FREEMEM(st->buf); ++ st->buf = (uint8_t *)buf; ++ st->size = len; ++ ++ return 0; ++} ++ ++OCTET_STRING_t * ++OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) { ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ OCTET_STRING_t *st; ++ ++ st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); ++ if(st && str && OCTET_STRING_fromBuf(st, str, len)) { ++ FREEMEM(st); ++ st = NULL; ++ } ++ ++ return st; ++} ++ +diff --git a/asn1/asn1c/OCTET_STRING.h b/asn1/asn1c/OCTET_STRING.h +new file mode 100644 +index 0000000000000000000000000000000000000000..5150161a7a1a19e8e7c123776684e66c1cd429cf +--- /dev/null ++++ b/asn1/asn1c/OCTET_STRING.h +@@ -0,0 +1,80 @@ ++/*- ++ * Copyright (c) 2003 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _OCTET_STRING_H_ ++#define _OCTET_STRING_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct OCTET_STRING { ++ uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ ++ int size; /* Size of the buffer */ ++ ++ asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ ++} OCTET_STRING_t; ++ ++extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; ++ ++asn_struct_free_f OCTET_STRING_free; ++asn_struct_print_f OCTET_STRING_print; ++asn_struct_print_f OCTET_STRING_print_utf8; ++ber_type_decoder_f OCTET_STRING_decode_ber; ++der_type_encoder_f OCTET_STRING_encode_der; ++xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ ++xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ ++xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ ++xer_type_encoder_f OCTET_STRING_encode_xer; ++xer_type_encoder_f OCTET_STRING_encode_xer_utf8; ++per_type_decoder_f OCTET_STRING_decode_uper; ++per_type_encoder_f OCTET_STRING_encode_uper; ++ ++/****************************** ++ * Handy conversion routines. * ++ ******************************/ ++ ++/* ++ * This function clears the previous value of the OCTET STRING (if any) ++ * and then allocates a new memory with the specified content (str/size). ++ * If size = -1, the size of the original string will be determined ++ * using strlen(str). ++ * If str equals to NULL, the function will silently clear the ++ * current contents of the OCTET STRING. ++ * Returns 0 if it was possible to perform operation, -1 otherwise. ++ */ ++int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); ++ ++/* Handy conversion from the C string into the OCTET STRING. */ ++#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) ++ ++/* ++ * Allocate and fill the new OCTET STRING and return a pointer to the newly ++ * allocated object. NULL is permitted in str: the function will just allocate ++ * empty OCTET STRING. ++ */ ++OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, ++ const char *str, int size); ++ ++/**************************** ++ * Internally useful stuff. * ++ ****************************/ ++ ++typedef struct asn_OCTET_STRING_specifics_s { ++ /* ++ * Target structure description. ++ */ ++ int struct_size; /* Size of the structure */ ++ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ ++ ++ int subvariant; /* {0,1,2} for O-S, BIT STRING or ANY */ ++} asn_OCTET_STRING_specifics_t; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _OCTET_STRING_H_ */ +diff --git a/asn1/asn1c/TypeValuePair.c b/asn1/asn1c/TypeValuePair.c +new file mode 100644 +index 0000000000000000000000000000000000000000..707eef3f65c4bf0a64b4864391e64865cc19d7ca +--- /dev/null ++++ b/asn1/asn1c/TypeValuePair.c +@@ -0,0 +1,71 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#include ++ ++#include "TypeValuePair.h" ++ ++static asn_TYPE_member_t asn_MBR_TypeValuePair_1[] = { ++ { ATF_NOFLAGS, 0, offsetof(struct TypeValuePair, type), ++ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_Int32, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "type" ++ }, ++ { ATF_NOFLAGS, 0, offsetof(struct TypeValuePair, value), ++ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), ++ +1, /* EXPLICIT tag at current level */ ++ &asn_DEF_OCTET_STRING, ++ 0, /* Defer constraints checking to the member type */ ++ 0, /* PER is not compiled, use -gen-PER */ ++ 0, ++ "value" ++ }, ++}; ++static ber_tlv_tag_t asn_DEF_TypeValuePair_tags_1[] = { ++ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) ++}; ++static asn_TYPE_tag2member_t asn_MAP_TypeValuePair_tag2el_1[] = { ++ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* type at 34 */ ++ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* value at 35 */ ++}; ++static asn_SEQUENCE_specifics_t asn_SPC_TypeValuePair_specs_1 = { ++ sizeof(struct TypeValuePair), ++ offsetof(struct TypeValuePair, _asn_ctx), ++ asn_MAP_TypeValuePair_tag2el_1, ++ 2, /* Count of tags in the map */ ++ 0, 0, 0, /* Optional elements (not needed) */ ++ -1, /* Start extensions */ ++ -1 /* Stop extensions */ ++}; ++asn_TYPE_descriptor_t asn_DEF_TypeValuePair = { ++ "TypeValuePair", ++ "TypeValuePair", ++ SEQUENCE_free, ++ SEQUENCE_print, ++ SEQUENCE_constraint, ++ SEQUENCE_decode_ber, ++ SEQUENCE_encode_der, ++ SEQUENCE_decode_xer, ++ SEQUENCE_encode_xer, ++ 0, 0, /* No PER support, use "-gen-PER" to enable */ ++ 0, /* Use generic outmost tag fetcher */ ++ asn_DEF_TypeValuePair_tags_1, ++ sizeof(asn_DEF_TypeValuePair_tags_1) ++ /sizeof(asn_DEF_TypeValuePair_tags_1[0]), /* 1 */ ++ asn_DEF_TypeValuePair_tags_1, /* Same as above */ ++ sizeof(asn_DEF_TypeValuePair_tags_1) ++ /sizeof(asn_DEF_TypeValuePair_tags_1[0]), /* 1 */ ++ 0, /* No PER visible constraints */ ++ asn_MBR_TypeValuePair_1, ++ 2, /* Elements count */ ++ &asn_SPC_TypeValuePair_specs_1 /* Additional specs */ ++}; ++ +diff --git a/asn1/asn1c/TypeValuePair.h b/asn1/asn1c/TypeValuePair.h +new file mode 100644 +index 0000000000000000000000000000000000000000..538b4609c5f0fe051988885c84c3caf6d8b85452 +--- /dev/null ++++ b/asn1/asn1c/TypeValuePair.h +@@ -0,0 +1,39 @@ ++/* ++ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) ++ * From ASN.1 module "KeytabModule" ++ * found in "ipa.asn1" ++ * `asn1c -fskeletons-copy` ++ */ ++ ++#ifndef _TypeValuePair_H_ ++#define _TypeValuePair_H_ ++ ++ ++#include ++ ++/* Including external dependencies */ ++#include "Int32.h" ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* TypeValuePair */ ++typedef struct TypeValuePair { ++ Int32_t type; ++ OCTET_STRING_t value; ++ ++ /* Context for parsing across buffer boundaries */ ++ asn_struct_ctx_t _asn_ctx; ++} TypeValuePair_t; ++ ++/* Implementation */ ++extern asn_TYPE_descriptor_t asn_DEF_TypeValuePair; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _TypeValuePair_H_ */ +diff --git a/asn1/asn1c/asn_SEQUENCE_OF.c b/asn1/asn1c/asn_SEQUENCE_OF.c +new file mode 100644 +index 0000000000000000000000000000000000000000..ec952fc99936ab1464d76ac75821fc19e47995cb +--- /dev/null ++++ b/asn1/asn1c/asn_SEQUENCE_OF.c +@@ -0,0 +1,41 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++ ++typedef A_SEQUENCE_OF(void) asn_sequence; ++ ++void ++asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free) { ++ asn_sequence *as = (asn_sequence *)asn_sequence_of_x; ++ ++ if(as) { ++ void *ptr; ++ int n; ++ ++ if(number < 0 || number >= as->count) ++ return; /* Nothing to delete */ ++ ++ if(_do_free && as->free) { ++ ptr = as->array[number]; ++ } else { ++ ptr = 0; ++ } ++ ++ /* ++ * Shift all elements to the left to hide the gap. ++ */ ++ --as->count; ++ for(n = number; n < as->count; n++) ++ as->array[n] = as->array[n+1]; ++ ++ /* ++ * Invoke the third-party function only when the state ++ * of the parent structure is consistent. ++ */ ++ if(ptr) as->free(ptr); ++ } ++} ++ +diff --git a/asn1/asn1c/asn_SEQUENCE_OF.h b/asn1/asn1c/asn_SEQUENCE_OF.h +new file mode 100644 +index 0000000000000000000000000000000000000000..e678f0347221f96698668bf6d8461655f8e40d82 +--- /dev/null ++++ b/asn1/asn1c/asn_SEQUENCE_OF.h +@@ -0,0 +1,52 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef ASN_SEQUENCE_OF_H ++#define ASN_SEQUENCE_OF_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * SEQUENCE OF is the same as SET OF with a tiny difference: ++ * the delete operation preserves the initial order of elements ++ * and thus MAY operate in non-constant time. ++ */ ++#define A_SEQUENCE_OF(type) A_SET_OF(type) ++ ++#define ASN_SEQUENCE_ADD(headptr, ptr) \ ++ asn_sequence_add((headptr), (ptr)) ++ ++/*********************************************** ++ * Implementation of the SEQUENCE OF structure. ++ */ ++ ++#define asn_sequence_add asn_set_add ++#define asn_sequence_empty asn_set_empty ++ ++/* ++ * Delete the element from the set by its number (base 0). ++ * This is NOT a constant-time operation. ++ * The order of elements is preserved. ++ * If _do_free is given AND the (*free) is initialized, the element ++ * will be freed using the custom (*free) function as well. ++ */ ++void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free); ++ ++/* ++ * Cope with different conversions requirements to/from void in C and C++. ++ * This is mostly useful for support library. ++ */ ++typedef A_SEQUENCE_OF(void) asn_anonymous_sequence_; ++#define _A_SEQUENCE_FROM_VOID(ptr) ((asn_anonymous_sequence_ *)(ptr)) ++#define _A_CSEQUENCE_FROM_VOID(ptr) ((const asn_anonymous_sequence_ *)(ptr)) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ASN_SEQUENCE_OF_H */ +diff --git a/asn1/asn1c/asn_SET_OF.c b/asn1/asn1c/asn_SET_OF.c +new file mode 100644 +index 0000000000000000000000000000000000000000..944f2cb8ad70a166e65dbb3536ef62fc34a8e74c +--- /dev/null ++++ b/asn1/asn1c/asn_SET_OF.c +@@ -0,0 +1,88 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * Add another element into the set. ++ */ ++int ++asn_set_add(void *asn_set_of_x, void *ptr) { ++ asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); ++ ++ if(as == 0 || ptr == 0) { ++ errno = EINVAL; /* Invalid arguments */ ++ return -1; ++ } ++ ++ /* ++ * Make sure there's enough space to insert an element. ++ */ ++ if(as->count == as->size) { ++ int _newsize = as->size ? (as->size << 1) : 4; ++ void *_new_arr; ++ _new_arr = REALLOC(as->array, _newsize * sizeof(as->array[0])); ++ if(_new_arr) { ++ as->array = (void **)_new_arr; ++ as->size = _newsize; ++ } else { ++ /* ENOMEM */ ++ return -1; ++ } ++ } ++ ++ as->array[as->count++] = ptr; ++ ++ return 0; ++} ++ ++void ++asn_set_del(void *asn_set_of_x, int number, int _do_free) { ++ asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); ++ ++ if(as) { ++ void *ptr; ++ if(number < 0 || number >= as->count) ++ return; ++ ++ if(_do_free && as->free) { ++ ptr = as->array[number]; ++ } else { ++ ptr = 0; ++ } ++ ++ as->array[number] = as->array[--as->count]; ++ ++ /* ++ * Invoke the third-party function only when the state ++ * of the parent structure is consistent. ++ */ ++ if(ptr) as->free(ptr); ++ } ++} ++ ++/* ++ * Free the contents of the set, do not free the set itself. ++ */ ++void ++asn_set_empty(void *asn_set_of_x) { ++ asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); ++ ++ if(as) { ++ if(as->array) { ++ if(as->free) { ++ while(as->count--) ++ as->free(as->array[as->count]); ++ } ++ FREEMEM(as->array); ++ as->array = 0; ++ } ++ as->count = 0; ++ as->size = 0; ++ } ++ ++} ++ +diff --git a/asn1/asn1c/asn_SET_OF.h b/asn1/asn1c/asn_SET_OF.h +new file mode 100644 +index 0000000000000000000000000000000000000000..7edf14b51b984d545b818fcf3a93204935d46a80 +--- /dev/null ++++ b/asn1/asn1c/asn_SET_OF.h +@@ -0,0 +1,62 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef ASN_SET_OF_H ++#define ASN_SET_OF_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define A_SET_OF(type) \ ++ struct { \ ++ type **array; \ ++ int count; /* Meaningful size */ \ ++ int size; /* Allocated size */ \ ++ void (*free)(type *); \ ++ } ++ ++#define ASN_SET_ADD(headptr, ptr) \ ++ asn_set_add((headptr), (ptr)) ++ ++/******************************************* ++ * Implementation of the SET OF structure. ++ */ ++ ++/* ++ * Add another structure into the set by its pointer. ++ * RETURN VALUES: ++ * 0 for success and -1/errno for failure. ++ */ ++int asn_set_add(void *asn_set_of_x, void *ptr); ++ ++/* ++ * Delete the element from the set by its number (base 0). ++ * This is a constant-time operation. The order of elements before the ++ * deleted ones is guaranteed, the order of elements after the deleted ++ * one is NOT guaranteed. ++ * If _do_free is given AND the (*free) is initialized, the element ++ * will be freed using the custom (*free) function as well. ++ */ ++void asn_set_del(void *asn_set_of_x, int number, int _do_free); ++ ++/* ++ * Empty the contents of the set. Will free the elements, if (*free) is given. ++ * Will NOT free the set itself. ++ */ ++void asn_set_empty(void *asn_set_of_x); ++ ++/* ++ * Cope with different conversions requirements to/from void in C and C++. ++ * This is mostly useful for support library. ++ */ ++typedef A_SET_OF(void) asn_anonymous_set_; ++#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) ++#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ASN_SET_OF_H */ +diff --git a/asn1/asn1c/asn_application.h b/asn1/asn1c/asn_application.h +new file mode 100644 +index 0000000000000000000000000000000000000000..f40cd86ad3c63a7a0a07214addecb57d087abe25 +--- /dev/null ++++ b/asn1/asn1c/asn_application.h +@@ -0,0 +1,47 @@ ++/*- ++ * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * Application-level ASN.1 callbacks. ++ */ ++#ifndef _ASN_APPLICATION_H_ ++#define _ASN_APPLICATION_H_ ++ ++#include "asn_system.h" /* for platform-dependent types */ ++#include "asn_codecs.h" /* for ASN.1 codecs specifics */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * Generic type of an application-defined callback to return various ++ * types of data to the application. ++ * EXPECTED RETURN VALUES: ++ * -1: Failed to consume bytes. Abort the mission. ++ * Non-negative return values indicate success, and ignored. ++ */ ++typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, ++ void *application_specific_key); ++ ++/* ++ * A callback of this type is called whenever constraint validation fails ++ * on some ASN.1 type. See "constraints.h" for more details on constraint ++ * validation. ++ * This callback specifies a descriptor of the ASN.1 type which failed ++ * the constraint check, as well as human readable message on what ++ * particular constraint has failed. ++ */ ++typedef void (asn_app_constraint_failed_f)(void *application_specific_key, ++ struct asn_TYPE_descriptor_s *type_descriptor_which_failed, ++ const void *structure_which_failed_ptr, ++ const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ ++ ++#endif /* _ASN_APPLICATION_H_ */ +diff --git a/asn1/asn1c/asn_codecs.h b/asn1/asn1c/asn_codecs.h +new file mode 100644 +index 0000000000000000000000000000000000000000..4a251d940880a03b24dc9f3fe41f2febb9b49211 +--- /dev/null ++++ b/asn1/asn1c/asn_codecs.h +@@ -0,0 +1,109 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _ASN_CODECS_H_ ++#define _ASN_CODECS_H_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++ ++/* ++ * This structure defines a set of parameters that may be passed ++ * to every ASN.1 encoder or decoder function. ++ * WARNING: if max_stack_size member is set, and you are calling the ++ * function pointers of the asn_TYPE_descriptor_t directly, ++ * this structure must be ALLOCATED ON THE STACK! ++ * If you can't always satisfy this requirement, use ber_decode(), ++ * xer_decode() and uper_decode() functions instead. ++ */ ++typedef struct asn_codec_ctx_s { ++ /* ++ * Limit the decoder routines to use no (much) more stack than a given ++ * number of bytes. Most of decoders are stack-based, and this ++ * would protect against stack overflows if the number of nested ++ * encodings is high. ++ * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based, ++ * and are safe from this kind of overflow. ++ * A value from getrlimit(RLIMIT_STACK) may be used to initialize ++ * this variable. Be careful in multithreaded environments, as the ++ * stack size is rather limited. ++ */ ++ size_t max_stack_size; /* 0 disables stack bounds checking */ ++} asn_codec_ctx_t; ++ ++/* ++ * Type of the return value of the encoding functions (der_encode, xer_encode). ++ */ ++typedef struct asn_enc_rval_s { ++ /* ++ * Number of bytes encoded. ++ * -1 indicates failure to encode the structure. ++ * In this case, the members below this one are meaningful. ++ */ ++ ssize_t encoded; ++ ++ /* ++ * Members meaningful when (encoded == -1), for post mortem analysis. ++ */ ++ ++ /* Type which cannot be encoded */ ++ struct asn_TYPE_descriptor_s *failed_type; ++ ++ /* Pointer to the structure of that type */ ++ void *structure_ptr; ++} asn_enc_rval_t; ++#define _ASN_ENCODE_FAILED do { \ ++ asn_enc_rval_t tmp_error; \ ++ tmp_error.encoded = -1; \ ++ tmp_error.failed_type = td; \ ++ tmp_error.structure_ptr = sptr; \ ++ ASN_DEBUG("Failed to encode element %s", td->name); \ ++ return tmp_error; \ ++} while(0) ++#define _ASN_ENCODED_OK(rval) do { \ ++ rval.structure_ptr = 0; \ ++ rval.failed_type = 0; \ ++ return rval; \ ++} while(0) ++ ++/* ++ * Type of the return value of the decoding functions (ber_decode, xer_decode) ++ * ++ * Please note that the number of consumed bytes is ALWAYS meaningful, ++ * even if code==RC_FAIL. This is to indicate the number of successfully ++ * decoded bytes, hence providing a possibility to fail with more diagnostics ++ * (i.e., print the offending remainder of the buffer). ++ */ ++enum asn_dec_rval_code_e { ++ RC_OK, /* Decoded successfully */ ++ RC_WMORE, /* More data expected, call again */ ++ RC_FAIL /* Failure to decode data */ ++}; ++typedef struct asn_dec_rval_s { ++ enum asn_dec_rval_code_e code; /* Result code */ ++ size_t consumed; /* Number of bytes consumed */ ++} asn_dec_rval_t; ++#define _ASN_DECODE_FAILED do { \ ++ asn_dec_rval_t tmp_error; \ ++ tmp_error.code = RC_FAIL; \ ++ tmp_error.consumed = 0; \ ++ ASN_DEBUG("Failed to decode element %s", td->name); \ ++ return tmp_error; \ ++} while(0) ++#define _ASN_DECODE_STARVED do { \ ++ asn_dec_rval_t tmp_error; \ ++ tmp_error.code = RC_WMORE; \ ++ tmp_error.consumed = 0; \ ++ return tmp_error; \ ++} while(0) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _ASN_CODECS_H_ */ +diff --git a/asn1/asn1c/asn_codecs_prim.c b/asn1/asn1c/asn_codecs_prim.c +new file mode 100644 +index 0000000000000000000000000000000000000000..4e5c63937adafc40a56b67fe5b3d9482220907d5 +--- /dev/null ++++ b/asn1/asn1c/asn_codecs_prim.c +@@ -0,0 +1,295 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * Decode an always-primitive type. ++ */ ++asn_dec_rval_t ++ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, ++ void **sptr, const void *buf_ptr, size_t size, int tag_mode) { ++ ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; ++ asn_dec_rval_t rval; ++ ber_tlv_len_t length; ++ ++ /* ++ * If the structure is not there, allocate it. ++ */ ++ if(st == NULL) { ++ st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st)); ++ if(st == NULL) _ASN_DECODE_FAILED; ++ *sptr = (void *)st; ++ } ++ ++ ASN_DEBUG("Decoding %s as plain primitive (tm=%d)", ++ td->name, tag_mode); ++ ++ /* ++ * Check tags and extract value length. ++ */ ++ rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, ++ tag_mode, 0, &length, 0); ++ if(rval.code != RC_OK) ++ return rval; ++ ++ ASN_DEBUG("%s length is %d bytes", td->name, (int)length); ++ ++ /* ++ * Make sure we have this length. ++ */ ++ buf_ptr = ((const char *)buf_ptr) + rval.consumed; ++ size -= rval.consumed; ++ if(length > (ber_tlv_len_t)size) { ++ rval.code = RC_WMORE; ++ rval.consumed = 0; ++ return rval; ++ } ++ ++ st->size = (int)length; ++ /* The following better be optimized away. */ ++ if(sizeof(st->size) != sizeof(length) ++ && (ber_tlv_len_t)st->size != length) { ++ st->size = 0; ++ _ASN_DECODE_FAILED; ++ } ++ ++ st->buf = (uint8_t *)MALLOC(length + 1); ++ if(!st->buf) { ++ st->size = 0; ++ _ASN_DECODE_FAILED; ++ } ++ ++ memcpy(st->buf, buf_ptr, length); ++ st->buf[length] = '\0'; /* Just in case */ ++ ++ rval.code = RC_OK; ++ rval.consumed += length; ++ ++ ASN_DEBUG("Took %ld/%ld bytes to encode %s", ++ (long)rval.consumed, ++ (long)length, td->name); ++ ++ return rval; ++} ++ ++/* ++ * Encode an always-primitive type using DER. ++ */ ++asn_enc_rval_t ++der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr, ++ int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_enc_rval_t erval; ++ ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; ++ ++ ASN_DEBUG("%s %s as a primitive type (tm=%d)", ++ cb?"Encoding":"Estimating", td->name, tag_mode); ++ ++ erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag, ++ cb, app_key); ++ ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded); ++ if(erval.encoded == -1) { ++ erval.failed_type = td; ++ erval.structure_ptr = sptr; ++ return erval; ++ } ++ ++ if(cb && st->buf) { ++ if(cb(st->buf, st->size, app_key) < 0) { ++ erval.encoded = -1; ++ erval.failed_type = td; ++ erval.structure_ptr = sptr; ++ return erval; ++ } ++ } else { ++ assert(st->buf || st->size == 0); ++ } ++ ++ erval.encoded += st->size; ++ _ASN_ENCODED_OK(erval); ++} ++ ++void ++ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr, ++ int contents_only) { ++ ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; ++ ++ if(!td || !sptr) ++ return; ++ ++ ASN_DEBUG("Freeing %s as a primitive type", td->name); ++ ++ if(st->buf) ++ FREEMEM(st->buf); ++ ++ if(!contents_only) ++ FREEMEM(st); ++} ++ ++ ++/* ++ * Local internal type passed around as an argument. ++ */ ++struct xdp_arg_s { ++ asn_TYPE_descriptor_t *type_descriptor; ++ void *struct_key; ++ xer_primitive_body_decoder_f *prim_body_decoder; ++ int decoded_something; ++ int want_more; ++}; ++ ++ ++static int ++xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) { ++ struct xdp_arg_s *arg = (struct xdp_arg_s *)key; ++ enum xer_pbd_rval bret; ++ ++ if(arg->decoded_something) { ++ if(xer_is_whitespace(chunk_buf, chunk_size)) ++ return 0; /* Skip it. */ ++ /* ++ * Decoding was done once already. Prohibit doing it again. ++ */ ++ return -1; ++ } ++ ++ bret = arg->prim_body_decoder(arg->type_descriptor, ++ arg->struct_key, chunk_buf, chunk_size); ++ switch(bret) { ++ case XPBD_SYSTEM_FAILURE: ++ case XPBD_DECODER_LIMIT: ++ case XPBD_BROKEN_ENCODING: ++ break; ++ case XPBD_BODY_CONSUMED: ++ /* Tag decoded successfully */ ++ arg->decoded_something = 1; ++ /* Fall through */ ++ case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static ssize_t ++xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { ++ struct xdp_arg_s *arg = (struct xdp_arg_s *)key; ++ enum xer_pbd_rval bret; ++ ++ if(arg->decoded_something) { ++ if(xer_is_whitespace(chunk_buf, chunk_size)) ++ return chunk_size; ++ /* ++ * Decoding was done once already. Prohibit doing it again. ++ */ ++ return -1; ++ } ++ ++ if(!have_more) { ++ /* ++ * If we've received something like "1", we can't really ++ * tell whether it is really `1` or `123`, until we know ++ * that there is no more data coming. ++ * The have_more argument will be set to 1 once something ++ * like this is available to the caller of this callback: ++ * "1want_more = 1; ++ return -1; ++ } ++ ++ bret = arg->prim_body_decoder(arg->type_descriptor, ++ arg->struct_key, chunk_buf, chunk_size); ++ switch(bret) { ++ case XPBD_SYSTEM_FAILURE: ++ case XPBD_DECODER_LIMIT: ++ case XPBD_BROKEN_ENCODING: ++ break; ++ case XPBD_BODY_CONSUMED: ++ /* Tag decoded successfully */ ++ arg->decoded_something = 1; ++ /* Fall through */ ++ case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ ++ return chunk_size; ++ } ++ ++ return -1; ++} ++ ++ ++asn_dec_rval_t ++xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, ++ void **sptr, ++ size_t struct_size, ++ const char *opt_mname, ++ const void *buf_ptr, size_t size, ++ xer_primitive_body_decoder_f *prim_body_decoder ++) { ++ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; ++ asn_struct_ctx_t s_ctx; ++ struct xdp_arg_s s_arg; ++ asn_dec_rval_t rc; ++ ++ /* ++ * Create the structure if does not exist. ++ */ ++ if(!*sptr) { ++ *sptr = CALLOC(1, struct_size); ++ if(!*sptr) _ASN_DECODE_FAILED; ++ } ++ ++ memset(&s_ctx, 0, sizeof(s_ctx)); ++ s_arg.type_descriptor = td; ++ s_arg.struct_key = *sptr; ++ s_arg.prim_body_decoder = prim_body_decoder; ++ s_arg.decoded_something = 0; ++ s_arg.want_more = 0; ++ ++ rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg, ++ xml_tag, buf_ptr, size, ++ xer_decode__unexpected_tag, xer_decode__body); ++ switch(rc.code) { ++ case RC_OK: ++ if(!s_arg.decoded_something) { ++ char ch; ++ ASN_DEBUG("Primitive body is not recognized, " ++ "supplying empty one"); ++ /* ++ * Decoding opportunity has come and gone. ++ * Where's the result? ++ * Try to feed with empty body, see if it eats it. ++ */ ++ if(prim_body_decoder(s_arg.type_descriptor, ++ s_arg.struct_key, &ch, 0) ++ != XPBD_BODY_CONSUMED) { ++ /* ++ * This decoder does not like empty stuff. ++ */ ++ _ASN_DECODE_FAILED; ++ } ++ } ++ break; ++ case RC_WMORE: ++ /* ++ * Redo the whole thing later. ++ * We don't have a context to save intermediate parsing state. ++ */ ++ rc.consumed = 0; ++ break; ++ case RC_FAIL: ++ rc.consumed = 0; ++ if(s_arg.want_more) ++ rc.code = RC_WMORE; ++ else ++ _ASN_DECODE_FAILED; ++ break; ++ } ++ return rc; ++} ++ +diff --git a/asn1/asn1c/asn_codecs_prim.h b/asn1/asn1c/asn_codecs_prim.h +new file mode 100644 +index 0000000000000000000000000000000000000000..0f683fdd0ac7d5be56c55b1363fa4fddb0d48198 +--- /dev/null ++++ b/asn1/asn1c/asn_codecs_prim.h +@@ -0,0 +1,53 @@ ++/*- ++ * Copyright (c) 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef ASN_CODECS_PRIM_H ++#define ASN_CODECS_PRIM_H ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct ASN__PRIMITIVE_TYPE_s { ++ uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ ++ int size; /* Size of the buffer */ ++} ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ ++ ++asn_struct_free_f ASN__PRIMITIVE_TYPE_free; ++ber_type_decoder_f ber_decode_primitive; ++der_type_encoder_f der_encode_primitive; ++ ++/* ++ * A callback specification for the xer_decode_primitive() function below. ++ */ ++enum xer_pbd_rval { ++ XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ ++ XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ ++ XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ ++ XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ ++ XPBD_BODY_CONSUMED /* Body is recognized and consumed */ ++}; ++typedef enum xer_pbd_rval (xer_primitive_body_decoder_f) ++ (asn_TYPE_descriptor_t *td, void *struct_ptr, ++ const void *chunk_buf, size_t chunk_size); ++ ++/* ++ * Specific function to decode simple primitive types. ++ * Also see xer_decode_general() in xer_decoder.h ++ */ ++asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *type_descriptor, ++ void **struct_ptr, size_t struct_size, ++ const char *opt_mname, ++ const void *buf_ptr, size_t size, ++ xer_primitive_body_decoder_f *prim_body_decoder ++); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ASN_CODECS_PRIM_H */ +diff --git a/asn1/asn1c/asn_internal.h b/asn1/asn1c/asn_internal.h +new file mode 100644 +index 0000000000000000000000000000000000000000..67f055a62fbf74c397d2c108469549291ef9e6af +--- /dev/null ++++ b/asn1/asn1c/asn_internal.h +@@ -0,0 +1,111 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * Declarations internally useful for the ASN.1 support code. ++ */ ++#ifndef _ASN_INTERNAL_H_ ++#define _ASN_INTERNAL_H_ ++ ++#include "asn_application.h" /* Application-visible API */ ++ ++#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ ++#include /* for assert() macro */ ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Environment version might be used to avoid running with the old library */ ++#define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */ ++int get_asn1c_environment_version(void); /* Run-time version */ ++ ++#define CALLOC(nmemb, size) calloc(nmemb, size) ++#define MALLOC(size) malloc(size) ++#define REALLOC(oldptr, size) realloc(oldptr, size) ++#define FREEMEM(ptr) free(ptr) ++ ++/* ++ * A macro for debugging the ASN.1 internals. ++ * You may enable or override it. ++ */ ++#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ ++#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ ++#ifdef __GNUC__ ++#define ASN_DEBUG(fmt, args...) do { \ ++ fprintf(stderr, fmt, ##args); \ ++ fprintf(stderr, " (%s:%d)\n", \ ++ __FILE__, __LINE__); \ ++ } while(0) ++#else /* !__GNUC__ */ ++void ASN_DEBUG_f(const char *fmt, ...); ++#define ASN_DEBUG ASN_DEBUG_f ++#endif /* __GNUC__ */ ++#else /* EMIT_ASN_DEBUG != 1 */ ++static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } ++#endif /* EMIT_ASN_DEBUG */ ++#endif /* ASN_DEBUG */ ++ ++/* ++ * Invoke the application-supplied callback and fail, if something is wrong. ++ */ ++#define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) ++#define _ASN_E_CALLBACK(foo) do { \ ++ if(foo) goto cb_failed; \ ++ } while(0) ++#define _ASN_CALLBACK(buf, size) \ ++ _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) ++#define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ ++ _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) ++#define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ ++ _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) \ ++ || __ASN_E_cbc(buf2, size2) \ ++ || __ASN_E_cbc(buf3, size3)) ++ ++#define _i_ASN_TEXT_INDENT(nl, level) do { \ ++ int __level = (level); \ ++ int __nl = ((nl) != 0); \ ++ int __i; \ ++ if(__nl) _ASN_CALLBACK("\n", 1); \ ++ for(__i = 0; __i < __level; __i++) \ ++ _ASN_CALLBACK(" ", 4); \ ++ er.encoded += __nl + 4 * __level; \ ++} while(0) ++ ++#define _i_INDENT(nl) do { \ ++ int __i; \ ++ if((nl) && cb("\n", 1, app_key) < 0) return -1; \ ++ for(__i = 0; __i < ilevel; __i++) \ ++ if(cb(" ", 4, app_key) < 0) return -1; \ ++} while(0) ++ ++/* ++ * Check stack against overflow, if limit is set. ++ */ ++#define _ASN_DEFAULT_STACK_MAX (30000) ++static inline int ++_ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) { ++ if(ctx && ctx->max_stack_size) { ++ ++ /* ctx MUST be allocated on the stack */ ++ ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); ++ if(usedstack > 0) usedstack = -usedstack; /* grows up! */ ++ ++ /* double negative required to avoid int wrap-around */ ++ if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { ++ ASN_DEBUG("Stack limit %ld reached", ++ (long)ctx->max_stack_size); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _ASN_INTERNAL_H_ */ +diff --git a/asn1/asn1c/asn_system.h b/asn1/asn1c/asn_system.h +new file mode 100644 +index 0000000000000000000000000000000000000000..d7ebdaa4e16a2636184db6ba4fe34fda5860a6bc +--- /dev/null ++++ b/asn1/asn1c/asn_system.h +@@ -0,0 +1,104 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * Miscellaneous system-dependent types. ++ */ ++#ifndef _ASN_SYSTEM_H_ ++#define _ASN_SYSTEM_H_ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include /* For snprintf(3) */ ++#include /* For *alloc(3) */ ++#include /* For memcpy(3) */ ++#include /* For size_t */ ++#include /* For va_start */ ++#include /* for offsetof and ptrdiff_t */ ++ ++#ifdef WIN32 ++ ++#include ++#include ++#define snprintf _snprintf ++#define vsnprintf _vsnprintf ++ ++#ifdef _MSC_VER /* MSVS.Net */ ++#ifndef __cplusplus ++#define inline __inline ++#endif ++#define ssize_t SSIZE_T ++typedef char int8_t; ++typedef short int16_t; ++typedef int int32_t; ++typedef unsigned char uint8_t; ++typedef unsigned short uint16_t; ++typedef unsigned int uint32_t; ++#define WIN32_LEAN_AND_MEAN ++#include ++#include ++#define isnan _isnan ++#define finite _finite ++#define copysign _copysign ++#define ilogb _logb ++#endif /* _MSC_VER */ ++ ++#else /* !WIN32 */ ++ ++#if defined(__vxworks) ++#include ++#else /* !defined(__vxworks) */ ++ ++#include /* C99 specifies this file */ ++/* ++ * 1. Earlier FreeBSD version didn't have , ++ * but was present. ++ * 2. Sun Solaris requires for alloca(3), ++ * but does not have . ++ */ ++#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) ++#if defined(sun) ++#include /* For alloca(3) */ ++#include /* for finite(3) */ ++#elif defined(__hpux) ++#ifdef __GNUC__ ++#include /* For alloca(3) */ ++#else /* !__GNUC__ */ ++#define inline ++#endif /* __GNUC__ */ ++#else ++#include /* SUSv2+ and C99 specify this file, for uintXX_t */ ++#endif /* defined(sun) */ ++#endif ++ ++#endif /* defined(__vxworks) */ ++ ++#endif /* WIN32 */ ++ ++#if __GNUC__ >= 3 ++#ifndef GCC_PRINTFLIKE ++#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) ++#endif ++#else ++#ifndef GCC_PRINTFLIKE ++#define GCC_PRINTFLIKE(fmt,var) /* nothing */ ++#endif ++#endif ++ ++#ifndef offsetof /* If not defined by */ ++#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) ++#endif /* offsetof */ ++ ++#ifndef MIN /* Suitable for comparing primitive types (integers) */ ++#if defined(__GNUC__) ++#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ ++ ((_a)<(_b)?(_a):(_b)); }) ++#else /* !__GNUC__ */ ++#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ ++#endif /* __GNUC__ */ ++#endif /* MIN */ ++ ++#endif /* _ASN_SYSTEM_H_ */ +diff --git a/asn1/asn1c/ber_decoder.c b/asn1/asn1c/ber_decoder.c +new file mode 100644 +index 0000000000000000000000000000000000000000..601f66c0b0274b74dcb56e7eca469ded9b076b2c +--- /dev/null ++++ b/asn1/asn1c/ber_decoder.c +@@ -0,0 +1,283 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++ ++#undef ADVANCE ++#define ADVANCE(num_bytes) do { \ ++ size_t num = num_bytes; \ ++ ptr = ((const char *)ptr) + num; \ ++ size -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++#undef RETURN ++#define RETURN(_code) do { \ ++ asn_dec_rval_t rval; \ ++ rval.code = _code; \ ++ if(opt_ctx) opt_ctx->step = step; /* Save context */ \ ++ if(_code == RC_OK || opt_ctx) \ ++ rval.consumed = consumed_myself; \ ++ else \ ++ rval.consumed = 0; /* Context-free */ \ ++ return rval; \ ++ } while(0) ++ ++/* ++ * The BER decoder of any type. ++ */ ++asn_dec_rval_t ++ber_decode(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *type_descriptor, ++ void **struct_ptr, const void *ptr, size_t size) { ++ asn_codec_ctx_t s_codec_ctx; ++ ++ /* ++ * Stack checker requires that the codec context ++ * must be allocated on the stack. ++ */ ++ if(opt_codec_ctx) { ++ if(opt_codec_ctx->max_stack_size) { ++ s_codec_ctx = *opt_codec_ctx; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ } else { ++ /* If context is not given, be security-conscious anyway */ ++ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); ++ s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ ++ /* ++ * Invoke type-specific decoder. ++ */ ++ return type_descriptor->ber_decoder(opt_codec_ctx, type_descriptor, ++ struct_ptr, /* Pointer to the destination structure */ ++ ptr, size, /* Buffer and its size */ ++ 0 /* Default tag mode is 0 */ ++ ); ++} ++ ++/* ++ * Check the set of >> tags matches the definition. ++ */ ++asn_dec_rval_t ++ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, ++ const void *ptr, size_t size, int tag_mode, int last_tag_form, ++ ber_tlv_len_t *last_length, int *opt_tlv_form) { ++ ssize_t consumed_myself = 0; ++ ssize_t tag_len; ++ ssize_t len_len; ++ ber_tlv_tag_t tlv_tag; ++ ber_tlv_len_t tlv_len; ++ ber_tlv_len_t limit_len = -1; ++ int expect_00_terminators = 0; ++ int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */ ++ int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */ ++ int tagno; ++ ++ /* ++ * Make sure we didn't exceed the maximum stack size. ++ */ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ RETURN(RC_FAIL); ++ ++ /* ++ * So what does all this implicit skip stuff mean? ++ * Imagine two types, ++ * A ::= [5] IMPLICIT T ++ * B ::= [2] EXPLICIT T ++ * Where T is defined as ++ * T ::= [4] IMPLICIT SEQUENCE { ... } ++ * ++ * Let's say, we are starting to decode type A, given the ++ * following TLV stream: <5> <0>. What does this mean? ++ * It means that the type A contains type T which is, ++ * in turn, empty. ++ * Remember though, that we are still in A. We cannot ++ * just pass control to the type T decoder. Why? Because ++ * the type T decoder expects <4> <0>, not <5> <0>. ++ * So, we must make sure we are going to receive <5> while ++ * still in A, then pass control to the T decoder, indicating ++ * that the tag <4> was implicitly skipped. The decoder of T ++ * hence will be prepared to treat <4> as valid tag, and decode ++ * it appropriately. ++ */ ++ ++ tagno = step /* Continuing where left previously */ ++ + (tag_mode==1?-1:0) ++ ; ++ ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)", ++ td->name, (long)size, tag_mode, step, tagno); ++ /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */ ++ ++ if(tag_mode == 0 && tagno == td->tags_count) { ++ /* ++ * This must be the _untagged_ ANY type, ++ * which outermost tag isn't known in advance. ++ * Fetch the tag and length separately. ++ */ ++ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); ++ switch(tag_len) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ } ++ tlv_constr = BER_TLV_CONSTRUCTED(ptr); ++ len_len = ber_fetch_length(tlv_constr, ++ (const char *)ptr + tag_len, size - tag_len, &tlv_len); ++ switch(len_len) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ } ++ ASN_DEBUG("Advancing %ld in ANY case", ++ (long)(tag_len + len_len)); ++ ADVANCE(tag_len + len_len); ++ } else { ++ assert(tagno < td->tags_count); /* At least one loop */ ++ } ++ for((void)tagno; tagno < td->tags_count; tagno++, step++) { ++ ++ /* ++ * Fetch and process T from TLV. ++ */ ++ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); ++ ASN_DEBUG("Fetching tag from {%p,%ld}: " ++ "len %ld, step %d, tagno %d got %s", ++ ptr, (long)size, ++ (long)tag_len, step, tagno, ++ ber_tlv_tag_string(tlv_tag)); ++ switch(tag_len) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ } ++ ++ tlv_constr = BER_TLV_CONSTRUCTED(ptr); ++ ++ /* ++ * If {I}, don't check anything. ++ * If {I,B,C}, check B and C unless we're at I. ++ */ ++ if(tag_mode != 0 && step == 0) { ++ /* ++ * We don't expect tag to match here. ++ * It's just because we don't know how the tag ++ * is supposed to look like. ++ */ ++ } else { ++ assert(tagno >= 0); /* Guaranteed by the code above */ ++ if(tlv_tag != td->tags[tagno]) { ++ /* ++ * Unexpected tag. Too bad. ++ */ ++ ASN_DEBUG("Expected: %s, " ++ "expectation failed (tn=%d, tm=%d)", ++ ber_tlv_tag_string(td->tags[tagno]), ++ tagno, tag_mode ++ ); ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ /* ++ * Attention: if there are more tags expected, ++ * ensure that the current tag is presented ++ * in constructed form (it contains other tags!). ++ * If this one is the last one, check that the tag form ++ * matches the one given in descriptor. ++ */ ++ if(tagno < (td->tags_count - 1)) { ++ if(tlv_constr == 0) { ++ ASN_DEBUG("tlv_constr = %d, expfail", ++ tlv_constr); ++ RETURN(RC_FAIL); ++ } ++ } else { ++ if(last_tag_form != tlv_constr ++ && last_tag_form != -1) { ++ ASN_DEBUG("last_tag_form %d != %d", ++ last_tag_form, tlv_constr); ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ /* ++ * Fetch and process L from TLV. ++ */ ++ len_len = ber_fetch_length(tlv_constr, ++ (const char *)ptr + tag_len, size - tag_len, &tlv_len); ++ ASN_DEBUG("Fetchinig len = %ld", (long)len_len); ++ switch(len_len) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ } ++ ++ /* ++ * FIXME ++ * As of today, the chain of tags ++ * must either contain several indefinite length TLVs, ++ * or several definite length ones. ++ * No mixing is allowed. ++ */ ++ if(tlv_len == -1) { ++ /* ++ * Indefinite length. ++ */ ++ if(limit_len == -1) { ++ expect_00_terminators++; ++ } else { ++ ASN_DEBUG("Unexpected indefinite length " ++ "in a chain of definite lengths"); ++ RETURN(RC_FAIL); ++ } ++ ADVANCE(tag_len + len_len); ++ continue; ++ } else { ++ if(expect_00_terminators) { ++ ASN_DEBUG("Unexpected definite length " ++ "in a chain of indefinite lengths"); ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ /* ++ * Check that multiple TLVs specify ever decreasing length, ++ * which is consistent. ++ */ ++ if(limit_len == -1) { ++ limit_len = tlv_len + tag_len + len_len; ++ if(limit_len < 0) { ++ /* Too great tlv_len value? */ ++ RETURN(RC_FAIL); ++ } ++ } else if(limit_len != tlv_len + tag_len + len_len) { ++ /* ++ * Inner TLV specifies length which is inconsistent ++ * with the outer TLV's length value. ++ */ ++ ASN_DEBUG("Outer TLV is %ld and inner is %ld", ++ (long)limit_len, (long)tlv_len); ++ RETURN(RC_FAIL); ++ } ++ ++ ADVANCE(tag_len + len_len); ++ ++ limit_len -= (tag_len + len_len); ++ if((ssize_t)size > limit_len) { ++ /* ++ * Make sure that we won't consume more bytes ++ * from the parent frame than the inferred limit. ++ */ ++ size = limit_len; ++ } ++ } ++ ++ if(opt_tlv_form) ++ *opt_tlv_form = tlv_constr; ++ if(expect_00_terminators) ++ *last_length = -expect_00_terminators; ++ else ++ *last_length = tlv_len; ++ ++ RETURN(RC_OK); ++} +diff --git a/asn1/asn1c/ber_decoder.h b/asn1/asn1c/ber_decoder.h +new file mode 100644 +index 0000000000000000000000000000000000000000..768133b67e75b4eb18e523e1943245e17ce9b3aa +--- /dev/null ++++ b/asn1/asn1c/ber_decoder.h +@@ -0,0 +1,63 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _BER_DECODER_H_ ++#define _BER_DECODER_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++struct asn_codec_ctx_s; /* Forward declaration */ ++ ++/* ++ * The BER decoder of any type. ++ * This function may be invoked directly from the application. ++ */ ++asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void **struct_ptr, /* Pointer to a target structure's pointer */ ++ const void *buffer, /* Data to be decoded */ ++ size_t size /* Size of that buffer */ ++ ); ++ ++/* ++ * Type of generic function which decodes the byte stream into the structure. ++ */ ++typedef asn_dec_rval_t (ber_type_decoder_f)( ++ struct asn_codec_ctx_s *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void **struct_ptr, const void *buf_ptr, size_t size, ++ int tag_mode); ++ ++/******************************* ++ * INTERNALLY USEFUL FUNCTIONS * ++ *******************************/ ++ ++/* ++ * Check that all tags correspond to the type definition (as given in head). ++ * On return, last_length would contain either a non-negative length of the ++ * value part of the last TLV, or the negative number of expected ++ * "end of content" sequences. The number may only be negative if the ++ * head->last_tag_form is non-zero. ++ */ ++asn_dec_rval_t ber_check_tags( ++ struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ asn_struct_ctx_t *opt_ctx, /* saved decoding context */ ++ const void *ptr, size_t size, ++ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ ++ int last_tag_form, /* {-1,0:1}: any, primitive, constr */ ++ ber_tlv_len_t *last_length, ++ int *opt_tlv_form /* optional tag form */ ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _BER_DECODER_H_ */ +diff --git a/asn1/asn1c/ber_tlv_length.c b/asn1/asn1c/ber_tlv_length.c +new file mode 100644 +index 0000000000000000000000000000000000000000..b87e75e0469887ee7d06bfb5f83b99b8120a5374 +--- /dev/null ++++ b/asn1/asn1c/ber_tlv_length.c +@@ -0,0 +1,178 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++ssize_t ++ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, ++ ber_tlv_len_t *len_r) { ++ const uint8_t *buf = (const uint8_t *)bufptr; ++ unsigned oct; ++ ++ if(size == 0) ++ return 0; /* Want more */ ++ ++ oct = *(const uint8_t *)buf; ++ if((oct & 0x80) == 0) { ++ /* ++ * Short definite length. ++ */ ++ *len_r = oct; /* & 0x7F */ ++ return 1; ++ } else { ++ ber_tlv_len_t len; ++ size_t skipped; ++ ++ if(_is_constructed && oct == 0x80) { ++ *len_r = -1; /* Indefinite length */ ++ return 1; ++ } ++ ++ if(oct == 0xff) { ++ /* Reserved in standard for future use. */ ++ return -1; ++ } ++ ++ oct &= 0x7F; /* Leave only the 7 LS bits */ ++ for(len = 0, buf++, skipped = 1; ++ oct && (++skipped <= size); buf++, oct--) { ++ ++ len = (len << 8) | *buf; ++ if(len < 0 ++ || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) { ++ /* ++ * Too large length value. ++ */ ++ return -1; ++ } ++ } ++ ++ if(oct == 0) { ++ ber_tlv_len_t lenplusepsilon = (size_t)len + 1024; ++ /* ++ * Here length may be very close or equal to 2G. ++ * However, the arithmetics used in some decoders ++ * may add some (small) quantities to the length, ++ * to check the resulting value against some limits. ++ * This may result in integer wrap-around, which ++ * we try to avoid by checking it earlier here. ++ */ ++ if(lenplusepsilon < 0) { ++ /* Too large length value */ ++ return -1; ++ } ++ ++ *len_r = len; ++ return skipped; ++ } ++ ++ return 0; /* Want more */ ++ } ++ ++} ++ ++ssize_t ++ber_skip_length(asn_codec_ctx_t *opt_codec_ctx, ++ int _is_constructed, const void *ptr, size_t size) { ++ ber_tlv_len_t vlen; /* Length of V in TLV */ ++ ssize_t tl; /* Length of L in TLV */ ++ ssize_t ll; /* Length of L in TLV */ ++ size_t skip; ++ ++ /* ++ * Make sure we didn't exceed the maximum stack size. ++ */ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ return -1; ++ ++ /* ++ * Determine the size of L in TLV. ++ */ ++ ll = ber_fetch_length(_is_constructed, ptr, size, &vlen); ++ if(ll <= 0) return ll; ++ ++ /* ++ * Definite length. ++ */ ++ if(vlen >= 0) { ++ skip = ll + vlen; ++ if(skip > size) ++ return 0; /* Want more */ ++ return skip; ++ } ++ ++ /* ++ * Indefinite length! ++ */ ++ ASN_DEBUG("Skipping indefinite length"); ++ for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) { ++ ber_tlv_tag_t tag; ++ ++ /* Fetch the tag */ ++ tl = ber_fetch_tag(ptr, size, &tag); ++ if(tl <= 0) return tl; ++ ++ ll = ber_skip_length(opt_codec_ctx, ++ BER_TLV_CONSTRUCTED(ptr), ++ ((const char *)ptr) + tl, size - tl); ++ if(ll <= 0) return ll; ++ ++ skip += tl + ll; ++ ++ /* ++ * This may be the end of the indefinite length structure, ++ * two consecutive 0 octets. ++ * Check if it is true. ++ */ ++ if(((const uint8_t *)ptr)[0] == 0 ++ && ((const uint8_t *)ptr)[1] == 0) ++ return skip; ++ ++ ptr = ((const char *)ptr) + tl + ll; ++ size -= tl + ll; ++ } ++ ++ /* UNREACHABLE */ ++} ++ ++size_t ++der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) { ++ size_t required_size; /* Size of len encoding */ ++ uint8_t *buf = (uint8_t *)bufp; ++ uint8_t *end; ++ size_t i; ++ ++ if(len <= 127) { ++ /* Encoded in 1 octet */ ++ if(size) *buf = (uint8_t)len; ++ return 1; ++ } ++ ++ /* ++ * Compute the size of the subsequent bytes. ++ */ ++ for(required_size = 1, i = 8; i < 8 * sizeof(len); i += 8) { ++ if(len >> i) ++ required_size++; ++ else ++ break; ++ } ++ ++ if(size <= required_size) ++ return required_size + 1; ++ ++ *buf++ = (uint8_t)(0x80 | required_size); /* Length of the encoding */ ++ ++ /* ++ * Produce the len encoding, space permitting. ++ */ ++ end = buf + required_size; ++ for(i -= 8; buf < end; i -= 8, buf++) ++ *buf = (uint8_t)(len >> i); ++ ++ return required_size + 1; ++} ++ +diff --git a/asn1/asn1c/ber_tlv_length.h b/asn1/asn1c/ber_tlv_length.h +new file mode 100644 +index 0000000000000000000000000000000000000000..3496802244013c6c3652d5d067bccdf022e719cf +--- /dev/null ++++ b/asn1/asn1c/ber_tlv_length.h +@@ -0,0 +1,50 @@ ++/*- ++ * Copyright (c) 2003 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _BER_TLV_LENGTH_H_ ++#define _BER_TLV_LENGTH_H_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef ssize_t ber_tlv_len_t; ++ ++/* ++ * This function tries to fetch the length of the BER TLV value and place it ++ * in *len_r. ++ * RETURN VALUES: ++ * 0: More data expected than bufptr contains. ++ * -1: Fatal error deciphering length. ++ * >0: Number of bytes used from bufptr. ++ * On return with >0, len_r is constrained as -1..MAX, where -1 mean ++ * that the value is of indefinite length. ++ */ ++ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, ++ ber_tlv_len_t *len_r); ++ ++/* ++ * This function expects bufptr to be positioned over L in TLV. ++ * It returns number of bytes occupied by L and V together, suitable ++ * for skipping. The function properly handles indefinite length. ++ * RETURN VALUES: ++ * Standard {-1,0,>0} convention. ++ */ ++ssize_t ber_skip_length( ++ struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ ++ int _is_constructed, const void *bufptr, size_t size); ++ ++/* ++ * This function serializes the length (L from TLV) in DER format. ++ * It always returns number of bytes necessary to represent the length, ++ * it is a caller's responsibility to check the return value ++ * against the supplied buffer's size. ++ */ ++size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _BER_TLV_LENGTH_H_ */ +diff --git a/asn1/asn1c/ber_tlv_tag.c b/asn1/asn1c/ber_tlv_tag.c +new file mode 100644 +index 0000000000000000000000000000000000000000..42708760e089948b405743678efbc56ddd836c87 +--- /dev/null ++++ b/asn1/asn1c/ber_tlv_tag.c +@@ -0,0 +1,144 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++ssize_t ++ber_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) { ++ ber_tlv_tag_t val; ++ ber_tlv_tag_t tclass; ++ size_t skipped; ++ ++ if(size == 0) ++ return 0; ++ ++ val = *(const uint8_t *)ptr; ++ tclass = (val >> 6); ++ if((val &= 0x1F) != 0x1F) { ++ /* ++ * Simple form: everything encoded in a single octet. ++ * Tag Class is encoded using two least significant bits. ++ */ ++ *tag_r = (val << 2) | tclass; ++ return 1; ++ } ++ ++ /* ++ * Each octet contains 7 bits of useful information. ++ * The MSB is 0 if it is the last octet of the tag. ++ */ ++ for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; ++ skipped <= size; ++ ptr = ((const char *)ptr) + 1, skipped++) { ++ unsigned int oct = *(const uint8_t *)ptr; ++ if(oct & 0x80) { ++ val = (val << 7) | (oct & 0x7F); ++ /* ++ * Make sure there are at least 9 bits spare ++ * at the MS side of a value. ++ */ ++ if(val >> ((8 * sizeof(val)) - 9)) { ++ /* ++ * We would not be able to accomodate ++ * any more tag bits. ++ */ ++ return -1; ++ } ++ } else { ++ val = (val << 7) | oct; ++ *tag_r = (val << 2) | tclass; ++ return skipped; ++ } ++ } ++ ++ return 0; /* Want more */ ++} ++ ++ ++ssize_t ++ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) { ++ char buf[sizeof("[APPLICATION ]") + 32]; ++ ssize_t ret; ++ ++ ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf)); ++ if(ret >= (ssize_t)sizeof(buf) || ret < 2) { ++ errno = EPERM; ++ return -1; ++ } ++ ++ return fwrite(buf, 1, ret, f); ++} ++ ++ssize_t ++ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) { ++ char *type = 0; ++ int ret; ++ ++ switch(tag & 0x3) { ++ case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break; ++ case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break; ++ case ASN_TAG_CLASS_CONTEXT: type = ""; break; ++ case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break; ++ } ++ ++ ret = snprintf(buf, size, "[%s%u]", type, ((unsigned)tag) >> 2); ++ if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */ ++ ++ return ret; ++} ++ ++char * ++ber_tlv_tag_string(ber_tlv_tag_t tag) { ++ static char buf[sizeof("[APPLICATION ]") + 32]; ++ ++ (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf)); ++ ++ return buf; ++} ++ ++ ++size_t ++ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) { ++ int tclass = BER_TAG_CLASS(tag); ++ ber_tlv_tag_t tval = BER_TAG_VALUE(tag); ++ uint8_t *buf = (uint8_t *)bufp; ++ uint8_t *end; ++ size_t required_size; ++ size_t i; ++ ++ if(tval <= 30) { ++ /* Encoded in 1 octet */ ++ if(size) buf[0] = (tclass << 6) | tval; ++ return 1; ++ } else if(size) { ++ *buf++ = (tclass << 6) | 0x1F; ++ size--; ++ } ++ ++ /* ++ * Compute the size of the subsequent bytes. ++ */ ++ for(required_size = 1, i = 7; i < 8 * sizeof(tval); i += 7) { ++ if(tval >> i) ++ required_size++; ++ else ++ break; ++ } ++ ++ if(size < required_size) ++ return required_size + 1; ++ ++ /* ++ * Fill in the buffer, space permitting. ++ */ ++ end = buf + required_size - 1; ++ for(i -= 7; buf < end; i -= 7, buf++) ++ *buf = 0x80 | ((tval >> i) & 0x7F); ++ *buf = (tval & 0x7F); /* Last octet without high bit */ ++ ++ return required_size + 1; ++} ++ +diff --git a/asn1/asn1c/ber_tlv_tag.h b/asn1/asn1c/ber_tlv_tag.h +new file mode 100644 +index 0000000000000000000000000000000000000000..60e866861b28b3861f1e482452dcde1c844e5253 +--- /dev/null ++++ b/asn1/asn1c/ber_tlv_tag.h +@@ -0,0 +1,60 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _BER_TLV_TAG_H_ ++#define _BER_TLV_TAG_H_ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++enum asn_tag_class { ++ ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ ++ ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ ++ ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ ++ ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ ++}; ++typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ ++ ++/* ++ * Tag class is encoded together with tag value for optimization purposes. ++ */ ++#define BER_TAG_CLASS(tag) ((tag) & 0x3) ++#define BER_TAG_VALUE(tag) ((tag) >> 2) ++#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) ++ ++#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) ++ ++/* ++ * Several functions for printing the TAG in the canonical form ++ * (i.e. "[PRIVATE 0]"). ++ * Return values correspond to their libc counterparts (if any). ++ */ ++ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); ++ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); ++char *ber_tlv_tag_string(ber_tlv_tag_t tag); ++ ++ ++/* ++ * This function tries to fetch the tag from the input stream. ++ * RETURN VALUES: ++ * 0: More data expected than bufptr contains. ++ * -1: Fatal error deciphering tag. ++ * >0: Number of bytes used from bufptr. tag_r will contain the tag. ++ */ ++ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); ++ ++/* ++ * This function serializes the tag (T from TLV) in BER format. ++ * It always returns number of bytes necessary to represent the tag, ++ * it is a caller's responsibility to check the return value ++ * against the supplied buffer's size. ++ */ ++size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _BER_TLV_TAG_H_ */ +diff --git a/asn1/asn1c/constr_CHOICE.c b/asn1/asn1c/constr_CHOICE.c +new file mode 100644 +index 0000000000000000000000000000000000000000..b8d6fa9a7f210585e851f8f1ab3cadf1d8fe4923 +--- /dev/null ++++ b/asn1/asn1c/constr_CHOICE.c +@@ -0,0 +1,1101 @@ ++/* ++ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++ ++/* ++ * Number of bytes left for this structure. ++ * (ctx->left) indicates the number of bytes _transferred_ for the structure. ++ * (size) contains the number of bytes in the buffer passed. ++ */ ++#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) ++ ++/* ++ * If the subprocessor function returns with an indication that it wants ++ * more data, it may well be a fatal decoding problem, because the ++ * size is constrained by the 's L, even if the buffer size allows ++ * reading more data. ++ * For example, consider the buffer containing the following TLVs: ++ * ... ++ * The TLV length clearly indicates that one byte is expected in V, but ++ * if the V processor returns with "want more data" even if the buffer ++ * contains way more data than the V processor have seen. ++ */ ++#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) ++ ++/* ++ * This macro "eats" the part of the buffer which is definitely "consumed", ++ * i.e. was correctly converted into local representation or rightfully skipped. ++ */ ++#undef ADVANCE ++#define ADVANCE(num_bytes) do { \ ++ size_t num = num_bytes; \ ++ ptr = ((const char *)ptr) + num;\ ++ size -= num; \ ++ if(ctx->left >= 0) \ ++ ctx->left -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++/* ++ * Switch to the next phase of parsing. ++ */ ++#undef NEXT_PHASE ++#define NEXT_PHASE(ctx) do { \ ++ ctx->phase++; \ ++ ctx->step = 0; \ ++ } while(0) ++ ++/* ++ * Return a standardized complex structure. ++ */ ++#undef RETURN ++#define RETURN(_code) do { \ ++ rval.code = _code; \ ++ rval.consumed = consumed_myself;\ ++ return rval; \ ++ } while(0) ++ ++/* ++ * See the definitions. ++ */ ++static int _fetch_present_idx(const void *struct_ptr, int off, int size); ++static void _set_present_idx(void *sptr, int offset, int size, int pres); ++ ++/* ++ * Tags are canonically sorted in the tag to member table. ++ */ ++static int ++_search4tag(const void *ap, const void *bp) { ++ const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; ++ const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; ++ ++ int a_class = BER_TAG_CLASS(a->el_tag); ++ int b_class = BER_TAG_CLASS(b->el_tag); ++ ++ if(a_class == b_class) { ++ ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); ++ ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); ++ ++ if(a_value == b_value) ++ return 0; ++ else if(a_value < b_value) ++ return -1; ++ else ++ return 1; ++ } else if(a_class < b_class) { ++ return -1; ++ } else { ++ return 1; ++ } ++} ++ ++/* ++ * The decoder of the CHOICE type. ++ */ ++asn_dec_rval_t ++CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **struct_ptr, const void *ptr, size_t size, int tag_mode) { ++ /* ++ * Bring closer parts of structure description. ++ */ ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elements = td->elements; ++ ++ /* ++ * Parts of the structure being constructed. ++ */ ++ void *st = *struct_ptr; /* Target structure. */ ++ asn_struct_ctx_t *ctx; /* Decoder context */ ++ ++ ber_tlv_tag_t tlv_tag; /* T from TLV */ ++ ssize_t tag_len; /* Length of TLV's T */ ++ asn_dec_rval_t rval; /* Return code from subparsers */ ++ ++ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ ++ ++ ASN_DEBUG("Decoding %s as CHOICE", td->name); ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(st == 0) { ++ st = *struct_ptr = CALLOC(1, specs->struct_size); ++ if(st == 0) { ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ /* ++ * Restore parsing context. ++ */ ++ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); ++ ++ /* ++ * Start to parse where left previously ++ */ ++ switch(ctx->phase) { ++ case 0: ++ /* ++ * PHASE 0. ++ * Check that the set of tags associated with given structure ++ * perfectly fits our expectations. ++ */ ++ ++ if(tag_mode || td->tags_count) { ++ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, ++ tag_mode, -1, &ctx->left, 0); ++ if(rval.code != RC_OK) { ++ ASN_DEBUG("%s tagging check failed: %d", ++ td->name, rval.code); ++ return rval; ++ } ++ ++ if(ctx->left >= 0) { ++ /* ?Substracted below! */ ++ ctx->left += rval.consumed; ++ } ++ ADVANCE(rval.consumed); ++ } else { ++ ctx->left = -1; ++ } ++ ++ NEXT_PHASE(ctx); ++ ++ ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", ++ (long)ctx->left, (long)size); ++ ++ /* Fall through */ ++ case 1: ++ /* ++ * Fetch the T from TLV. ++ */ ++ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); ++ ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len); ++ switch(tag_len) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ do { ++ asn_TYPE_tag2member_t *t2m; ++ asn_TYPE_tag2member_t key; ++ ++ key.el_tag = tlv_tag; ++ t2m = (asn_TYPE_tag2member_t *)bsearch(&key, ++ specs->tag2el, specs->tag2el_count, ++ sizeof(specs->tag2el[0]), _search4tag); ++ if(t2m) { ++ /* ++ * Found the element corresponding to the tag. ++ */ ++ NEXT_PHASE(ctx); ++ ctx->step = t2m->el_no; ++ break; ++ } else if(specs->ext_start == -1) { ++ ASN_DEBUG("Unexpected tag %s " ++ "in non-extensible CHOICE %s", ++ ber_tlv_tag_string(tlv_tag), td->name); ++ RETURN(RC_FAIL); ++ } else { ++ /* Skip this tag */ ++ ssize_t skip; ++ ++ ASN_DEBUG("Skipping unknown tag %s", ++ ber_tlv_tag_string(tlv_tag)); ++ ++ skip = ber_skip_length(opt_codec_ctx, ++ BER_TLV_CONSTRUCTED(ptr), ++ (const char *)ptr + tag_len, ++ LEFT - tag_len); ++ ++ switch(skip) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ ADVANCE(skip + tag_len); ++ RETURN(RC_OK); ++ } ++ } while(0); ++ ++ case 2: ++ /* ++ * PHASE 2. ++ * Read in the element. ++ */ ++ do { ++ asn_TYPE_member_t *elm;/* CHOICE's element */ ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ elm = &elements[ctx->step]; ++ ++ /* ++ * Compute the position of the member inside a structure, ++ * and also a type of containment (it may be contained ++ * as pointer or using inline inclusion). ++ */ ++ if(elm->flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr2 = (void **)((char *)st + elm->memb_offset); ++ } else { ++ /* ++ * A pointer to a pointer ++ * holding the start of the structure ++ */ ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ /* Set presence to be able to free it properly at any time */ ++ _set_present_idx(st, specs->pres_offset, ++ specs->pres_size, ctx->step + 1); ++ /* ++ * Invoke the member fetch routine according to member's type ++ */ ++ rval = elm->type->ber_decoder(opt_codec_ctx, elm->type, ++ memb_ptr2, ptr, LEFT, elm->tag_mode); ++ switch(rval.code) { ++ case RC_OK: ++ break; ++ case RC_WMORE: /* More data expected */ ++ if(!SIZE_VIOLATION) { ++ ADVANCE(rval.consumed); ++ RETURN(RC_WMORE); ++ } ++ RETURN(RC_FAIL); ++ case RC_FAIL: /* Fatal error */ ++ RETURN(rval.code); ++ } /* switch(rval) */ ++ ++ ADVANCE(rval.consumed); ++ } while(0); ++ ++ NEXT_PHASE(ctx); ++ ++ /* Fall through */ ++ case 3: ++ ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d", ++ td->name, (long)ctx->left, (long)size, ++ tag_mode, td->tags_count); ++ ++ if(ctx->left > 0) { ++ /* ++ * The type must be fully decoded ++ * by the CHOICE member-specific decoder. ++ */ ++ RETURN(RC_FAIL); ++ } ++ ++ if(ctx->left == -1 ++ && !(tag_mode || td->tags_count)) { ++ /* ++ * This is an untagged CHOICE. ++ * It doesn't contain nothing ++ * except for the member itself, including all its tags. ++ * The decoding is completed. ++ */ ++ NEXT_PHASE(ctx); ++ break; ++ } ++ ++ /* ++ * Read in the "end of data chunks"'s. ++ */ ++ while(ctx->left < 0) { ++ ssize_t tl; ++ ++ tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); ++ switch(tl) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ /* ++ * Expected <0><0>... ++ */ ++ if(((const uint8_t *)ptr)[0] == 0) { ++ if(LEFT < 2) { ++ if(SIZE_VIOLATION) ++ RETURN(RC_FAIL); ++ else ++ RETURN(RC_WMORE); ++ } else if(((const uint8_t *)ptr)[1] == 0) { ++ /* ++ * Correctly finished with <0><0>. ++ */ ++ ADVANCE(2); ++ ctx->left++; ++ continue; ++ } ++ } else { ++ ASN_DEBUG("Unexpected continuation in %s", ++ td->name); ++ RETURN(RC_FAIL); ++ } ++ ++ /* UNREACHABLE */ ++ } ++ ++ NEXT_PHASE(ctx); ++ case 4: ++ /* No meaningful work here */ ++ break; ++ } ++ ++ RETURN(RC_OK); ++} ++ ++asn_enc_rval_t ++CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr, ++ int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm; /* CHOICE element */ ++ asn_enc_rval_t erval; ++ void *memb_ptr; ++ size_t computed_size = 0; ++ int present; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ ++ ASN_DEBUG("%s %s as CHOICE", ++ cb?"Encoding":"Estimating", td->name); ++ ++ present = _fetch_present_idx(sptr, ++ specs->pres_offset, specs->pres_size); ++ ++ /* ++ * If the structure was not initialized, it cannot be encoded: ++ * can't deduce what to encode in the choice type. ++ */ ++ if(present <= 0 || present > td->elements_count) { ++ if(present == 0 && td->elements_count == 0) { ++ /* The CHOICE is empty?! */ ++ erval.encoded = 0; ++ _ASN_ENCODED_OK(erval); ++ } ++ _ASN_ENCODE_FAILED; ++ } ++ ++ /* ++ * Seek over the present member of the structure. ++ */ ++ elm = &td->elements[present-1]; ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(memb_ptr == 0) { ++ if(elm->optional) { ++ erval.encoded = 0; ++ _ASN_ENCODED_OK(erval); ++ } ++ /* Mandatory element absent */ ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ } ++ ++ /* ++ * If the CHOICE itself is tagged EXPLICIT: ++ * T ::= [2] EXPLICIT CHOICE { ... } ++ * Then emit the appropriate tags. ++ */ ++ if(tag_mode == 1 || td->tags_count) { ++ /* ++ * For this, we need to pre-compute the member. ++ */ ++ ssize_t ret; ++ ++ /* Encode member with its tag */ ++ erval = elm->type->der_encoder(elm->type, memb_ptr, ++ elm->tag_mode, elm->tag, 0, 0); ++ if(erval.encoded == -1) ++ return erval; ++ ++ /* Encode CHOICE with parent or my own tag */ ++ ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag, ++ cb, app_key); ++ if(ret == -1) ++ _ASN_ENCODE_FAILED; ++ computed_size += ret; ++ } ++ ++ /* ++ * Encode the single underlying member. ++ */ ++ erval = elm->type->der_encoder(elm->type, memb_ptr, ++ elm->tag_mode, elm->tag, cb, app_key); ++ if(erval.encoded == -1) ++ return erval; ++ ++ ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)", ++ (long)erval.encoded, (long)computed_size); ++ ++ erval.encoded += computed_size; ++ ++ return erval; ++} ++ ++ber_tlv_tag_t ++CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ int present; ++ ++ assert(tag_mode == 0); (void)tag_mode; ++ assert(tag == 0); (void)tag; ++ ++ /* ++ * Figure out which CHOICE element is encoded. ++ */ ++ present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); ++ ++ if(present > 0 || present <= td->elements_count) { ++ asn_TYPE_member_t *elm = &td->elements[present-1]; ++ const void *memb_ptr; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(const void * const *) ++ ((const char *)ptr + elm->memb_offset); ++ } else { ++ memb_ptr = (const void *) ++ ((const char *)ptr + elm->memb_offset); ++ } ++ ++ return asn_TYPE_outmost_tag(elm->type, memb_ptr, ++ elm->tag_mode, elm->tag); ++ } else { ++ return (ber_tlv_tag_t)-1; ++ } ++} ++ ++int ++CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, ++ asn_app_constraint_failed_f *ctfailcb, void *app_key) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ int present; ++ ++ if(!sptr) { ++ _ASN_CTFAIL(app_key, td, ++ "%s: value not given (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++ ++ /* ++ * Figure out which CHOICE element is encoded. ++ */ ++ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); ++ if(present > 0 && present <= td->elements_count) { ++ asn_TYPE_member_t *elm = &td->elements[present-1]; ++ const void *memb_ptr; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); ++ if(!memb_ptr) { ++ if(elm->optional) ++ return 0; ++ _ASN_CTFAIL(app_key, td, ++ "%s: mandatory CHOICE element %s absent (%s:%d)", ++ td->name, elm->name, __FILE__, __LINE__); ++ return -1; ++ } ++ } else { ++ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); ++ } ++ ++ if(elm->memb_constraints) { ++ return elm->memb_constraints(elm->type, memb_ptr, ++ ctfailcb, app_key); ++ } else { ++ int ret = elm->type->check_constraints(elm->type, ++ memb_ptr, ctfailcb, app_key); ++ /* ++ * Cannot inherit it eralier: ++ * need to make sure we get the updated version. ++ */ ++ elm->memb_constraints = elm->type->check_constraints; ++ return ret; ++ } ++ } else { ++ _ASN_CTFAIL(app_key, td, ++ "%s: no CHOICE element given (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++} ++ ++#undef XER_ADVANCE ++#define XER_ADVANCE(num_bytes) do { \ ++ size_t num = num_bytes; \ ++ buf_ptr = ((const char *)buf_ptr) + num;\ ++ size -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++/* ++ * Decode the XER (XML) data. ++ */ ++asn_dec_rval_t ++CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **struct_ptr, const char *opt_mname, ++ const void *buf_ptr, size_t size) { ++ /* ++ * Bring closer parts of structure description. ++ */ ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; ++ ++ /* ++ * Parts of the structure being constructed. ++ */ ++ void *st = *struct_ptr; /* Target structure. */ ++ asn_struct_ctx_t *ctx; /* Decoder context */ ++ ++ asn_dec_rval_t rval; /* Return value of a decoder */ ++ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ ++ int edx; /* Element index */ ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(st == 0) { ++ st = *struct_ptr = CALLOC(1, specs->struct_size); ++ if(st == 0) RETURN(RC_FAIL); ++ } ++ ++ /* ++ * Restore parsing context. ++ */ ++ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); ++ if(ctx->phase == 0 && !*xml_tag) ++ ctx->phase = 1; /* Skip the outer tag checking phase */ ++ ++ /* ++ * Phases of XER/XML processing: ++ * Phase 0: Check that the opening tag matches our expectations. ++ * Phase 1: Processing body and reacting on closing tag. ++ * Phase 2: Processing inner type. ++ * Phase 3: Only waiting for closing tag. ++ * Phase 4: Skipping unknown extensions. ++ * Phase 5: PHASED OUT ++ */ ++ for(edx = ctx->step; ctx->phase <= 4;) { ++ pxer_chunk_type_e ch_type; /* XER chunk type */ ++ ssize_t ch_size; /* Chunk size */ ++ xer_check_tag_e tcv; /* Tag check value */ ++ asn_TYPE_member_t *elm; ++ ++ /* ++ * Go inside the member. ++ */ ++ if(ctx->phase == 2) { ++ asn_dec_rval_t tmprval; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ elm = &td->elements[edx]; ++ ++ if(elm->flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr2 = (void **)((char *)st ++ + elm->memb_offset); ++ } else { ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ /* Start/Continue decoding the inner member */ ++ tmprval = elm->type->xer_decoder(opt_codec_ctx, ++ elm->type, memb_ptr2, elm->name, ++ buf_ptr, size); ++ XER_ADVANCE(tmprval.consumed); ++ ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d", ++ elm->type->name, tmprval.code); ++ if(tmprval.code != RC_OK) ++ RETURN(tmprval.code); ++ assert(_fetch_present_idx(st, ++ specs->pres_offset, specs->pres_size) == 0); ++ /* Record what we've got */ ++ _set_present_idx(st, ++ specs->pres_offset, specs->pres_size, edx + 1); ++ ctx->phase = 3; ++ /* Fall through */ ++ } ++ ++ /* No need to wait for closing tag; special mode. */ ++ if(ctx->phase == 3 && !*xml_tag) { ++ ctx->phase = 5; /* Phase out */ ++ RETURN(RC_OK); ++ } ++ ++ /* ++ * Get the next part of the XML stream. ++ */ ++ ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type); ++ switch(ch_size) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ default: ++ switch(ch_type) { ++ case PXER_COMMENT: /* Got XML comment */ ++ case PXER_TEXT: /* Ignore free-standing text */ ++ XER_ADVANCE(ch_size); /* Skip silently */ ++ continue; ++ case PXER_TAG: ++ break; /* Check the rest down there */ ++ } ++ } ++ ++ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); ++ ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d", ++ ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', ++ ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', ++ ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', ++ ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', ++ xml_tag, tcv); ++ ++ /* Skip the extensions section */ ++ if(ctx->phase == 4) { ++ ASN_DEBUG("skip_unknown(%d, %ld)", ++ tcv, (long)ctx->left); ++ switch(xer_skip_unknown(tcv, &ctx->left)) { ++ case -1: ++ ctx->phase = 5; ++ RETURN(RC_FAIL); ++ continue; ++ case 1: ++ ctx->phase = 3; ++ /* Fall through */ ++ case 0: ++ XER_ADVANCE(ch_size); ++ continue; ++ case 2: ++ ctx->phase = 3; ++ break; ++ } ++ } ++ ++ switch(tcv) { ++ case XCT_BOTH: ++ break; /* No CHOICE? */ ++ case XCT_CLOSING: ++ if(ctx->phase != 3) ++ break; ++ XER_ADVANCE(ch_size); ++ ctx->phase = 5; /* Phase out */ ++ RETURN(RC_OK); ++ case XCT_OPENING: ++ if(ctx->phase == 0) { ++ XER_ADVANCE(ch_size); ++ ctx->phase = 1; /* Processing body phase */ ++ continue; ++ } ++ /* Fall through */ ++ case XCT_UNKNOWN_OP: ++ case XCT_UNKNOWN_BO: ++ ++ if(ctx->phase != 1) ++ break; /* Really unexpected */ ++ ++ /* ++ * Search which inner member corresponds to this tag. ++ */ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ elm = &td->elements[edx]; ++ tcv = xer_check_tag(buf_ptr,ch_size,elm->name); ++ switch(tcv) { ++ case XCT_BOTH: ++ case XCT_OPENING: ++ /* ++ * Process this member. ++ */ ++ ctx->step = edx; ++ ctx->phase = 2; ++ break; ++ case XCT_UNKNOWN_OP: ++ case XCT_UNKNOWN_BO: ++ continue; ++ default: ++ edx = td->elements_count; ++ break; /* Phase out */ ++ } ++ break; ++ } ++ if(edx != td->elements_count) ++ continue; ++ ++ /* It is expected extension */ ++ if(specs->ext_start != -1) { ++ ASN_DEBUG("Got anticipated extension"); ++ /* ++ * Check for (XCT_BOTH or XCT_UNKNOWN_BO) ++ * By using a mask. Only record a pure ++ * tags. ++ */ ++ if(tcv & XCT_CLOSING) { ++ /* Found without body */ ++ ctx->phase = 3; /* Terminating */ ++ } else { ++ ctx->left = 1; ++ ctx->phase = 4; /* Skip ...'s */ ++ } ++ XER_ADVANCE(ch_size); ++ continue; ++ } ++ ++ /* Fall through */ ++ default: ++ break; ++ } ++ ++ ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]" ++ " (ph=%d, tag=%s)", ++ ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', ++ ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', ++ ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', ++ ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', ++ td->name, ctx->phase, xml_tag); ++ break; ++ } ++ ++ ctx->phase = 5; /* Phase out, just in case */ ++ RETURN(RC_FAIL); ++} ++ ++ ++asn_enc_rval_t ++CHOICE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_CHOICE_specifics_t *specs=(asn_CHOICE_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ int present; ++ ++ if(!sptr) ++ _ASN_ENCODE_FAILED; ++ ++ /* ++ * Figure out which CHOICE element is encoded. ++ */ ++ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); ++ ++ if(present <= 0 || present > td->elements_count) { ++ _ASN_ENCODE_FAILED; ++ } else { ++ asn_enc_rval_t tmper; ++ asn_TYPE_member_t *elm = &td->elements[present-1]; ++ void *memb_ptr; ++ const char *mname = elm->name; ++ unsigned int mlen = strlen(mname); ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(!memb_ptr) _ASN_ENCODE_FAILED; ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ } ++ ++ er.encoded = 0; ++ ++ if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel); ++ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); ++ ++ tmper = elm->type->xer_encoder(elm->type, memb_ptr, ++ ilevel + 1, flags, cb, app_key); ++ if(tmper.encoded == -1) return tmper; ++ ++ _ASN_CALLBACK3("", 1); ++ ++ er.encoded += 5 + (2 * mlen) + tmper.encoded; ++ } ++ ++ if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel - 1); ++ ++ _ASN_ENCODED_OK(er); ++cb_failed: ++ _ASN_ENCODE_FAILED; ++} ++ ++asn_dec_rval_t ++CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ asn_dec_rval_t rv; ++ asn_per_constraint_t *ct; ++ asn_TYPE_member_t *elm; /* CHOICE's element */ ++ void *memb_ptr; ++ void **memb_ptr2; ++ void *st = *sptr; ++ int value; ++ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(!st) { ++ st = *sptr = CALLOC(1, specs->struct_size); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else ct = 0; ++ ++ if(ct && ct->flags & APC_EXTENSIBLE) { ++ value = per_get_few_bits(pd, 1); ++ if(value < 0) _ASN_DECODE_STARVED; ++ if(value) ct = 0; /* Not restricted */ ++ } ++ ++ if(ct && ct->range_bits >= 0) { ++ value = per_get_few_bits(pd, ct->range_bits); ++ if(value < 0) _ASN_DECODE_STARVED; ++ ASN_DEBUG("CHOICE %s got index %d in range %d", ++ td->name, value, ct->range_bits); ++ if(value > ct->upper_bound) ++ _ASN_DECODE_FAILED; ++ } else { ++ if(specs->ext_start == -1) ++ _ASN_DECODE_FAILED; ++ value = uper_get_nsnnwn(pd); ++ if(value < 0) _ASN_DECODE_STARVED; ++ value += specs->ext_start; ++ if(value >= td->elements_count) ++ _ASN_DECODE_FAILED; ++ ASN_DEBUG("NOT IMPLEMENTED YET"); ++ _ASN_DECODE_FAILED; ++ } ++ ++ /* Adjust if canonical order is different from natural order */ ++ if(specs->canonical_order) ++ value = specs->canonical_order[value]; ++ ++ /* Set presence to be able to free it later */ ++ _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); ++ ++ elm = &td->elements[value]; ++ if(elm->flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr2 = (void **)((char *)st + elm->memb_offset); ++ } else { ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); ++ ++ rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, ++ elm->per_constraints, memb_ptr2, pd); ++ if(rv.code != RC_OK) ++ ASN_DEBUG("Failed to decode %s in %s (CHOICE)", ++ elm->name, td->name); ++ return rv; ++} ++ ++asn_enc_rval_t ++CHOICE_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm; /* CHOICE's element */ ++ asn_per_constraint_t *ct; ++ void *memb_ptr; ++ int present; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ ++ ASN_DEBUG("Encoding %s as CHOICE", td->name); ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else ct = 0; ++ ++ present = _fetch_present_idx(sptr, ++ specs->pres_offset, specs->pres_size); ++ ++ /* ++ * If the structure was not initialized properly, it cannot be encoded: ++ * can't deduce what to encode in the choice type. ++ */ ++ if(present <= 0 || present > td->elements_count) ++ _ASN_ENCODE_FAILED; ++ else ++ present--; ++ ++ /* Adjust if canonical order is different from natural order */ ++ if(specs->canonical_order) ++ present = specs->canonical_order[present]; ++ ++ ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present); ++ ++ if(ct && ct->range_bits >= 0) { ++ if(present < ct->lower_bound ++ || present > ct->upper_bound) { ++ if(ct->flags & APC_EXTENSIBLE) { ++ if(per_put_few_bits(po, 1, 1)) ++ _ASN_ENCODE_FAILED; ++ } else { ++ _ASN_ENCODE_FAILED; ++ } ++ ct = 0; ++ } ++ } ++ if(ct && ct->flags & APC_EXTENSIBLE) ++ if(per_put_few_bits(po, 0, 1)) ++ _ASN_ENCODE_FAILED; ++ ++ if(ct && ct->range_bits >= 0) { ++ if(per_put_few_bits(po, present, ct->range_bits)) ++ _ASN_ENCODE_FAILED; ++ } else { ++ if(specs->ext_start == -1) ++ _ASN_ENCODE_FAILED; ++ if(uper_put_nsnnwn(po, present - specs->ext_start)) ++ _ASN_ENCODE_FAILED; ++ ASN_DEBUG("NOT IMPLEMENTED YET"); ++ _ASN_ENCODE_FAILED; ++ } ++ ++ elm = &td->elements[present]; ++ if(elm->flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(!memb_ptr) _ASN_ENCODE_FAILED; ++ } else { ++ memb_ptr = (char *)sptr + elm->memb_offset; ++ } ++ ++ return elm->type->uper_encoder(elm->type, elm->per_constraints, ++ memb_ptr, po); ++} ++ ++ ++int ++CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ int present; ++ ++ if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; ++ ++ /* ++ * Figure out which CHOICE element is encoded. ++ */ ++ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); ++ ++ /* ++ * Print that element. ++ */ ++ if(present > 0 && present <= td->elements_count) { ++ asn_TYPE_member_t *elm = &td->elements[present-1]; ++ const void *memb_ptr; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); ++ if(!memb_ptr) return (cb("", 8, app_key) < 0) ? -1 : 0; ++ } else { ++ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); ++ } ++ ++ /* Print member's name and stuff */ ++ if(0) { ++ if(cb(elm->name, strlen(elm->name), app_key) < 0 ++ || cb(": ", 2, app_key) < 0) ++ return -1; ++ } ++ ++ return elm->type->print_struct(elm->type, memb_ptr, ilevel, ++ cb, app_key); ++ } else { ++ return (cb("", 8, app_key) < 0) ? -1 : 0; ++ } ++} ++ ++void ++CHOICE_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ int present; ++ ++ if(!td || !ptr) ++ return; ++ ++ ASN_DEBUG("Freeing %s as CHOICE", td->name); ++ ++ /* ++ * Figure out which CHOICE element is encoded. ++ */ ++ present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); ++ ++ /* ++ * Free that element. ++ */ ++ if(present > 0 && present <= td->elements_count) { ++ asn_TYPE_member_t *elm = &td->elements[present-1]; ++ void *memb_ptr; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)ptr + elm->memb_offset); ++ if(memb_ptr) ++ ASN_STRUCT_FREE(*elm->type, memb_ptr); ++ } else { ++ memb_ptr = (void *)((char *)ptr + elm->memb_offset); ++ ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); ++ } ++ } ++ ++ if(!contents_only) { ++ FREEMEM(ptr); ++ } ++} ++ ++ ++/* ++ * The following functions functions offer protection against -fshort-enums, ++ * compatible with little- and big-endian machines. ++ * If assertion is triggered, either disable -fshort-enums, or add an entry ++ * here with the ->pres_size of your target stracture. ++ * Unless the target structure is packed, the ".present" member ++ * is guaranteed to be aligned properly. ASN.1 compiler itself does not ++ * produce packed code. ++ */ ++static int ++_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) { ++ const void *present_ptr; ++ int present; ++ ++ present_ptr = ((const char *)struct_ptr) + pres_offset; ++ ++ switch(pres_size) { ++ case sizeof(int): present = *(const int *)present_ptr; break; ++ case sizeof(short): present = *(const short *)present_ptr; break; ++ case sizeof(char): present = *(const char *)present_ptr; break; ++ default: ++ /* ANSI C mandates enum to be equivalent to integer */ ++ assert(pres_size != sizeof(int)); ++ return 0; /* If not aborted, pass back safe value */ ++ } ++ ++ return present; ++} ++ ++static void ++_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) { ++ void *present_ptr; ++ present_ptr = ((char *)struct_ptr) + pres_offset; ++ ++ switch(pres_size) { ++ case sizeof(int): *(int *)present_ptr = present; break; ++ case sizeof(short): *(short *)present_ptr = present; break; ++ case sizeof(char): *(char *)present_ptr = present; break; ++ default: ++ /* ANSI C mandates enum to be equivalent to integer */ ++ assert(pres_size != sizeof(int)); ++ } ++} +diff --git a/asn1/asn1c/constr_CHOICE.h b/asn1/asn1c/constr_CHOICE.h +new file mode 100644 +index 0000000000000000000000000000000000000000..83404e6d43573c9903888fb5c49853e852a7848e +--- /dev/null ++++ b/asn1/asn1c/constr_CHOICE.h +@@ -0,0 +1,57 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _CONSTR_CHOICE_H_ ++#define _CONSTR_CHOICE_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct asn_CHOICE_specifics_s { ++ /* ++ * Target structure description. ++ */ ++ int struct_size; /* Size of the target structure. */ ++ int ctx_offset; /* Offset of the asn_codec_ctx_t member */ ++ int pres_offset; /* Identifier of the present member */ ++ int pres_size; /* Size of the identifier (enum) */ ++ ++ /* ++ * Tags to members mapping table. ++ */ ++ asn_TYPE_tag2member_t *tag2el; ++ int tag2el_count; ++ ++ /* Canonical ordering of CHOICE elements, for PER */ ++ int *canonical_order; ++ ++ /* ++ * Extensions-related stuff. ++ */ ++ int ext_start; /* First member of extensions, or -1 */ ++} asn_CHOICE_specifics_t; ++ ++/* ++ * A set specialized functions dealing with the CHOICE type. ++ */ ++asn_struct_free_f CHOICE_free; ++asn_struct_print_f CHOICE_print; ++asn_constr_check_f CHOICE_constraint; ++ber_type_decoder_f CHOICE_decode_ber; ++der_type_encoder_f CHOICE_encode_der; ++xer_type_decoder_f CHOICE_decode_xer; ++xer_type_encoder_f CHOICE_encode_xer; ++per_type_decoder_f CHOICE_decode_uper; ++per_type_encoder_f CHOICE_encode_uper; ++asn_outmost_tag_f CHOICE_outmost_tag; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _CONSTR_CHOICE_H_ */ +diff --git a/asn1/asn1c/constr_SEQUENCE.c b/asn1/asn1c/constr_SEQUENCE.c +new file mode 100644 +index 0000000000000000000000000000000000000000..b769434345763a454777a89458155f5debea73c8 +--- /dev/null ++++ b/asn1/asn1c/constr_SEQUENCE.c +@@ -0,0 +1,1251 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++ ++/* ++ * Number of bytes left for this structure. ++ * (ctx->left) indicates the number of bytes _transferred_ for the structure. ++ * (size) contains the number of bytes in the buffer passed. ++ */ ++#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) ++ ++/* ++ * If the subprocessor function returns with an indication that it wants ++ * more data, it may well be a fatal decoding problem, because the ++ * size is constrained by the 's L, even if the buffer size allows ++ * reading more data. ++ * For example, consider the buffer containing the following TLVs: ++ * ... ++ * The TLV length clearly indicates that one byte is expected in V, but ++ * if the V processor returns with "want more data" even if the buffer ++ * contains way more data than the V processor have seen. ++ */ ++#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) ++ ++/* ++ * This macro "eats" the part of the buffer which is definitely "consumed", ++ * i.e. was correctly converted into local representation or rightfully skipped. ++ */ ++#undef ADVANCE ++#define ADVANCE(num_bytes) do { \ ++ size_t num = num_bytes; \ ++ ptr = ((const char *)ptr) + num;\ ++ size -= num; \ ++ if(ctx->left >= 0) \ ++ ctx->left -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++/* ++ * Switch to the next phase of parsing. ++ */ ++#undef NEXT_PHASE ++#undef PHASE_OUT ++#define NEXT_PHASE(ctx) do { \ ++ ctx->phase++; \ ++ ctx->step = 0; \ ++ } while(0) ++#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) ++ ++/* ++ * Return a standardized complex structure. ++ */ ++#undef RETURN ++#define RETURN(_code) do { \ ++ rval.code = _code; \ ++ rval.consumed = consumed_myself;\ ++ return rval; \ ++ } while(0) ++ ++/* ++ * Check whether we are inside the extensions group. ++ */ ++#define IN_EXTENSION_GROUP(specs, memb_idx) \ ++ ( ((memb_idx) > (specs)->ext_after) \ ++ &&((memb_idx) < (specs)->ext_before)) ++ ++ ++/* ++ * Tags are canonically sorted in the tag2element map. ++ */ ++static int ++_t2e_cmp(const void *ap, const void *bp) { ++ const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; ++ const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; ++ ++ int a_class = BER_TAG_CLASS(a->el_tag); ++ int b_class = BER_TAG_CLASS(b->el_tag); ++ ++ if(a_class == b_class) { ++ ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); ++ ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); ++ ++ if(a_value == b_value) { ++ if(a->el_no > b->el_no) ++ return 1; ++ /* ++ * Important: we do not check ++ * for a->el_no <= b->el_no! ++ */ ++ return 0; ++ } else if(a_value < b_value) ++ return -1; ++ else ++ return 1; ++ } else if(a_class < b_class) { ++ return -1; ++ } else { ++ return 1; ++ } ++} ++ ++ ++/* ++ * The decoder of the SEQUENCE type. ++ */ ++asn_dec_rval_t ++SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **struct_ptr, const void *ptr, size_t size, int tag_mode) { ++ /* ++ * Bring closer parts of structure description. ++ */ ++ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elements = td->elements; ++ ++ /* ++ * Parts of the structure being constructed. ++ */ ++ void *st = *struct_ptr; /* Target structure. */ ++ asn_struct_ctx_t *ctx; /* Decoder context */ ++ ++ ber_tlv_tag_t tlv_tag; /* T from TLV */ ++ asn_dec_rval_t rval; /* Return code from subparsers */ ++ ++ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ ++ int edx; /* SEQUENCE element's index */ ++ ++ ASN_DEBUG("Decoding %s as SEQUENCE", td->name); ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(st == 0) { ++ st = *struct_ptr = CALLOC(1, specs->struct_size); ++ if(st == 0) { ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ /* ++ * Restore parsing context. ++ */ ++ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); ++ ++ /* ++ * Start to parse where left previously ++ */ ++ switch(ctx->phase) { ++ case 0: ++ /* ++ * PHASE 0. ++ * Check that the set of tags associated with given structure ++ * perfectly fits our expectations. ++ */ ++ ++ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, ++ tag_mode, 1, &ctx->left, 0); ++ if(rval.code != RC_OK) { ++ ASN_DEBUG("%s tagging check failed: %d", ++ td->name, rval.code); ++ return rval; ++ } ++ ++ if(ctx->left >= 0) ++ ctx->left += rval.consumed; /* ?Substracted below! */ ++ ADVANCE(rval.consumed); ++ ++ NEXT_PHASE(ctx); ++ ++ ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", ++ (long)ctx->left, (long)size); ++ ++ /* Fall through */ ++ case 1: ++ /* ++ * PHASE 1. ++ * From the place where we've left it previously, ++ * try to decode the next member from the list of ++ * this structure's elements. ++ * (ctx->step) stores the member being processed ++ * between invocations and the microphase {0,1} of parsing ++ * that member: ++ * step = ( * 2 + ). ++ */ ++ for(edx = (ctx->step >> 1); edx < td->elements_count; ++ edx++, ctx->step = (ctx->step & ~1) + 2) { ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ssize_t tag_len; /* Length of TLV's T */ ++ int opt_edx_end; /* Next non-optional element */ ++ int use_bsearch; ++ int n; ++ ++ if(ctx->step & 1) ++ goto microphase2; ++ ++ /* ++ * MICROPHASE 1: Synchronize decoding. ++ */ ++ ASN_DEBUG("In %s SEQUENCE left %d, edx=%d flags=%d" ++ " opt=%d ec=%d", ++ td->name, (int)ctx->left, edx, ++ elements[edx].flags, elements[edx].optional, ++ td->elements_count); ++ ++ if(ctx->left == 0 /* No more stuff is expected */ ++ && ( ++ /* Explicit OPTIONAL specification reaches the end */ ++ (edx + elements[edx].optional ++ == td->elements_count) ++ || ++ /* All extensions are optional */ ++ (IN_EXTENSION_GROUP(specs, edx) ++ && specs->ext_before > td->elements_count) ++ ) ++ ) { ++ ASN_DEBUG("End of SEQUENCE %s", td->name); ++ /* ++ * Found the legitimate end of the structure. ++ */ ++ PHASE_OUT(ctx); ++ RETURN(RC_OK); ++ } ++ ++ /* ++ * Fetch the T from TLV. ++ */ ++ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); ++ ASN_DEBUG("Current tag in %s SEQUENCE for element %d " ++ "(%s) is %s encoded in %d bytes, of frame %ld", ++ td->name, edx, elements[edx].name, ++ ber_tlv_tag_string(tlv_tag), (int)tag_len, (long)LEFT); ++ switch(tag_len) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { ++ if(LEFT < 2) { ++ if(SIZE_VIOLATION) ++ RETURN(RC_FAIL); ++ else ++ RETURN(RC_WMORE); ++ } else if(((const uint8_t *)ptr)[1] == 0) { ++ ASN_DEBUG("edx = %d, opt = %d, ec=%d", ++ edx, elements[edx].optional, ++ td->elements_count); ++ if((edx + elements[edx].optional ++ == td->elements_count) ++ || (IN_EXTENSION_GROUP(specs, edx) ++ && specs->ext_before ++ > td->elements_count)) { ++ /* ++ * Yeah, baby! Found the terminator ++ * of the indefinite length structure. ++ */ ++ /* ++ * Proceed to the canonical ++ * finalization function. ++ * No advancing is necessary. ++ */ ++ goto phase3; ++ } ++ } ++ } ++ ++ /* ++ * Find the next available type with this tag. ++ */ ++ use_bsearch = 0; ++ opt_edx_end = edx + elements[edx].optional + 1; ++ if(opt_edx_end > td->elements_count) ++ opt_edx_end = td->elements_count; /* Cap */ ++ else if(opt_edx_end - edx > 8) { ++ /* Limit the scope of linear search... */ ++ opt_edx_end = edx + 8; ++ use_bsearch = 1; ++ /* ... and resort to bsearch() */ ++ } ++ for(n = edx; n < opt_edx_end; n++) { ++ if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) { ++ /* ++ * Found element corresponding to the tag ++ * being looked at. ++ * Reposition over the right element. ++ */ ++ edx = n; ++ ctx->step = 1 + 2 * edx; /* Remember! */ ++ goto microphase2; ++ } else if(elements[n].flags & ATF_OPEN_TYPE) { ++ /* ++ * This is the ANY type, which may bear ++ * any flag whatsoever. ++ */ ++ edx = n; ++ ctx->step = 1 + 2 * edx; /* Remember! */ ++ goto microphase2; ++ } else if(elements[n].tag == (ber_tlv_tag_t)-1) { ++ use_bsearch = 1; ++ break; ++ } ++ } ++ if(use_bsearch) { ++ /* ++ * Resort to a binary search over ++ * sorted array of tags. ++ */ ++ asn_TYPE_tag2member_t *t2m; ++ asn_TYPE_tag2member_t key; ++ key.el_tag = tlv_tag; ++ key.el_no = edx; ++ t2m = (asn_TYPE_tag2member_t *)bsearch(&key, ++ specs->tag2el, specs->tag2el_count, ++ sizeof(specs->tag2el[0]), _t2e_cmp); ++ if(t2m) { ++ asn_TYPE_tag2member_t *best = 0; ++ asn_TYPE_tag2member_t *t2m_f, *t2m_l; ++ int edx_max = edx + elements[edx].optional; ++ /* ++ * Rewind to the first element with that tag, ++ * `cause bsearch() does not guarantee order. ++ */ ++ t2m_f = t2m + t2m->toff_first; ++ t2m_l = t2m + t2m->toff_last; ++ for(t2m = t2m_f; t2m <= t2m_l; t2m++) { ++ if(t2m->el_no > edx_max) break; ++ if(t2m->el_no < edx) continue; ++ best = t2m; ++ } ++ if(best) { ++ edx = best->el_no; ++ ctx->step = 1 + 2 * edx; ++ goto microphase2; ++ } ++ } ++ n = opt_edx_end; ++ } ++ if(n == opt_edx_end) { ++ /* ++ * If tag is unknown, it may be either ++ * an unknown (thus, incorrect) tag, ++ * or an extension (...), ++ * or an end of the indefinite-length structure. ++ */ ++ if(!IN_EXTENSION_GROUP(specs, edx)) { ++ ASN_DEBUG("Unexpected tag %s (at %d)", ++ ber_tlv_tag_string(tlv_tag), edx); ++ ASN_DEBUG("Expected tag %s (%s)%s", ++ ber_tlv_tag_string(elements[edx].tag), ++ elements[edx].name, ++ elements[edx].optional ++ ?" or alternatives":""); ++ RETURN(RC_FAIL); ++ } else { ++ /* Skip this tag */ ++ ssize_t skip; ++ ++ skip = ber_skip_length(opt_codec_ctx, ++ BER_TLV_CONSTRUCTED(ptr), ++ (const char *)ptr + tag_len, ++ LEFT - tag_len); ++ ASN_DEBUG("Skip length %d in %s", ++ (int)skip, td->name); ++ switch(skip) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ ADVANCE(skip + tag_len); ++ ctx->step -= 2; ++ edx--; ++ continue; /* Try again with the next tag */ ++ } ++ } ++ ++ /* ++ * MICROPHASE 2: Invoke the member-specific decoder. ++ */ ++ ctx->step |= 1; /* Confirm entering next microphase */ ++ microphase2: ++ ASN_DEBUG("Inside SEQUENCE %s MF2", td->name); ++ ++ /* ++ * Compute the position of the member inside a structure, ++ * and also a type of containment (it may be contained ++ * as pointer or using inline inclusion). ++ */ ++ if(elements[edx].flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset); ++ } else { ++ /* ++ * A pointer to a pointer ++ * holding the start of the structure ++ */ ++ memb_ptr = (char *)st + elements[edx].memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ /* ++ * Invoke the member fetch routine according to member's type ++ */ ++ rval = elements[edx].type->ber_decoder(opt_codec_ctx, ++ elements[edx].type, ++ memb_ptr2, ptr, LEFT, ++ elements[edx].tag_mode); ++ ASN_DEBUG("In %s SEQUENCE decoded %d %s of %d " ++ "in %d bytes rval.code %d, size=%d", ++ td->name, edx, elements[edx].type->name, ++ (int)LEFT, (int)rval.consumed, rval.code, (int)size); ++ switch(rval.code) { ++ case RC_OK: ++ break; ++ case RC_WMORE: /* More data expected */ ++ if(!SIZE_VIOLATION) { ++ ADVANCE(rval.consumed); ++ RETURN(RC_WMORE); ++ } ++ ASN_DEBUG("Size violation (c->l=%ld <= s=%ld)", ++ (long)ctx->left, (long)size); ++ /* Fall through */ ++ case RC_FAIL: /* Fatal error */ ++ RETURN(RC_FAIL); ++ } /* switch(rval) */ ++ ++ ADVANCE(rval.consumed); ++ } /* for(all structure members) */ ++ ++ phase3: ++ ctx->phase = 3; ++ case 3: /* 00 and other tags expected */ ++ case 4: /* only 00's expected */ ++ ++ ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld", ++ td->name, (long)ctx->left, (long)size); ++ ++ /* ++ * Skip everything until the end of the SEQUENCE. ++ */ ++ while(ctx->left) { ++ ssize_t tl, ll; ++ ++ tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); ++ switch(tl) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ /* ++ * If expected <0><0>... ++ */ ++ if(ctx->left < 0 ++ && ((const uint8_t *)ptr)[0] == 0) { ++ if(LEFT < 2) { ++ if(SIZE_VIOLATION) ++ RETURN(RC_FAIL); ++ else ++ RETURN(RC_WMORE); ++ } else if(((const uint8_t *)ptr)[1] == 0) { ++ /* ++ * Correctly finished with <0><0>. ++ */ ++ ADVANCE(2); ++ ctx->left++; ++ ctx->phase = 4; ++ continue; ++ } ++ } ++ ++ if(!IN_EXTENSION_GROUP(specs, td->elements_count) ++ || ctx->phase == 4) { ++ ASN_DEBUG("Unexpected continuation " ++ "of a non-extensible type " ++ "%s (SEQUENCE): %s", ++ td->name, ++ ber_tlv_tag_string(tlv_tag)); ++ RETURN(RC_FAIL); ++ } ++ ++ ll = ber_skip_length(opt_codec_ctx, ++ BER_TLV_CONSTRUCTED(ptr), ++ (const char *)ptr + tl, LEFT - tl); ++ switch(ll) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ ADVANCE(tl + ll); ++ } ++ ++ PHASE_OUT(ctx); ++ } ++ ++ RETURN(RC_OK); ++} ++ ++ ++/* ++ * The DER encoder of the SEQUENCE type. ++ */ ++asn_enc_rval_t ++SEQUENCE_encode_der(asn_TYPE_descriptor_t *td, ++ void *sptr, int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ size_t computed_size = 0; ++ asn_enc_rval_t erval; ++ ssize_t ret; ++ int edx; ++ ++ ASN_DEBUG("%s %s as SEQUENCE", ++ cb?"Encoding":"Estimating", td->name); ++ ++ /* ++ * Gather the length of the underlying members sequence. ++ */ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(!memb_ptr) { ++ if(elm->optional) continue; ++ /* Mandatory element is missing */ ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ } ++ erval = elm->type->der_encoder(elm->type, memb_ptr, ++ elm->tag_mode, elm->tag, ++ 0, 0); ++ if(erval.encoded == -1) ++ return erval; ++ computed_size += erval.encoded; ++ ASN_DEBUG("Member %d %s estimated %ld bytes", ++ edx, elm->name, (long)erval.encoded); ++ } ++ ++ /* ++ * Encode the TLV for the sequence itself. ++ */ ++ ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); ++ ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size); ++ if(ret == -1) ++ _ASN_ENCODE_FAILED; ++ erval.encoded = computed_size + ret; ++ ++ if(!cb) _ASN_ENCODED_OK(erval); ++ ++ /* ++ * Encode all members. ++ */ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ asn_enc_rval_t tmperval; ++ void *memb_ptr; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(!memb_ptr) continue; ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ } ++ tmperval = elm->type->der_encoder(elm->type, memb_ptr, ++ elm->tag_mode, elm->tag, ++ cb, app_key); ++ if(tmperval.encoded == -1) ++ return tmperval; ++ computed_size -= tmperval.encoded; ++ ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %ld bytes", ++ edx, elm->name, td->name, (long)tmperval.encoded); ++ } ++ ++ if(computed_size != 0) ++ /* ++ * Encoded size is not equal to the computed size. ++ */ ++ _ASN_ENCODE_FAILED; ++ ++ _ASN_ENCODED_OK(erval); ++} ++ ++ ++#undef XER_ADVANCE ++#define XER_ADVANCE(num_bytes) do { \ ++ size_t num = num_bytes; \ ++ buf_ptr = ((const char *)buf_ptr) + num;\ ++ size -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++/* ++ * Decode the XER (XML) data. ++ */ ++asn_dec_rval_t ++SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **struct_ptr, const char *opt_mname, ++ const void *buf_ptr, size_t size) { ++ /* ++ * Bring closer parts of structure description. ++ */ ++ asn_SEQUENCE_specifics_t *specs ++ = (asn_SEQUENCE_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elements = td->elements; ++ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; ++ ++ /* ++ * ... and parts of the structure being constructed. ++ */ ++ void *st = *struct_ptr; /* Target structure. */ ++ asn_struct_ctx_t *ctx; /* Decoder context */ ++ ++ asn_dec_rval_t rval; /* Return value from a decoder */ ++ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ ++ int edx; /* Element index */ ++ int edx_end; ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(st == 0) { ++ st = *struct_ptr = CALLOC(1, specs->struct_size); ++ if(st == 0) RETURN(RC_FAIL); ++ } ++ ++ /* ++ * Restore parsing context. ++ */ ++ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); ++ ++ ++ /* ++ * Phases of XER/XML processing: ++ * Phase 0: Check that the opening tag matches our expectations. ++ * Phase 1: Processing body and reacting on closing tag. ++ * Phase 2: Processing inner type. ++ * Phase 3: Skipping unknown extensions. ++ * Phase 4: PHASED OUT ++ */ ++ for(edx = ctx->step; ctx->phase <= 3;) { ++ pxer_chunk_type_e ch_type; /* XER chunk type */ ++ ssize_t ch_size; /* Chunk size */ ++ xer_check_tag_e tcv; /* Tag check value */ ++ asn_TYPE_member_t *elm; ++ int n; ++ ++ /* ++ * Go inside the inner member of a sequence. ++ */ ++ if(ctx->phase == 2) { ++ asn_dec_rval_t tmprval; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ elm = &td->elements[edx]; ++ ++ if(elm->flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr2 = (void **)((char *)st ++ + elm->memb_offset); ++ } else { ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ /* Invoke the inner type decoder, m.b. multiple times */ ++ tmprval = elm->type->xer_decoder(opt_codec_ctx, ++ elm->type, memb_ptr2, elm->name, ++ buf_ptr, size); ++ XER_ADVANCE(tmprval.consumed); ++ if(tmprval.code != RC_OK) ++ RETURN(tmprval.code); ++ ctx->phase = 1; /* Back to body processing */ ++ ctx->step = ++edx; ++ ASN_DEBUG("XER/SEQUENCE phase => %d, step => %d", ++ ctx->phase, ctx->step); ++ /* Fall through */ ++ } ++ ++ /* ++ * Get the next part of the XML stream. ++ */ ++ ch_size = xer_next_token(&ctx->context, buf_ptr, size, ++ &ch_type); ++ switch(ch_size) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ default: ++ switch(ch_type) { ++ case PXER_COMMENT: /* Got XML comment */ ++ case PXER_TEXT: /* Ignore free-standing text */ ++ XER_ADVANCE(ch_size); /* Skip silently */ ++ continue; ++ case PXER_TAG: ++ break; /* Check the rest down there */ ++ } ++ } ++ ++ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); ++ ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]", ++ tcv, ctx->phase, xml_tag); ++ ++ /* Skip the extensions section */ ++ if(ctx->phase == 3) { ++ switch(xer_skip_unknown(tcv, &ctx->left)) { ++ case -1: ++ ctx->phase = 4; ++ RETURN(RC_FAIL); ++ case 0: ++ XER_ADVANCE(ch_size); ++ continue; ++ case 1: ++ XER_ADVANCE(ch_size); ++ ctx->phase = 1; ++ continue; ++ case 2: ++ ctx->phase = 1; ++ break; ++ } ++ } ++ ++ switch(tcv) { ++ case XCT_CLOSING: ++ if(ctx->phase == 0) break; ++ ctx->phase = 0; ++ /* Fall through */ ++ case XCT_BOTH: ++ if(ctx->phase == 0) { ++ if(edx >= td->elements_count ++ || ++ /* Explicit OPTIONAL specs reaches the end */ ++ (edx + elements[edx].optional ++ == td->elements_count) ++ || ++ /* All extensions are optional */ ++ (IN_EXTENSION_GROUP(specs, edx) ++ && specs->ext_before ++ > td->elements_count) ++ ) { ++ XER_ADVANCE(ch_size); ++ ctx->phase = 4; /* Phase out */ ++ RETURN(RC_OK); ++ } else { ++ ASN_DEBUG("Premature end of XER SEQUENCE"); ++ RETURN(RC_FAIL); ++ } ++ } ++ /* Fall through */ ++ case XCT_OPENING: ++ if(ctx->phase == 0) { ++ XER_ADVANCE(ch_size); ++ ctx->phase = 1; /* Processing body phase */ ++ continue; ++ } ++ /* Fall through */ ++ case XCT_UNKNOWN_OP: ++ case XCT_UNKNOWN_BO: ++ ++ ASN_DEBUG("XER/SEQUENCE: tcv=%d, ph=%d, edx=%d", ++ tcv, ctx->phase, edx); ++ if(ctx->phase != 1) { ++ break; /* Really unexpected */ ++ } ++ ++ if(edx < td->elements_count) { ++ /* ++ * Search which member corresponds to this tag. ++ */ ++ edx_end = edx + elements[edx].optional + 1; ++ if(edx_end > td->elements_count) ++ edx_end = td->elements_count; ++ for(n = edx; n < edx_end; n++) { ++ elm = &td->elements[n]; ++ tcv = xer_check_tag(buf_ptr, ++ ch_size, elm->name); ++ switch(tcv) { ++ case XCT_BOTH: ++ case XCT_OPENING: ++ /* ++ * Process this member. ++ */ ++ ctx->step = edx = n; ++ ctx->phase = 2; ++ break; ++ case XCT_UNKNOWN_OP: ++ case XCT_UNKNOWN_BO: ++ continue; ++ default: ++ n = edx_end; ++ break; /* Phase out */ ++ } ++ break; ++ } ++ if(n != edx_end) ++ continue; ++ } else { ++ ASN_DEBUG("Out of defined members: %d/%d", ++ edx, td->elements_count); ++ } ++ ++ /* It is expected extension */ ++ if(IN_EXTENSION_GROUP(specs, ++ edx + (edx < td->elements_count ++ ? elements[edx].optional : 0))) { ++ ASN_DEBUG("Got anticipated extension at %d", ++ edx); ++ /* ++ * Check for (XCT_BOTH or XCT_UNKNOWN_BO) ++ * By using a mask. Only record a pure ++ * tags. ++ */ ++ if(tcv & XCT_CLOSING) { ++ /* Found without body */ ++ } else { ++ ctx->left = 1; ++ ctx->phase = 3; /* Skip ...'s */ ++ } ++ XER_ADVANCE(ch_size); ++ continue; ++ } ++ ++ /* Fall through */ ++ default: ++ break; ++ } ++ ++ ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]", ++ size>0?((const char *)buf_ptr)[0]:'.', ++ size>1?((const char *)buf_ptr)[1]:'.', ++ size>2?((const char *)buf_ptr)[2]:'.', ++ size>3?((const char *)buf_ptr)[3]:'.', ++ size>4?((const char *)buf_ptr)[4]:'.', ++ size>5?((const char *)buf_ptr)[5]:'.'); ++ break; ++ } ++ ++ ctx->phase = 4; /* "Phase out" on hard failure */ ++ RETURN(RC_FAIL); ++} ++ ++asn_enc_rval_t ++SEQUENCE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_enc_rval_t er; ++ int xcan = (flags & XER_F_CANONICAL); ++ int edx; ++ ++ if(!sptr) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = 0; ++ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_enc_rval_t tmper; ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; ++ const char *mname = elm->name; ++ unsigned int mlen = strlen(mname); ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(!memb_ptr) { ++ if(elm->optional) ++ continue; ++ /* Mandatory element is missing */ ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ } ++ ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); ++ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); ++ ++ /* Print the member itself */ ++ tmper = elm->type->xer_encoder(elm->type, memb_ptr, ++ ilevel + 1, flags, cb, app_key); ++ if(tmper.encoded == -1) return tmper; ++ ++ _ASN_CALLBACK3("", 1); ++ er.encoded += 5 + (2 * mlen) + tmper.encoded; ++ } ++ ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); ++ ++ _ASN_ENCODED_OK(er); ++cb_failed: ++ _ASN_ENCODE_FAILED; ++} ++ ++int ++SEQUENCE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ int edx; ++ int ret; ++ ++ if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; ++ ++ /* Dump preamble */ ++ if(cb(td->name, strlen(td->name), app_key) < 0 ++ || cb(" ::= {", 6, app_key) < 0) ++ return -1; ++ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ const void *memb_ptr; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); ++ if(!memb_ptr) { ++ if(elm->optional) continue; ++ /* Print line */ ++ /* Fall through */ ++ } ++ } else { ++ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); ++ } ++ ++ /* Indentation */ ++ _i_INDENT(1); ++ ++ /* Print the member's name and stuff */ ++ if(cb(elm->name, strlen(elm->name), app_key) < 0 ++ || cb(": ", 2, app_key) < 0) ++ return -1; ++ ++ /* Print the member itself */ ++ ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 1, ++ cb, app_key); ++ if(ret) return ret; ++ } ++ ++ ilevel--; ++ _i_INDENT(1); ++ ++ return (cb("}", 1, app_key) < 0) ? -1 : 0; ++} ++ ++void ++SEQUENCE_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { ++ int edx; ++ ++ if(!td || !sptr) ++ return; ++ ++ ASN_DEBUG("Freeing %s as SEQUENCE", td->name); ++ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(memb_ptr) ++ ASN_STRUCT_FREE(*elm->type, memb_ptr); ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); ++ } ++ } ++ ++ if(!contents_only) { ++ FREEMEM(sptr); ++ } ++} ++ ++int ++SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, ++ asn_app_constraint_failed_f *ctfailcb, void *app_key) { ++ int edx; ++ ++ if(!sptr) { ++ _ASN_CTFAIL(app_key, td, ++ "%s: value not given (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++ ++ /* ++ * Iterate over structure members and check their validity. ++ */ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ const void *memb_ptr; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); ++ if(!memb_ptr) { ++ if(elm->optional) ++ continue; ++ _ASN_CTFAIL(app_key, td, ++ "%s: mandatory element %s absent (%s:%d)", ++ td->name, elm->name, __FILE__, __LINE__); ++ return -1; ++ } ++ } else { ++ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); ++ } ++ ++ if(elm->memb_constraints) { ++ int ret = elm->memb_constraints(elm->type, memb_ptr, ++ ctfailcb, app_key); ++ if(ret) return ret; ++ } else { ++ int ret = elm->type->check_constraints(elm->type, ++ memb_ptr, ctfailcb, app_key); ++ if(ret) return ret; ++ /* ++ * Cannot inherit it earlier: ++ * need to make sure we get the updated version. ++ */ ++ elm->memb_constraints = elm->type->check_constraints; ++ } ++ } ++ ++ return 0; ++} ++ ++asn_dec_rval_t ++SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; ++ void *st = *sptr; /* Target structure. */ ++ int extpresent = 0; /* Extension additions are present */ ++ uint8_t *opres; /* Presence of optional root members */ ++ asn_per_data_t opmd; ++ asn_dec_rval_t rv; ++ int edx; ++ ++ (void)constraints; ++ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ _ASN_DECODE_FAILED; ++ ++ if(!st) { ++ st = *sptr = CALLOC(1, specs->struct_size); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ ASN_DEBUG("Decoding %s as SEQUENCE (UPER)", td->name); ++ ++ /* Handle extensions */ ++ if(specs->ext_before >= 0) { ++ extpresent = per_get_few_bits(pd, 1); ++ if(extpresent < 0) _ASN_DECODE_STARVED; ++ } ++ ++ /* Prepare a place and read-in the presence bitmap */ ++ if(specs->roms_count) { ++ opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); ++ if(!opres) _ASN_DECODE_FAILED; ++ /* Get the presence map */ ++ if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { ++ FREEMEM(opres); ++ _ASN_DECODE_STARVED; ++ } ++ opmd.buffer = opres; ++ opmd.nboff = 0; ++ opmd.nbits = specs->roms_count; ++ ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", ++ td->name, specs->roms_count, *opres); ++ } else { ++ opres = 0; ++ memset(&opmd, 0, sizeof opmd); ++ } ++ ++ /* ++ * Get the sequence ROOT elements. ++ */ ++ for(edx = 0; edx < ((specs->ext_before < 0) ++ ? td->elements_count : specs->ext_before + 1); edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)st + elm->memb_offset); ++ } else { ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ /* Deal with optionality */ ++ if(elm->optional) { ++ int present = per_get_few_bits(&opmd, 1); ++ ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", ++ td->name, elm->name, present, ++ (int)opmd.nboff, (int)opmd.nbits); ++ if(present == 0) { ++ /* This element is not present */ ++ if(elm->default_value) { ++ /* Fill-in DEFAULT */ ++ if(elm->default_value(1, memb_ptr2)) { ++ FREEMEM(opres); ++ _ASN_DECODE_FAILED; ++ } ++ } ++ /* The member is just not present */ ++ continue; ++ } ++ /* Fall through */ ++ } ++ ++ /* Fetch the member from the stream */ ++ ASN_DEBUG("Decoding member %s in %s", elm->name, td->name); ++ rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, ++ elm->per_constraints, memb_ptr2, pd); ++ if(rv.code != RC_OK) { ++ ASN_DEBUG("Failed decode %s in %s", ++ elm->name, td->name); ++ FREEMEM(opres); ++ return rv; ++ } ++ } ++ ++ /* ++ * Deal with extensions. ++ */ ++ if(extpresent) { ++ ASN_DEBUG("Extensibility for %s: NOT IMPLEMENTED", td->name); ++ _ASN_DECODE_FAILED; ++ } else { ++ for(edx = specs->roms_count; edx < specs->roms_count ++ + specs->aoms_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ if(!elm->default_value) continue; ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)st ++ + elm->memb_offset); ++ } else { ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ /* Set default value */ ++ if(elm->default_value(1, memb_ptr2)) { ++ FREEMEM(opres); ++ _ASN_DECODE_FAILED; ++ } ++ } ++ } ++ ++ rv.consumed = 0; ++ rv.code = RC_OK; ++ FREEMEM(opres); ++ return rv; ++} ++ ++asn_enc_rval_t ++SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_SEQUENCE_specifics_t *specs ++ = (asn_SEQUENCE_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ int edx; ++ int i; ++ ++ (void)constraints; ++ ++ if(!sptr) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = 0; ++ ++ ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); ++ if(specs->ext_before >= 0) ++ _ASN_ENCODE_FAILED; /* We don't encode extensions yet */ ++ ++ /* Encode a presence bitmap */ ++ for(i = 0; i < specs->roms_count; i++) { ++ asn_TYPE_member_t *elm; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ int present; ++ ++ edx = specs->oms[i]; ++ elm = &td->elements[edx]; ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); ++ present = (*memb_ptr2 != 0); ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ memb_ptr2 = &memb_ptr; ++ present = 1; ++ } ++ ++ /* Eliminate default values */ ++ if(present && elm->default_value ++ && elm->default_value(0, memb_ptr2) == 1) ++ present = 0; ++ ++ ASN_DEBUG("Element %s %s %s->%s is %s", ++ elm->flags & ATF_POINTER ? "ptr" : "inline", ++ elm->default_value ? "def" : "wtv", ++ td->name, elm->name, present ? "present" : "absent"); ++ if(per_put_few_bits(po, present, 1)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ /* ++ * Get the sequence ROOT elements. ++ */ ++ for(edx = 0; edx < ((specs->ext_before < 0) ++ ? td->elements_count : specs->ext_before + 1); edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); ++ if(!*memb_ptr2) { ++ ASN_DEBUG("Element %s %d not present", ++ elm->name, edx); ++ if(elm->optional) ++ continue; ++ /* Mandatory element is missing */ ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ /* Eliminate default values */ ++ if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) ++ continue; ++ ++ er = elm->type->uper_encoder(elm->type, elm->per_constraints, ++ *memb_ptr2, po); ++ if(er.encoded == -1) ++ return er; ++ } ++ ++ _ASN_ENCODED_OK(er); ++} ++ +diff --git a/asn1/asn1c/constr_SEQUENCE.h b/asn1/asn1c/constr_SEQUENCE.h +new file mode 100644 +index 0000000000000000000000000000000000000000..5f589d5c1c0d1ae1d6e970742fc6467153bea79c +--- /dev/null ++++ b/asn1/asn1c/constr_SEQUENCE.h +@@ -0,0 +1,60 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _CONSTR_SEQUENCE_H_ ++#define _CONSTR_SEQUENCE_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct asn_SEQUENCE_specifics_s { ++ /* ++ * Target structure description. ++ */ ++ int struct_size; /* Size of the target structure. */ ++ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ ++ ++ /* ++ * Tags to members mapping table (sorted). ++ */ ++ asn_TYPE_tag2member_t *tag2el; ++ int tag2el_count; ++ ++ /* ++ * Optional members of the extensions root (roms) or additions (aoms). ++ * Meaningful for PER. ++ */ ++ int *oms; /* Optional MemberS */ ++ int roms_count; /* Root optional members count */ ++ int aoms_count; /* Additions optional members count */ ++ ++ /* ++ * Description of an extensions group. ++ */ ++ int ext_after; /* Extensions start after this member */ ++ int ext_before; /* Extensions stop before this member */ ++} asn_SEQUENCE_specifics_t; ++ ++ ++/* ++ * A set specialized functions dealing with the SEQUENCE type. ++ */ ++asn_struct_free_f SEQUENCE_free; ++asn_struct_print_f SEQUENCE_print; ++asn_constr_check_f SEQUENCE_constraint; ++ber_type_decoder_f SEQUENCE_decode_ber; ++der_type_encoder_f SEQUENCE_encode_der; ++xer_type_decoder_f SEQUENCE_decode_xer; ++xer_type_encoder_f SEQUENCE_encode_xer; ++per_type_decoder_f SEQUENCE_decode_uper; ++per_type_encoder_f SEQUENCE_encode_uper; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _CONSTR_SEQUENCE_H_ */ +diff --git a/asn1/asn1c/constr_SEQUENCE_OF.c b/asn1/asn1c/constr_SEQUENCE_OF.c +new file mode 100644 +index 0000000000000000000000000000000000000000..aa101176d649ee2b26e3616e88197d9488991bb2 +--- /dev/null ++++ b/asn1/asn1c/constr_SEQUENCE_OF.c +@@ -0,0 +1,208 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * The DER encoder of the SEQUENCE OF type. ++ */ ++asn_enc_rval_t ++SEQUENCE_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr, ++ int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_TYPE_member_t *elm = td->elements; ++ asn_anonymous_sequence_ *list = _A_SEQUENCE_FROM_VOID(ptr); ++ size_t computed_size = 0; ++ ssize_t encoding_size = 0; ++ asn_enc_rval_t erval; ++ int edx; ++ ++ ASN_DEBUG("Estimating size of SEQUENCE OF %s", td->name); ++ ++ /* ++ * Gather the length of the underlying members sequence. ++ */ ++ for(edx = 0; edx < list->count; edx++) { ++ void *memb_ptr = list->array[edx]; ++ if(!memb_ptr) continue; ++ erval = elm->type->der_encoder(elm->type, memb_ptr, ++ 0, elm->tag, ++ 0, 0); ++ if(erval.encoded == -1) ++ return erval; ++ computed_size += erval.encoded; ++ } ++ ++ /* ++ * Encode the TLV for the sequence itself. ++ */ ++ encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, ++ cb, app_key); ++ if(encoding_size == -1) { ++ erval.encoded = -1; ++ erval.failed_type = td; ++ erval.structure_ptr = ptr; ++ return erval; ++ } ++ ++ computed_size += encoding_size; ++ if(!cb) { ++ erval.encoded = computed_size; ++ _ASN_ENCODED_OK(erval); ++ } ++ ++ ASN_DEBUG("Encoding members of SEQUENCE OF %s", td->name); ++ ++ /* ++ * Encode all members. ++ */ ++ for(edx = 0; edx < list->count; edx++) { ++ void *memb_ptr = list->array[edx]; ++ if(!memb_ptr) continue; ++ erval = elm->type->der_encoder(elm->type, memb_ptr, ++ 0, elm->tag, ++ cb, app_key); ++ if(erval.encoded == -1) ++ return erval; ++ encoding_size += erval.encoded; ++ } ++ ++ if(computed_size != (size_t)encoding_size) { ++ /* ++ * Encoded size is not equal to the computed size. ++ */ ++ erval.encoded = -1; ++ erval.failed_type = td; ++ erval.structure_ptr = ptr; ++ } else { ++ erval.encoded = computed_size; ++ erval.structure_ptr = 0; ++ erval.failed_type = 0; ++ } ++ ++ return erval; ++} ++ ++asn_enc_rval_t ++SEQUENCE_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_enc_rval_t er; ++ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm = td->elements; ++ asn_anonymous_sequence_ *list = _A_SEQUENCE_FROM_VOID(sptr); ++ const char *mname = specs->as_XMLValueList ++ ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); ++ unsigned int mlen = mname ? strlen(mname) : 0; ++ int xcan = (flags & XER_F_CANONICAL); ++ int i; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ ++ er.encoded = 0; ++ ++ for(i = 0; i < list->count; i++) { ++ asn_enc_rval_t tmper; ++ void *memb_ptr = list->array[i]; ++ if(!memb_ptr) continue; ++ ++ if(mname) { ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); ++ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); ++ } ++ ++ tmper = elm->type->xer_encoder(elm->type, memb_ptr, ++ ilevel + 1, flags, cb, app_key); ++ if(tmper.encoded == -1) return tmper; ++ if(tmper.encoded == 0 && specs->as_XMLValueList) { ++ const char *name = elm->type->xml_tag; ++ size_t len = strlen(name); ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel + 1); ++ _ASN_CALLBACK3("<", 1, name, len, "/>", 2); ++ } ++ ++ if(mname) { ++ _ASN_CALLBACK3("", 1); ++ er.encoded += 5; ++ } ++ ++ er.encoded += (2 * mlen) + tmper.encoded; ++ } ++ ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); ++ ++ _ASN_ENCODED_OK(er); ++cb_failed: ++ _ASN_ENCODE_FAILED; ++} ++ ++asn_enc_rval_t ++SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_anonymous_sequence_ *list; ++ asn_per_constraint_t *ct; ++ asn_enc_rval_t er; ++ asn_TYPE_member_t *elm = td->elements; ++ int seq; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ list = _A_SEQUENCE_FROM_VOID(sptr); ++ ++ er.encoded = 0; ++ ++ ASN_DEBUG("Encoding %s as SEQUENCE OF (%d)", td->name, list->count); ++ ++ if(constraints) ct = &constraints->size; ++ else if(td->per_constraints) ct = &td->per_constraints->size; ++ else ct = 0; ++ ++ /* If extensible constraint, check if size is in root */ ++ if(ct) { ++ int not_in_root = (list->count < ct->lower_bound ++ || list->count > ct->upper_bound); ++ ASN_DEBUG("lb %ld ub %ld %s", ++ ct->lower_bound, ct->upper_bound, ++ ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); ++ if(ct->flags & APC_EXTENSIBLE) { ++ /* Declare whether size is in extension root */ ++ if(per_put_few_bits(po, not_in_root, 1)) ++ _ASN_ENCODE_FAILED; ++ if(not_in_root) ct = 0; ++ } else if(not_in_root && ct->effective_bits >= 0) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ if(ct && ct->effective_bits >= 0) { ++ /* X.691, #19.5: No length determinant */ ++ if(per_put_few_bits(po, list->count - ct->lower_bound, ++ ct->effective_bits)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ for(seq = -1; seq < list->count;) { ++ ssize_t mayEncode; ++ if(seq < 0) seq = 0; ++ if(ct && ct->effective_bits >= 0) { ++ mayEncode = list->count; ++ } else { ++ mayEncode = uper_put_length(po, list->count - seq); ++ if(mayEncode < 0) _ASN_ENCODE_FAILED; ++ } ++ ++ while(mayEncode--) { ++ void *memb_ptr = list->array[seq++]; ++ if(!memb_ptr) _ASN_ENCODE_FAILED; ++ er = elm->type->uper_encoder(elm->type, ++ elm->per_constraints, memb_ptr, po); ++ if(er.encoded == -1) ++ _ASN_ENCODE_FAILED; ++ } ++ } ++ ++ _ASN_ENCODED_OK(er); ++} ++ +diff --git a/asn1/asn1c/constr_SEQUENCE_OF.h b/asn1/asn1c/constr_SEQUENCE_OF.h +new file mode 100644 +index 0000000000000000000000000000000000000000..e2272f326ba1b961f3f0539c160481f9348b49da +--- /dev/null ++++ b/asn1/asn1c/constr_SEQUENCE_OF.h +@@ -0,0 +1,33 @@ ++/*- ++ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _CONSTR_SEQUENCE_OF_H_ ++#define _CONSTR_SEQUENCE_OF_H_ ++ ++#include ++#include /* Implemented using SET OF */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * A set specialized functions dealing with the SEQUENCE OF type. ++ * Generally implemented using SET OF. ++ */ ++#define SEQUENCE_OF_free SET_OF_free ++#define SEQUENCE_OF_print SET_OF_print ++#define SEQUENCE_OF_constraint SET_OF_constraint ++#define SEQUENCE_OF_decode_ber SET_OF_decode_ber ++#define SEQUENCE_OF_decode_xer SET_OF_decode_xer ++#define SEQUENCE_OF_decode_uper SET_OF_decode_uper ++der_type_encoder_f SEQUENCE_OF_encode_der; ++xer_type_encoder_f SEQUENCE_OF_encode_xer; ++per_type_encoder_f SEQUENCE_OF_encode_uper; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _CONSTR_SET_OF_H_ */ +diff --git a/asn1/asn1c/constr_SET_OF.c b/asn1/asn1c/constr_SET_OF.c +new file mode 100644 +index 0000000000000000000000000000000000000000..09f27db53dada6869accd8dbb3aba0f56b49e00b +--- /dev/null ++++ b/asn1/asn1c/constr_SET_OF.c +@@ -0,0 +1,942 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * Number of bytes left for this structure. ++ * (ctx->left) indicates the number of bytes _transferred_ for the structure. ++ * (size) contains the number of bytes in the buffer passed. ++ */ ++#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) ++ ++/* ++ * If the subprocessor function returns with an indication that it wants ++ * more data, it may well be a fatal decoding problem, because the ++ * size is constrained by the 's L, even if the buffer size allows ++ * reading more data. ++ * For example, consider the buffer containing the following TLVs: ++ * ... ++ * The TLV length clearly indicates that one byte is expected in V, but ++ * if the V processor returns with "want more data" even if the buffer ++ * contains way more data than the V processor have seen. ++ */ ++#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) ++ ++/* ++ * This macro "eats" the part of the buffer which is definitely "consumed", ++ * i.e. was correctly converted into local representation or rightfully skipped. ++ */ ++#undef ADVANCE ++#define ADVANCE(num_bytes) do { \ ++ size_t num = num_bytes; \ ++ ptr = ((const char *)ptr) + num;\ ++ size -= num; \ ++ if(ctx->left >= 0) \ ++ ctx->left -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++/* ++ * Switch to the next phase of parsing. ++ */ ++#undef NEXT_PHASE ++#undef PHASE_OUT ++#define NEXT_PHASE(ctx) do { \ ++ ctx->phase++; \ ++ ctx->step = 0; \ ++ } while(0) ++#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) ++ ++/* ++ * Return a standardized complex structure. ++ */ ++#undef RETURN ++#define RETURN(_code) do { \ ++ rval.code = _code; \ ++ rval.consumed = consumed_myself;\ ++ return rval; \ ++ } while(0) ++ ++/* ++ * The decoder of the SET OF type. ++ */ ++asn_dec_rval_t ++SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **struct_ptr, const void *ptr, size_t size, int tag_mode) { ++ /* ++ * Bring closer parts of structure description. ++ */ ++ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm = td->elements; /* Single one */ ++ ++ /* ++ * Parts of the structure being constructed. ++ */ ++ void *st = *struct_ptr; /* Target structure. */ ++ asn_struct_ctx_t *ctx; /* Decoder context */ ++ ++ ber_tlv_tag_t tlv_tag; /* T from TLV */ ++ asn_dec_rval_t rval; /* Return code from subparsers */ ++ ++ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ ++ ++ ASN_DEBUG("Decoding %s as SET OF", td->name); ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(st == 0) { ++ st = *struct_ptr = CALLOC(1, specs->struct_size); ++ if(st == 0) { ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ /* ++ * Restore parsing context. ++ */ ++ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); ++ ++ /* ++ * Start to parse where left previously ++ */ ++ switch(ctx->phase) { ++ case 0: ++ /* ++ * PHASE 0. ++ * Check that the set of tags associated with given structure ++ * perfectly fits our expectations. ++ */ ++ ++ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, ++ tag_mode, 1, &ctx->left, 0); ++ if(rval.code != RC_OK) { ++ ASN_DEBUG("%s tagging check failed: %d", ++ td->name, rval.code); ++ return rval; ++ } ++ ++ if(ctx->left >= 0) ++ ctx->left += rval.consumed; /* ?Substracted below! */ ++ ADVANCE(rval.consumed); ++ ++ ASN_DEBUG("Structure consumes %ld bytes, " ++ "buffer %ld", (long)ctx->left, (long)size); ++ ++ NEXT_PHASE(ctx); ++ /* Fall through */ ++ case 1: ++ /* ++ * PHASE 1. ++ * From the place where we've left it previously, ++ * try to decode the next item. ++ */ ++ for(;; ctx->step = 0) { ++ ssize_t tag_len; /* Length of TLV's T */ ++ ++ if(ctx->step & 1) ++ goto microphase2; ++ ++ /* ++ * MICROPHASE 1: Synchronize decoding. ++ */ ++ ++ if(ctx->left == 0) { ++ ASN_DEBUG("End of SET OF %s", td->name); ++ /* ++ * No more things to decode. ++ * Exit out of here. ++ */ ++ PHASE_OUT(ctx); ++ RETURN(RC_OK); ++ } ++ ++ /* ++ * Fetch the T from TLV. ++ */ ++ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); ++ switch(tag_len) { ++ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); ++ /* Fall through */ ++ case -1: RETURN(RC_FAIL); ++ } ++ ++ if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { ++ if(LEFT < 2) { ++ if(SIZE_VIOLATION) ++ RETURN(RC_FAIL); ++ else ++ RETURN(RC_WMORE); ++ } else if(((const uint8_t *)ptr)[1] == 0) { ++ /* ++ * Found the terminator of the ++ * indefinite length structure. ++ */ ++ break; ++ } ++ } ++ ++ /* Outmost tag may be unknown and cannot be fetched/compared */ ++ if(elm->tag != (ber_tlv_tag_t)-1) { ++ if(BER_TAGS_EQUAL(tlv_tag, elm->tag)) { ++ /* ++ * The new list member of expected type has arrived. ++ */ ++ } else { ++ ASN_DEBUG("Unexpected tag %s fixed SET OF %s", ++ ber_tlv_tag_string(tlv_tag), td->name); ++ ASN_DEBUG("%s SET OF has tag %s", ++ td->name, ber_tlv_tag_string(elm->tag)); ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ /* ++ * MICROPHASE 2: Invoke the member-specific decoder. ++ */ ++ ctx->step |= 1; /* Confirm entering next microphase */ ++ microphase2: ++ ++ /* ++ * Invoke the member fetch routine according to member's type ++ */ ++ rval = elm->type->ber_decoder(opt_codec_ctx, ++ elm->type, &ctx->ptr, ptr, LEFT, 0); ++ ASN_DEBUG("In %s SET OF %s code %d consumed %d", ++ td->name, elm->type->name, ++ rval.code, (int)rval.consumed); ++ switch(rval.code) { ++ case RC_OK: ++ { ++ asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); ++ if(ASN_SET_ADD(list, ctx->ptr) != 0) ++ RETURN(RC_FAIL); ++ else ++ ctx->ptr = 0; ++ } ++ break; ++ case RC_WMORE: /* More data expected */ ++ if(!SIZE_VIOLATION) { ++ ADVANCE(rval.consumed); ++ RETURN(RC_WMORE); ++ } ++ /* Fall through */ ++ case RC_FAIL: /* Fatal error */ ++ RETURN(RC_FAIL); ++ } /* switch(rval) */ ++ ++ ADVANCE(rval.consumed); ++ } /* for(all list members) */ ++ ++ NEXT_PHASE(ctx); ++ case 2: ++ /* ++ * Read in all "end of content" TLVs. ++ */ ++ while(ctx->left < 0) { ++ if(LEFT < 2) { ++ if(LEFT > 0 && ((const char *)ptr)[0] != 0) { ++ /* Unexpected tag */ ++ RETURN(RC_FAIL); ++ } else { ++ RETURN(RC_WMORE); ++ } ++ } ++ if(((const char *)ptr)[0] == 0 ++ && ((const char *)ptr)[1] == 0) { ++ ADVANCE(2); ++ ctx->left++; ++ } else { ++ RETURN(RC_FAIL); ++ } ++ } ++ ++ PHASE_OUT(ctx); ++ } ++ ++ RETURN(RC_OK); ++} ++ ++/* ++ * Internally visible buffer holding a single encoded element. ++ */ ++struct _el_buffer { ++ uint8_t *buf; ++ size_t length; ++ size_t size; ++}; ++/* Append bytes to the above structure */ ++static int _el_addbytes(const void *buffer, size_t size, void *el_buf_ptr) { ++ struct _el_buffer *el_buf = (struct _el_buffer *)el_buf_ptr; ++ ++ if(el_buf->length + size > el_buf->size) ++ return -1; ++ ++ memcpy(el_buf->buf + el_buf->length, buffer, size); ++ ++ el_buf->length += size; ++ return 0; ++} ++static int _el_buf_cmp(const void *ap, const void *bp) { ++ const struct _el_buffer *a = (const struct _el_buffer *)ap; ++ const struct _el_buffer *b = (const struct _el_buffer *)bp; ++ int ret; ++ size_t common_len; ++ ++ if(a->length < b->length) ++ common_len = a->length; ++ else ++ common_len = b->length; ++ ++ ret = memcmp(a->buf, b->buf, common_len); ++ if(ret == 0) { ++ if(a->length < b->length) ++ ret = -1; ++ else if(a->length > b->length) ++ ret = 1; ++ } ++ ++ return ret; ++} ++ ++/* ++ * The DER encoder of the SET OF type. ++ */ ++asn_enc_rval_t ++SET_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr, ++ int tag_mode, ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_TYPE_member_t *elm = td->elements; ++ asn_TYPE_descriptor_t *elm_type = elm->type; ++ der_type_encoder_f *der_encoder = elm_type->der_encoder; ++ asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); ++ size_t computed_size = 0; ++ ssize_t encoding_size = 0; ++ struct _el_buffer *encoded_els; ++ ssize_t eels_count = 0; ++ size_t max_encoded_len = 1; ++ asn_enc_rval_t erval; ++ int ret; ++ int edx; ++ ++ ASN_DEBUG("Estimating size for SET OF %s", td->name); ++ ++ /* ++ * Gather the length of the underlying members sequence. ++ */ ++ for(edx = 0; edx < list->count; edx++) { ++ void *memb_ptr = list->array[edx]; ++ if(!memb_ptr) continue; ++ erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, 0, 0); ++ if(erval.encoded == -1) ++ return erval; ++ computed_size += erval.encoded; ++ ++ /* Compute maximum encoding's size */ ++ if(max_encoded_len < (size_t)erval.encoded) ++ max_encoded_len = erval.encoded; ++ } ++ ++ /* ++ * Encode the TLV for the sequence itself. ++ */ ++ encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, ++ cb, app_key); ++ if(encoding_size == -1) { ++ erval.encoded = -1; ++ erval.failed_type = td; ++ erval.structure_ptr = ptr; ++ return erval; ++ } ++ computed_size += encoding_size; ++ ++ if(!cb || list->count == 0) { ++ erval.encoded = computed_size; ++ _ASN_ENCODED_OK(erval); ++ } ++ ++ /* ++ * DER mandates dynamic sorting of the SET OF elements ++ * according to their encodings. Build an array of the ++ * encoded elements. ++ */ ++ encoded_els = (struct _el_buffer *)MALLOC( ++ list->count * sizeof(encoded_els[0])); ++ if(encoded_els == NULL) { ++ erval.encoded = -1; ++ erval.failed_type = td; ++ erval.structure_ptr = ptr; ++ return erval; ++ } ++ ++ ASN_DEBUG("Encoding members of %s SET OF", td->name); ++ ++ /* ++ * Encode all members. ++ */ ++ for(edx = 0; edx < list->count; edx++) { ++ void *memb_ptr = list->array[edx]; ++ struct _el_buffer *encoded_el = &encoded_els[eels_count]; ++ ++ if(!memb_ptr) continue; ++ ++ /* ++ * Prepare space for encoding. ++ */ ++ encoded_el->buf = (uint8_t *)MALLOC(max_encoded_len); ++ if(encoded_el->buf) { ++ encoded_el->length = 0; ++ encoded_el->size = max_encoded_len; ++ } else { ++ for(edx--; edx >= 0; edx--) ++ FREEMEM(encoded_els[edx].buf); ++ FREEMEM(encoded_els); ++ erval.encoded = -1; ++ erval.failed_type = td; ++ erval.structure_ptr = ptr; ++ return erval; ++ } ++ ++ /* ++ * Encode the member into the prepared space. ++ */ ++ erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, ++ _el_addbytes, encoded_el); ++ if(erval.encoded == -1) { ++ for(; edx >= 0; edx--) ++ FREEMEM(encoded_els[edx].buf); ++ FREEMEM(encoded_els); ++ return erval; ++ } ++ encoding_size += erval.encoded; ++ eels_count++; ++ } ++ ++ /* ++ * Sort the encoded elements according to their encoding. ++ */ ++ qsort(encoded_els, eels_count, sizeof(encoded_els[0]), _el_buf_cmp); ++ ++ /* ++ * Report encoded elements to the application. ++ * Dispose of temporary sorted members table. ++ */ ++ ret = 0; ++ for(edx = 0; edx < eels_count; edx++) { ++ struct _el_buffer *encoded_el = &encoded_els[edx]; ++ /* Report encoded chunks to the application */ ++ if(ret == 0 ++ && cb(encoded_el->buf, encoded_el->length, app_key) < 0) ++ ret = -1; ++ FREEMEM(encoded_el->buf); ++ } ++ FREEMEM(encoded_els); ++ ++ if(ret || computed_size != (size_t)encoding_size) { ++ /* ++ * Standard callback failed, or ++ * encoded size is not equal to the computed size. ++ */ ++ erval.encoded = -1; ++ erval.failed_type = td; ++ erval.structure_ptr = ptr; ++ } else { ++ erval.encoded = computed_size; ++ } ++ ++ _ASN_ENCODED_OK(erval); ++} ++ ++#undef XER_ADVANCE ++#define XER_ADVANCE(num_bytes) do { \ ++ size_t num = num_bytes; \ ++ buf_ptr = ((const char *)buf_ptr) + num;\ ++ size -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++/* ++ * Decode the XER (XML) data. ++ */ ++asn_dec_rval_t ++SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **struct_ptr, const char *opt_mname, ++ const void *buf_ptr, size_t size) { ++ /* ++ * Bring closer parts of structure description. ++ */ ++ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; ++ asn_TYPE_member_t *element = td->elements; ++ const char *elm_tag; ++ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; ++ ++ /* ++ * ... and parts of the structure being constructed. ++ */ ++ void *st = *struct_ptr; /* Target structure. */ ++ asn_struct_ctx_t *ctx; /* Decoder context */ ++ ++ asn_dec_rval_t rval; /* Return value from a decoder */ ++ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(st == 0) { ++ st = *struct_ptr = CALLOC(1, specs->struct_size); ++ if(st == 0) RETURN(RC_FAIL); ++ } ++ ++ /* Which tag is expected for the downstream */ ++ if(specs->as_XMLValueList) { ++ elm_tag = (specs->as_XMLValueList == 1) ? 0 : ""; ++ } else { ++ elm_tag = (*element->name) ++ ? element->name : element->type->xml_tag; ++ } ++ ++ /* ++ * Restore parsing context. ++ */ ++ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); ++ ++ /* ++ * Phases of XER/XML processing: ++ * Phase 0: Check that the opening tag matches our expectations. ++ * Phase 1: Processing body and reacting on closing tag. ++ * Phase 2: Processing inner type. ++ */ ++ for(; ctx->phase <= 2;) { ++ pxer_chunk_type_e ch_type; /* XER chunk type */ ++ ssize_t ch_size; /* Chunk size */ ++ xer_check_tag_e tcv; /* Tag check value */ ++ ++ /* ++ * Go inside the inner member of a set. ++ */ ++ if(ctx->phase == 2) { ++ asn_dec_rval_t tmprval; ++ ++ /* Invoke the inner type decoder, m.b. multiple times */ ++ ASN_DEBUG("XER/SET OF element [%s]", elm_tag); ++ tmprval = element->type->xer_decoder(opt_codec_ctx, ++ element->type, &ctx->ptr, elm_tag, ++ buf_ptr, size); ++ if(tmprval.code == RC_OK) { ++ asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); ++ if(ASN_SET_ADD(list, ctx->ptr) != 0) ++ RETURN(RC_FAIL); ++ ctx->ptr = 0; ++ XER_ADVANCE(tmprval.consumed); ++ } else { ++ XER_ADVANCE(tmprval.consumed); ++ RETURN(tmprval.code); ++ } ++ ctx->phase = 1; /* Back to body processing */ ++ ASN_DEBUG("XER/SET OF phase => %d", ctx->phase); ++ /* Fall through */ ++ } ++ ++ /* ++ * Get the next part of the XML stream. ++ */ ++ ch_size = xer_next_token(&ctx->context, ++ buf_ptr, size, &ch_type); ++ switch(ch_size) { ++ case -1: RETURN(RC_FAIL); ++ case 0: RETURN(RC_WMORE); ++ default: ++ switch(ch_type) { ++ case PXER_COMMENT: /* Got XML comment */ ++ case PXER_TEXT: /* Ignore free-standing text */ ++ XER_ADVANCE(ch_size); /* Skip silently */ ++ continue; ++ case PXER_TAG: ++ break; /* Check the rest down there */ ++ } ++ } ++ ++ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); ++ ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s", ++ tcv, ctx->phase, xml_tag); ++ switch(tcv) { ++ case XCT_CLOSING: ++ if(ctx->phase == 0) break; ++ ctx->phase = 0; ++ /* Fall through */ ++ case XCT_BOTH: ++ if(ctx->phase == 0) { ++ /* No more things to decode */ ++ XER_ADVANCE(ch_size); ++ ctx->phase = 3; /* Phase out */ ++ RETURN(RC_OK); ++ } ++ /* Fall through */ ++ case XCT_OPENING: ++ if(ctx->phase == 0) { ++ XER_ADVANCE(ch_size); ++ ctx->phase = 1; /* Processing body phase */ ++ continue; ++ } ++ /* Fall through */ ++ case XCT_UNKNOWN_OP: ++ case XCT_UNKNOWN_BO: ++ ++ ASN_DEBUG("XER/SET OF: tcv=%d, ph=%d", tcv, ctx->phase); ++ if(ctx->phase == 1) { ++ /* ++ * Process a single possible member. ++ */ ++ ctx->phase = 2; ++ continue; ++ } ++ /* Fall through */ ++ default: ++ break; ++ } ++ ++ ASN_DEBUG("Unexpected XML tag in SET OF"); ++ break; ++ } ++ ++ ctx->phase = 3; /* "Phase out" on hard failure */ ++ RETURN(RC_FAIL); ++} ++ ++ ++ ++typedef struct xer_tmp_enc_s { ++ void *buffer; ++ size_t offset; ++ size_t size; ++} xer_tmp_enc_t; ++static int ++SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) { ++ xer_tmp_enc_t *t = (xer_tmp_enc_t *)key; ++ if(t->offset + size >= t->size) { ++ size_t newsize = (t->size << 2) + size; ++ void *p = REALLOC(t->buffer, newsize); ++ if(!p) return -1; ++ t->buffer = p; ++ t->size = newsize; ++ } ++ memcpy((char *)t->buffer + t->offset, buffer, size); ++ t->offset += size; ++ return 0; ++} ++static int ++SET_OF_xer_order(const void *aptr, const void *bptr) { ++ const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr; ++ const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr; ++ size_t minlen = a->offset; ++ int ret; ++ if(b->offset < minlen) minlen = b->offset; ++ /* Well-formed UTF-8 has this nice lexicographical property... */ ++ ret = memcmp(a->buffer, b->buffer, minlen); ++ if(ret != 0) return ret; ++ if(a->offset == b->offset) ++ return 0; ++ if(a->offset == minlen) ++ return -1; ++ return 1; ++} ++ ++ ++asn_enc_rval_t ++SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_enc_rval_t er; ++ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm = td->elements; ++ asn_anonymous_set_ *list = _A_SET_FROM_VOID(sptr); ++ const char *mname = specs->as_XMLValueList ++ ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); ++ size_t mlen = mname ? strlen(mname) : 0; ++ int xcan = (flags & XER_F_CANONICAL); ++ xer_tmp_enc_t *encs = 0; ++ size_t encs_count = 0; ++ void *original_app_key = app_key; ++ asn_app_consume_bytes_f *original_cb = cb; ++ int i; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ ++ if(xcan) { ++ encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0])); ++ if(!encs) _ASN_ENCODE_FAILED; ++ cb = SET_OF_encode_xer_callback; ++ } ++ ++ er.encoded = 0; ++ ++ for(i = 0; i < list->count; i++) { ++ asn_enc_rval_t tmper; ++ ++ void *memb_ptr = list->array[i]; ++ if(!memb_ptr) continue; ++ ++ if(encs) { ++ memset(&encs[encs_count], 0, sizeof(encs[0])); ++ app_key = &encs[encs_count]; ++ encs_count++; ++ } ++ ++ if(mname) { ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); ++ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); ++ } ++ ++ if(!xcan && specs->as_XMLValueList == 1) ++ _i_ASN_TEXT_INDENT(1, ilevel + 1); ++ tmper = elm->type->xer_encoder(elm->type, memb_ptr, ++ ilevel + (specs->as_XMLValueList != 2), ++ flags, cb, app_key); ++ if(tmper.encoded == -1) { ++ td = tmper.failed_type; ++ sptr = tmper.structure_ptr; ++ goto cb_failed; ++ } ++ if(tmper.encoded == 0 && specs->as_XMLValueList) { ++ const char *name = elm->type->xml_tag; ++ size_t len = strlen(name); ++ _ASN_CALLBACK3("<", 1, name, len, "/>", 2); ++ } ++ ++ if(mname) { ++ _ASN_CALLBACK3("", 1); ++ er.encoded += 5; ++ } ++ ++ er.encoded += (2 * mlen) + tmper.encoded; ++ } ++ ++ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); ++ ++ if(encs) { ++ xer_tmp_enc_t *enc = encs; ++ xer_tmp_enc_t *end = encs + encs_count; ++ ssize_t control_size = 0; ++ ++ cb = original_cb; ++ app_key = original_app_key; ++ qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order); ++ ++ for(; enc < end; enc++) { ++ _ASN_CALLBACK(enc->buffer, enc->offset); ++ FREEMEM(enc->buffer); ++ enc->buffer = 0; ++ control_size += enc->offset; ++ } ++ assert(control_size == er.encoded); ++ } ++ ++ goto cleanup; ++cb_failed: ++ er.encoded = -1; ++ er.failed_type = td; ++ er.structure_ptr = sptr; ++cleanup: ++ if(encs) { ++ while(encs_count-- > 0) { ++ if(encs[encs_count].buffer) ++ FREEMEM(encs[encs_count].buffer); ++ } ++ FREEMEM(encs); ++ } ++ _ASN_ENCODED_OK(er); ++} ++ ++int ++SET_OF_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_TYPE_member_t *elm = td->elements; ++ const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); ++ int ret; ++ int i; ++ ++ if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; ++ ++ /* Dump preamble */ ++ if(cb(td->name, strlen(td->name), app_key) < 0 ++ || cb(" ::= {", 6, app_key) < 0) ++ return -1; ++ ++ for(i = 0; i < list->count; i++) { ++ const void *memb_ptr = list->array[i]; ++ if(!memb_ptr) continue; ++ ++ _i_INDENT(1); ++ ++ ret = elm->type->print_struct(elm->type, memb_ptr, ++ ilevel + 1, cb, app_key); ++ if(ret) return ret; ++ } ++ ++ ilevel--; ++ _i_INDENT(1); ++ ++ return (cb("}", 1, app_key) < 0) ? -1 : 0; ++} ++ ++void ++SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { ++ if(td && ptr) { ++ asn_TYPE_member_t *elm = td->elements; ++ asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); ++ int i; ++ ++ /* ++ * Could not use set_of_empty() because of (*free) ++ * incompatibility. ++ */ ++ for(i = 0; i < list->count; i++) { ++ void *memb_ptr = list->array[i]; ++ if(memb_ptr) ++ ASN_STRUCT_FREE(*elm->type, memb_ptr); ++ } ++ list->count = 0; /* No meaningful elements left */ ++ ++ asn_set_empty(list); /* Remove (list->array) */ ++ ++ if(!contents_only) { ++ FREEMEM(ptr); ++ } ++ } ++} ++ ++int ++SET_OF_constraint(asn_TYPE_descriptor_t *td, const void *sptr, ++ asn_app_constraint_failed_f *ctfailcb, void *app_key) { ++ asn_TYPE_member_t *elm = td->elements; ++ asn_constr_check_f *constr; ++ const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); ++ int i; ++ ++ if(!sptr) { ++ _ASN_CTFAIL(app_key, td, ++ "%s: value not given (%s:%d)", ++ td->name, __FILE__, __LINE__); ++ return -1; ++ } ++ ++ constr = elm->memb_constraints; ++ if(!constr) constr = elm->type->check_constraints; ++ ++ /* ++ * Iterate over the members of an array. ++ * Validate each in turn, until one fails. ++ */ ++ for(i = 0; i < list->count; i++) { ++ const void *memb_ptr = list->array[i]; ++ int ret; ++ ++ if(!memb_ptr) continue; ++ ++ ret = constr(elm->type, memb_ptr, ctfailcb, app_key); ++ if(ret) return ret; ++ } ++ ++ /* ++ * Cannot inherit it eralier: ++ * need to make sure we get the updated version. ++ */ ++ if(!elm->memb_constraints) ++ elm->memb_constraints = elm->type->check_constraints; ++ ++ return 0; ++} ++ ++asn_dec_rval_t ++SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_dec_rval_t rv; ++ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm = td->elements; /* Single one */ ++ void *st = *sptr; ++ asn_anonymous_set_ *list; ++ asn_per_constraint_t *ct; ++ int repeat = 0; ++ ssize_t nelems; ++ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(!st) { ++ st = *sptr = CALLOC(1, specs->struct_size); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ list = _A_SET_FROM_VOID(st); ++ ++ /* Figure out which constraints to use */ ++ if(constraints) ct = &constraints->size; ++ else if(td->per_constraints) ct = &td->per_constraints->size; ++ else ct = 0; ++ ++ if(ct && ct->flags & APC_EXTENSIBLE) { ++ int value = per_get_few_bits(pd, 1); ++ if(value < 0) _ASN_DECODE_STARVED; ++ if(value) ct = 0; /* Not restricted! */ ++ } ++ ++ if(ct && ct->effective_bits >= 0) { ++ /* X.691, #19.5: No length determinant */ ++ nelems = per_get_few_bits(pd, ct->effective_bits); ++ ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", ++ (long)nelems, ct->lower_bound, td->name); ++ if(nelems < 0) _ASN_DECODE_STARVED; ++ nelems += ct->lower_bound; ++ } else { ++ nelems = -1; ++ } ++ ++ do { ++ int i; ++ if(nelems < 0) { ++ nelems = uper_get_length(pd, ++ ct ? ct->effective_bits : -1, &repeat); ++ ASN_DEBUG("Got to decode %d elements (eff %d)", ++ (int)nelems, (int)ct ? ct->effective_bits : -1); ++ if(nelems < 0) _ASN_DECODE_STARVED; ++ } ++ ++ for(i = 0; i < nelems; i++) { ++ void *ptr = 0; ++ ASN_DEBUG("SET OF %s decoding", elm->type->name); ++ rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, ++ elm->per_constraints, &ptr, pd); ++ ASN_DEBUG("%s SET OF %s decoded %d, %p", ++ td->name, elm->type->name, rv.code, ptr); ++ if(rv.code == RC_OK) { ++ if(ASN_SET_ADD(list, ptr) == 0) ++ continue; ++ ASN_DEBUG("Failed to add element into %s", ++ td->name); ++ /* Fall through */ ++ rv.code == RC_FAIL; ++ } else { ++ ASN_DEBUG("Failed decoding %s of %s (SET OF)", ++ elm->type->name, td->name); ++ } ++ if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); ++ return rv; ++ } ++ ++ nelems = -1; /* Allow uper_get_length() */ ++ } while(repeat); ++ ++ ASN_DEBUG("Decoded %s as SET OF", td->name); ++ ++ rv.code = RC_OK; ++ rv.consumed = 0; ++ return rv; ++} ++ +diff --git a/asn1/asn1c/constr_SET_OF.h b/asn1/asn1c/constr_SET_OF.h +new file mode 100644 +index 0000000000000000000000000000000000000000..bcd09662906b69e5ac5cfec82c8a47b47ab3f351 +--- /dev/null ++++ b/asn1/asn1c/constr_SET_OF.h +@@ -0,0 +1,42 @@ ++/*- ++ * Copyright (c) 2003 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _CONSTR_SET_OF_H_ ++#define _CONSTR_SET_OF_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct asn_SET_OF_specifics_s { ++ /* ++ * Target structure description. ++ */ ++ int struct_size; /* Size of the target structure. */ ++ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ ++ ++ /* XER-specific stuff */ ++ int as_XMLValueList; /* The member type must be encoded like this */ ++} asn_SET_OF_specifics_t; ++ ++/* ++ * A set specialized functions dealing with the SET OF type. ++ */ ++asn_struct_free_f SET_OF_free; ++asn_struct_print_f SET_OF_print; ++asn_constr_check_f SET_OF_constraint; ++ber_type_decoder_f SET_OF_decode_ber; ++der_type_encoder_f SET_OF_encode_der; ++xer_type_decoder_f SET_OF_decode_xer; ++xer_type_encoder_f SET_OF_encode_xer; ++per_type_decoder_f SET_OF_decode_uper; ++per_type_encoder_f SET_OF_encode_uper; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _CONSTR_SET_OF_H_ */ +diff --git a/asn1/asn1c/constr_TYPE.c b/asn1/asn1c/constr_TYPE.c +new file mode 100644 +index 0000000000000000000000000000000000000000..4bc88d44f3c54131da0696b60050bd26376ce5b4 +--- /dev/null ++++ b/asn1/asn1c/constr_TYPE.c +@@ -0,0 +1,77 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * Version of the ASN.1 infrastructure shipped with compiler. ++ */ ++int get_asn1c_environment_version() { return ASN1C_ENVIRONMENT_VERSION; } ++ ++static asn_app_consume_bytes_f _print2fp; ++ ++/* ++ * Return the outmost tag of the type. ++ */ ++ber_tlv_tag_t ++asn_TYPE_outmost_tag(asn_TYPE_descriptor_t *type_descriptor, ++ const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) { ++ ++ if(tag_mode) ++ return tag; ++ ++ if(type_descriptor->tags_count) ++ return type_descriptor->tags[0]; ++ ++ return type_descriptor->outmost_tag(type_descriptor, struct_ptr, 0, 0); ++} ++ ++/* ++ * Print the target language's structure in human readable form. ++ */ ++int ++asn_fprint(FILE *stream, asn_TYPE_descriptor_t *td, const void *struct_ptr) { ++ if(!stream) stream = stdout; ++ if(!td || !struct_ptr) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* Invoke type-specific printer */ ++ if(td->print_struct(td, struct_ptr, 1, _print2fp, stream)) ++ return -1; ++ ++ /* Terminate the output */ ++ if(_print2fp("\n", 1, stream)) ++ return -1; ++ ++ return fflush(stream); ++} ++ ++/* Dump the data into the specified stdio stream */ ++static int ++_print2fp(const void *buffer, size_t size, void *app_key) { ++ FILE *stream = (FILE *)app_key; ++ ++ if(fwrite(buffer, 1, size, stream) != size) ++ return -1; ++ ++ return 0; ++} ++ ++ ++/* ++ * Some compilers do not support variable args macros. ++ * This function is a replacement of ASN_DEBUG() macro. ++ */ ++void ASN_DEBUG_f(const char *fmt, ...); ++void ASN_DEBUG_f(const char *fmt, ...) { ++ va_list ap; ++ va_start(ap, fmt); ++ vfprintf(stderr, fmt, ap); ++ fprintf(stderr, "\n"); ++ va_end(ap); ++} +diff --git a/asn1/asn1c/constr_TYPE.h b/asn1/asn1c/constr_TYPE.h +new file mode 100644 +index 0000000000000000000000000000000000000000..95507c8097b840457eafb95e1bae4abcff6a3e22 +--- /dev/null ++++ b/asn1/asn1c/constr_TYPE.h +@@ -0,0 +1,180 @@ ++/*- ++ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++/* ++ * This file contains the declaration structure called "ASN.1 Type Definition", ++ * which holds all information necessary for encoding and decoding routines. ++ * This structure even contains pointer to these encoding and decoding routines ++ * for each defined ASN.1 type. ++ */ ++#ifndef _CONSTR_TYPE_H_ ++#define _CONSTR_TYPE_H_ ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++struct asn_TYPE_member_s; /* Forward declaration */ ++ ++/* ++ * This type provides the context information for various ASN.1 routines, ++ * primarily ones doing decoding. A member _asn_ctx of this type must be ++ * included into certain target language's structures, such as compound types. ++ */ ++typedef struct asn_struct_ctx_s { ++ short phase; /* Decoding phase */ ++ short step; /* Elementary step of a phase */ ++ int context; /* Other context information */ ++ void *ptr; /* Decoder-specific stuff (stack elements) */ ++ ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ ++} asn_struct_ctx_t; ++ ++#include /* Basic Encoding Rules decoder */ ++#include /* Distinguished Encoding Rules encoder */ ++#include /* Decoder of XER (XML, text) */ ++#include /* Encoder into XER (XML, text) */ ++#include /* Packet Encoding Rules decoder */ ++#include /* Packet Encoding Rules encoder */ ++#include /* Subtype constraints support */ ++ ++/* ++ * Free the structure according to its specification. ++ * If (free_contents_only) is set, the wrapper structure itself (struct_ptr) ++ * will not be freed. (It may be useful in case the structure is allocated ++ * statically or arranged on the stack, yet its elements are allocated ++ * dynamically.) ++ */ ++typedef void (asn_struct_free_f)( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, int free_contents_only); ++#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF),ptr,0) ++#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ ++ (asn_DEF).free_struct(&(asn_DEF),ptr,1) ++ ++/* ++ * Print the structure according to its specification. ++ */ ++typedef int (asn_struct_print_f)( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ const void *struct_ptr, ++ int level, /* Indentation level */ ++ asn_app_consume_bytes_f *callback, void *app_key); ++ ++/* ++ * Return the outmost tag of the type. ++ * If the type is untagged CHOICE, the dynamic operation is performed. ++ * NOTE: This function pointer type is only useful internally. ++ * Do not use it in your application. ++ */ ++typedef ber_tlv_tag_t (asn_outmost_tag_f)( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); ++/* The instance of the above function type; used internally. */ ++asn_outmost_tag_f asn_TYPE_outmost_tag; ++ ++ ++/* ++ * The definitive description of the destination language's structure. ++ */ ++typedef struct asn_TYPE_descriptor_s { ++ char *name; /* A name of the ASN.1 type. "" in some cases. */ ++ char *xml_tag; /* Name used in XML tag */ ++ ++ /* ++ * Generalized functions for dealing with the specific type. ++ * May be directly invoked by applications. ++ */ ++ asn_struct_free_f *free_struct; /* Free the structure */ ++ asn_struct_print_f *print_struct; /* Human readable output */ ++ asn_constr_check_f *check_constraints; /* Constraints validator */ ++ ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ ++ der_type_encoder_f *der_encoder; /* Canonical DER encoder */ ++ xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ ++ xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ ++ per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ ++ per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ ++ ++ /*********************************************************************** ++ * Internally useful members. Not to be used by applications directly. * ++ **********************************************************************/ ++ ++ /* ++ * Tags that are expected to occur. ++ */ ++ asn_outmost_tag_f *outmost_tag; /* */ ++ ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ ++ int tags_count; /* Number of tags which are expected */ ++ ber_tlv_tag_t *all_tags;/* Every tag for BER/containment */ ++ int all_tags_count; /* Number of tags */ ++ ++ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ ++ ++ /* ++ * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). ++ */ ++ struct asn_TYPE_member_s *elements; ++ int elements_count; ++ ++ /* ++ * Additional information describing the type, used by appropriate ++ * functions above. ++ */ ++ void *specifics; ++} asn_TYPE_descriptor_t; ++ ++/* ++ * This type describes an element of the constructed type, ++ * i.e. SEQUENCE, SET, CHOICE, etc. ++ */ ++ enum asn_TYPE_flags_e { ++ ATF_NOFLAGS, ++ ATF_POINTER = 0x01, /* Represented by the pointer */ ++ ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ ++ }; ++typedef struct asn_TYPE_member_s { ++ enum asn_TYPE_flags_e flags; /* Element's presentation flags */ ++ int optional; /* Following optional members, including current */ ++ int memb_offset; /* Offset of the element */ ++ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ ++ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ ++ asn_TYPE_descriptor_t *type; /* Member type descriptor */ ++ asn_constr_check_f *memb_constraints; /* Constraints validator */ ++ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ ++ int (*default_value)(int setval, void **sptr); /* DEFAULT */ ++ char *name; /* ASN.1 identifier of the element */ ++} asn_TYPE_member_t; ++ ++/* ++ * BER tag to element number mapping. ++ */ ++typedef struct asn_TYPE_tag2member_s { ++ ber_tlv_tag_t el_tag; /* Outmost tag of the member */ ++ int el_no; /* Index of the associated member, base 0 */ ++ int toff_first; /* First occurence of the el_tag, relative */ ++ int toff_last; /* Last occurence of the el_tag, relatvie */ ++} asn_TYPE_tag2member_t; ++ ++/* ++ * This function is a wrapper around (td)->print_struct, which prints out ++ * the contents of the target language's structure (struct_ptr) into the ++ * file pointer (stream) in human readable form. ++ * RETURN VALUES: ++ * 0: The structure is printed. ++ * -1: Problem dumping the structure. ++ * (See also xer_fprint() in xer_encoder.h) ++ */ ++int asn_fprint(FILE *stream, /* Destination stream descriptor */ ++ asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ ++ const void *struct_ptr); /* Structure to be printed */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _CONSTR_TYPE_H_ */ +diff --git a/asn1/asn1c/constraints.c b/asn1/asn1c/constraints.c +new file mode 100644 +index 0000000000000000000000000000000000000000..1bdda73e5d68cba8311e3fda444fd86d20865d2d +--- /dev/null ++++ b/asn1/asn1c/constraints.c +@@ -0,0 +1,93 @@ ++#include "asn_internal.h" ++#include "constraints.h" ++ ++int ++asn_generic_no_constraint(asn_TYPE_descriptor_t *type_descriptor, ++ const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { ++ ++ (void)type_descriptor; /* Unused argument */ ++ (void)struct_ptr; /* Unused argument */ ++ (void)cb; /* Unused argument */ ++ (void)key; /* Unused argument */ ++ ++ /* Nothing to check */ ++ return 0; ++} ++ ++int ++asn_generic_unknown_constraint(asn_TYPE_descriptor_t *type_descriptor, ++ const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { ++ ++ (void)type_descriptor; /* Unused argument */ ++ (void)struct_ptr; /* Unused argument */ ++ (void)cb; /* Unused argument */ ++ (void)key; /* Unused argument */ ++ ++ /* Unknown how to check */ ++ return 0; ++} ++ ++struct errbufDesc { ++ asn_TYPE_descriptor_t *failed_type; ++ const void *failed_struct_ptr; ++ char *errbuf; ++ size_t errlen; ++}; ++ ++static void ++_asn_i_ctfailcb(void *key, asn_TYPE_descriptor_t *td, const void *sptr, const char *fmt, ...) { ++ struct errbufDesc *arg = key; ++ va_list ap; ++ ssize_t vlen; ++ ssize_t maxlen; ++ ++ arg->failed_type = td; ++ arg->failed_struct_ptr = sptr; ++ ++ maxlen = arg->errlen; ++ if(maxlen <= 0) ++ return; ++ ++ va_start(ap, fmt); ++ vlen = vsnprintf(arg->errbuf, maxlen, fmt, ap); ++ va_end(ap); ++ if(vlen >= maxlen) { ++ arg->errbuf[maxlen-1] = '\0'; /* Ensuring libc correctness */ ++ arg->errlen = maxlen - 1; /* Not counting termination */ ++ return; ++ } else if(vlen >= 0) { ++ arg->errbuf[vlen] = '\0'; /* Ensuring libc correctness */ ++ arg->errlen = vlen; /* Not counting termination */ ++ } else { ++ /* ++ * The libc on this system is broken. ++ */ ++ vlen = sizeof("") - 1; ++ maxlen--; ++ arg->errlen = vlen < maxlen ? vlen : maxlen; ++ memcpy(arg->errbuf, "", arg->errlen); ++ arg->errbuf[arg->errlen] = 0; ++ } ++ ++ return; ++} ++ ++int ++asn_check_constraints(asn_TYPE_descriptor_t *type_descriptor, ++ const void *struct_ptr, char *errbuf, size_t *errlen) { ++ struct errbufDesc arg; ++ int ret; ++ ++ arg.failed_type = 0; ++ arg.failed_struct_ptr = 0; ++ arg.errbuf = errbuf; ++ arg.errlen = errlen ? *errlen : 0; ++ ++ ret = type_descriptor->check_constraints(type_descriptor, ++ struct_ptr, _asn_i_ctfailcb, &arg); ++ if(ret == -1 && errlen) ++ *errlen = arg.errlen; ++ ++ return ret; ++} ++ +diff --git a/asn1/asn1c/constraints.h b/asn1/asn1c/constraints.h +new file mode 100644 +index 0000000000000000000000000000000000000000..5032345ee475564eeea0240bf73d76ae41139f6f +--- /dev/null ++++ b/asn1/asn1c/constraints.h +@@ -0,0 +1,63 @@ ++/*- ++ * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ ++#define _ASN1_CONSTRAINTS_VALIDATOR_H_ ++ ++#include /* Platform-dependent types */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++ ++/* ++ * Validate the structure according to the ASN.1 constraints. ++ * If errbuf and errlen are given, they shall be pointing to the appropriate ++ * buffer space and its length before calling this function. Alternatively, ++ * they could be passed as NULL's. If constraints validation fails, ++ * errlen will contain the actual number of bytes taken from the errbuf ++ * to encode an error message (properly 0-terminated). ++ * ++ * RETURN VALUES: ++ * This function returns 0 in case all ASN.1 constraints are met ++ * and -1 if one or more constraints were failed. ++ */ ++int ++asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, ++ const void *struct_ptr, /* Target language's structure */ ++ char *errbuf, /* Returned error description */ ++ size_t *errlen /* Length of the error description */ ++ ); ++ ++ ++/* ++ * Generic type for constraint checking callback, ++ * associated with every type descriptor. ++ */ ++typedef int (asn_constr_check_f)( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ const void *struct_ptr, ++ asn_app_constraint_failed_f *optional_callback, /* Log the error */ ++ void *optional_app_key /* Opaque key passed to a callback */ ++ ); ++ ++/******************************* ++ * INTERNALLY USEFUL FUNCTIONS * ++ *******************************/ ++ ++asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ ++asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ ++ ++/* ++ * Invoke the callback with a complete error message. ++ */ ++#define _ASN_CTFAIL if(ctfailcb) ctfailcb ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ +diff --git a/asn1/asn1c/der_encoder.c b/asn1/asn1c/der_encoder.c +new file mode 100644 +index 0000000000000000000000000000000000000000..6c859e1b08bba9600c97970df2fceede5716ddc0 +--- /dev/null ++++ b/asn1/asn1c/der_encoder.c +@@ -0,0 +1,199 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++ ++static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, ++ asn_app_consume_bytes_f *cb, void *app_key, int constructed); ++ ++/* ++ * The DER encoder of any type. ++ */ ++asn_enc_rval_t ++der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, ++ asn_app_consume_bytes_f *consume_bytes, void *app_key) { ++ ++ ASN_DEBUG("DER encoder invoked for %s", ++ type_descriptor->name); ++ ++ /* ++ * Invoke type-specific encoder. ++ */ ++ return type_descriptor->der_encoder(type_descriptor, ++ struct_ptr, /* Pointer to the destination structure */ ++ 0, 0, ++ consume_bytes, app_key); ++} ++ ++/* ++ * Argument type and callback necessary for der_encode_to_buffer(). ++ */ ++typedef struct enc_to_buf_arg { ++ void *buffer; ++ size_t left; ++} enc_to_buf_arg; ++static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { ++ enc_to_buf_arg *arg = (enc_to_buf_arg *)key; ++ ++ if(arg->left < size) ++ return -1; /* Data exceeds the available buffer size */ ++ ++ memcpy(arg->buffer, buffer, size); ++ arg->buffer = ((char *)arg->buffer) + size; ++ arg->left -= size; ++ ++ return 0; ++} ++ ++/* ++ * A variant of the der_encode() which encodes the data into the provided buffer ++ */ ++asn_enc_rval_t ++der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, ++ void *buffer, size_t buffer_size) { ++ enc_to_buf_arg arg; ++ asn_enc_rval_t ec; ++ ++ arg.buffer = buffer; ++ arg.left = buffer_size; ++ ++ ec = type_descriptor->der_encoder(type_descriptor, ++ struct_ptr, /* Pointer to the destination structure */ ++ 0, 0, encode_to_buffer_cb, &arg); ++ if(ec.encoded != -1) { ++ assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); ++ /* Return the encoded contents size */ ++ } ++ return ec; ++} ++ ++ ++/* ++ * Write out leading TL[v] sequence according to the type definition. ++ */ ++ssize_t ++der_write_tags(asn_TYPE_descriptor_t *sd, ++ size_t struct_length, ++ int tag_mode, int last_tag_form, ++ ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ ++ asn_app_consume_bytes_f *cb, ++ void *app_key) { ++ ber_tlv_tag_t *tags; /* Copy of tags stream */ ++ int tags_count; /* Number of tags */ ++ size_t overall_length; ++ ssize_t *lens; ++ int i; ++ ++ ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)", ++ sd->name, tag_mode, sd->tags_count, ++ ber_tlv_tag_string(tag), ++ tag_mode ++ ?(sd->tags_count+1 ++ -((tag_mode == -1) && sd->tags_count)) ++ :sd->tags_count ++ ); ++ ++ if(tag_mode) { ++ /* ++ * Instead of doing shaman dance like we do in ber_check_tags(), ++ * allocate a small array on the stack ++ * and initialize it appropriately. ++ */ ++ int stag_offset; ++ tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t)); ++ if(!tags) { /* Can fail on !x86 */ ++ errno = ENOMEM; ++ return -1; ++ } ++ tags_count = sd->tags_count ++ + 1 /* EXPLICIT or IMPLICIT tag is given */ ++ - ((tag_mode == -1) && sd->tags_count); ++ /* Copy tags over */ ++ tags[0] = tag; ++ stag_offset = -1 + ((tag_mode == -1) && sd->tags_count); ++ for(i = 1; i < tags_count; i++) ++ tags[i] = sd->tags[i + stag_offset]; ++ } else { ++ tags = sd->tags; ++ tags_count = sd->tags_count; ++ } ++ ++ /* No tags to write */ ++ if(tags_count == 0) ++ return 0; ++ ++ lens = (ssize_t *)alloca(tags_count * sizeof(lens[0])); ++ if(!lens) { ++ errno = ENOMEM; ++ return -1; ++ } ++ ++ /* ++ * Array of tags is initialized. ++ * Now, compute the size of the TLV pairs, from right to left. ++ */ ++ overall_length = struct_length; ++ for(i = tags_count - 1; i >= 0; --i) { ++ lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0); ++ if(lens[i] == -1) return -1; ++ overall_length += lens[i]; ++ lens[i] = overall_length - lens[i]; ++ } ++ ++ if(!cb) return overall_length - struct_length; ++ ++ ASN_DEBUG("%s %s TL sequence (%d elements)", ++ cb?"Encoding":"Estimating", sd->name, tags_count); ++ ++ /* ++ * Encode the TL sequence for real. ++ */ ++ for(i = 0; i < tags_count; i++) { ++ ssize_t len; ++ int _constr; ++ ++ /* Check if this tag happens to be constructed */ ++ _constr = (last_tag_form || i < (tags_count - 1)); ++ ++ len = der_write_TL(tags[i], lens[i], cb, app_key, _constr); ++ if(len == -1) return -1; ++ } ++ ++ return overall_length - struct_length; ++} ++ ++static ssize_t ++der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, ++ asn_app_consume_bytes_f *cb, void *app_key, ++ int constructed) { ++ uint8_t buf[32]; ++ size_t size = 0; ++ int buf_size = cb?sizeof(buf):0; ++ ssize_t tmp; ++ ++ /* Serialize tag (T from TLV) into possibly zero-length buffer */ ++ tmp = ber_tlv_tag_serialize(tag, buf, buf_size); ++ if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1; ++ size += tmp; ++ ++ /* Serialize length (L from TLV) into possibly zero-length buffer */ ++ tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0); ++ if(tmp == -1) return -1; ++ size += tmp; ++ ++ if(size > sizeof(buf)) ++ return -1; ++ ++ /* ++ * If callback is specified, invoke it, and check its return value. ++ */ ++ if(cb) { ++ if(constructed) *buf |= 0x20; ++ if(cb(buf, size, app_key) < 0) ++ return -1; ++ } ++ ++ return size; ++} +diff --git a/asn1/asn1c/der_encoder.h b/asn1/asn1c/der_encoder.h +new file mode 100644 +index 0000000000000000000000000000000000000000..4e2fb06c28194510c6434f4829e56b2436d8f092 +--- /dev/null ++++ b/asn1/asn1c/der_encoder.h +@@ -0,0 +1,67 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _DER_ENCODER_H_ ++#define _DER_ENCODER_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++ ++/* ++ * The DER encoder of any type. May be invoked by the application. ++ */ ++asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ asn_app_consume_bytes_f *consume_bytes_cb, ++ void *app_key /* Arbitrary callback argument */ ++ ); ++ ++/* A variant of der_encode() which encodes data into the pre-allocated buffer */ ++asn_enc_rval_t der_encode_to_buffer( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ void *buffer, /* Pre-allocated buffer */ ++ size_t buffer_size /* Initial buffer size (maximum) */ ++ ); ++ ++/* ++ * Type of the generic DER encoder. ++ */ ++typedef asn_enc_rval_t (der_type_encoder_f)( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ ++ ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ ++ void *app_key /* Arbitrary callback argument */ ++ ); ++ ++ ++/******************************* ++ * INTERNALLY USEFUL FUNCTIONS * ++ *******************************/ ++ ++/* ++ * Write out leading TL[v] sequence according to the type definition. ++ */ ++ssize_t der_write_tags( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ size_t struct_length, ++ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ ++ int last_tag_form, /* {0,!0}: prim, constructed */ ++ ber_tlv_tag_t tag, ++ asn_app_consume_bytes_f *consume_bytes_cb, ++ void *app_key ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _DER_ENCODER_H_ */ +diff --git a/asn1/asn1c/ipa.asn1 b/asn1/asn1c/ipa.asn1 +new file mode 100644 +index 0000000000000000000000000000000000000000..a18488ed371de7270afe7a0a9b345217205a2873 +--- /dev/null ++++ b/asn1/asn1c/ipa.asn1 +@@ -0,0 +1,37 @@ ++KeytabModule DEFINITIONS ::= BEGIN ++ ++ Int32 ::= INTEGER (-2147483648..2147483647) ++ -- signed values representable in 32 bits (from RFC4120) ++ ++ GetKeytabControl ::= CHOICE { ++ newkeys [0] GKNewKeys, ++ curkeys [1] GKCurrentKeys, ++ reply [2] GKReply ++ } ++ ++ GKNewKeys ::= SEQUENCE { ++ serviceIdentity [0] OCTET STRING, ++ enctypes [1] SEQUENCE OF Int32, ++ password [2] OCTET STRING OPTIONAL ++ } ++ ++ GKCurrentKeys ::= SEQUENCE { ++ serviceIdentity [0] OCTET STRING ++ } ++ ++ GKReply ::= SEQUENCE { ++ newkvno Int32, ++ keys SEQUENCE OF KrbKey ++ } ++ ++ KrbKey ::= SEQUENCE { ++ key [0] TypeValuePair, ++ salt [1] TypeValuePair OPTIONAL, ++ s2kparams [2] OCTET STRING OPTIONAL ++ } ++ ++ TypeValuePair ::= SEQUENCE { ++ type [0] Int32, ++ value [1] OCTET STRING ++ } ++END +diff --git a/asn1/asn1c/per_decoder.c b/asn1/asn1c/per_decoder.c +new file mode 100644 +index 0000000000000000000000000000000000000000..16dee369624bbf28bb8957e222abe77059980d9f +--- /dev/null ++++ b/asn1/asn1c/per_decoder.c +@@ -0,0 +1,55 @@ ++#include ++#include ++#include ++ ++asn_dec_rval_t ++uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { ++ asn_codec_ctx_t s_codec_ctx; ++ asn_dec_rval_t rval; ++ asn_per_data_t pd; ++ ++ if(skip_bits < 0 || skip_bits > 7 ++ || unused_bits < 0 || unused_bits > 7 ++ || (unused_bits > 0 && !size)) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Stack checker requires that the codec context ++ * must be allocated on the stack. ++ */ ++ if(opt_codec_ctx) { ++ if(opt_codec_ctx->max_stack_size) { ++ s_codec_ctx = *opt_codec_ctx; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ } else { ++ /* If context is not given, be security-conscious anyway */ ++ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); ++ s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ ++ /* Fill in the position indicator */ ++ pd.buffer = (const uint8_t *)buffer; ++ pd.nboff = skip_bits; ++ pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from */ ++ if(pd.nboff > pd.nbits) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Invoke type-specific decoder. ++ */ ++ if(!td->uper_decoder) ++ _ASN_DECODE_FAILED; /* PER is not compiled in */ ++ rval = td->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd); ++ if(rval.code == RC_OK) { ++ /* Return the number of consumed bits */ ++ rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) ++ + pd.nboff - skip_bits; ++ } else { ++ /* PER codec is not a restartable */ ++ rval.consumed = 0; ++ } ++ return rval; ++} ++ +diff --git a/asn1/asn1c/per_decoder.h b/asn1/asn1c/per_decoder.h +new file mode 100644 +index 0000000000000000000000000000000000000000..26aaf59400445aff62fb007370fc35c0cfa9b1b2 +--- /dev/null ++++ b/asn1/asn1c/per_decoder.h +@@ -0,0 +1,44 @@ ++/*- ++ * Copyright (c) 2005 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _PER_DECODER_H_ ++#define _PER_DECODER_H_ ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++ ++/* ++ * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. ++ */ ++asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ ++ void **struct_ptr, /* Pointer to a target structure's pointer */ ++ const void *buffer, /* Data to be decoded */ ++ size_t size, /* Size of data buffer */ ++ int skip_bits, /* Number of unused leading bits, 0..7 */ ++ int unused_bits /* Number of unused tailing bits, 0..7 */ ++ ); ++ ++ ++/* ++ * Type of the type-specific PER decoder function. ++ */ ++typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ asn_per_constraints_t *constraints, ++ void **struct_ptr, ++ asn_per_data_t *per_data ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _PER_DECODER_H_ */ +diff --git a/asn1/asn1c/per_encoder.c b/asn1/asn1c/per_encoder.c +new file mode 100644 +index 0000000000000000000000000000000000000000..614dd23331d482a05b973f790449359e7f503768 +--- /dev/null ++++ b/asn1/asn1c/per_encoder.c +@@ -0,0 +1,95 @@ ++#include ++#include ++#include ++ ++/* Flush partially filled buffer */ ++static int _uper_encode_flush_outp(asn_per_outp_t *po); ++ ++asn_enc_rval_t ++uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_per_outp_t po; ++ asn_enc_rval_t er; ++ ++ /* ++ * Invoke type-specific encoder. ++ */ ++ if(!td || !td->uper_encoder) ++ _ASN_ENCODE_FAILED; /* PER is not compiled in */ ++ ++ po.buffer = po.tmpspace; ++ po.nboff = 0; ++ po.nbits = 8 * sizeof(po.tmpspace); ++ po.outper = cb; ++ po.op_key = app_key; ++ po.flushed_bytes = 0; ++ ++ er = td->uper_encoder(td, 0, sptr, &po); ++ if(er.encoded != -1) { ++ size_t bits_to_flush; ++ ++ bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; ++ ++ /* Set number of bits encoded to a firm value */ ++ er.encoded = (po.flushed_bytes << 3) + bits_to_flush; ++ ++ if(_uper_encode_flush_outp(&po)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ return er; ++} ++ ++/* ++ * Argument type and callback necessary for uper_encode_to_buffer(). ++ */ ++typedef struct enc_to_buf_arg { ++ void *buffer; ++ size_t left; ++} enc_to_buf_arg; ++static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { ++ enc_to_buf_arg *arg = (enc_to_buf_arg *)key; ++ ++ if(arg->left < size) ++ return -1; /* Data exceeds the available buffer size */ ++ ++ memcpy(arg->buffer, buffer, size); ++ arg->buffer = ((char *)arg->buffer) + size; ++ arg->left -= size; ++ ++ return 0; ++} ++ ++asn_enc_rval_t ++uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { ++ enc_to_buf_arg key; ++ ++ /* ++ * Invoke type-specific encoder. ++ */ ++ if(!td || !td->uper_encoder) ++ _ASN_ENCODE_FAILED; /* PER is not compiled in */ ++ ++ key.buffer = buffer; ++ key.left = buffer_size; ++ ++ ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); ++ ++ return uper_encode(td, sptr, encode_to_buffer_cb, &key); ++} ++ ++static int ++_uper_encode_flush_outp(asn_per_outp_t *po) { ++ uint8_t *buf; ++ ++ if(po->nboff == 0 && po->buffer == po->tmpspace) ++ return 0; ++ ++ buf = po->buffer + (po->nboff >> 3); ++ /* Make sure we account for the last, partially filled */ ++ if(po->nboff & 0x07) { ++ buf[0] &= 0xff << (8 - (po->nboff & 0x07)); ++ buf++; ++ } ++ ++ return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); ++} +diff --git a/asn1/asn1c/per_encoder.h b/asn1/asn1c/per_encoder.h +new file mode 100644 +index 0000000000000000000000000000000000000000..9ac130b7373cc354effd24058027ea85ca3a9e59 +--- /dev/null ++++ b/asn1/asn1c/per_encoder.h +@@ -0,0 +1,49 @@ ++/*- ++ * Copyright (c) 2006 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _PER_ENCODER_H_ ++#define _PER_ENCODER_H_ ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++ ++/* ++ * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. ++ */ ++asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ ++ void *app_key /* Arbitrary callback argument */ ++); ++ ++/* A variant of uper_encode() which encodes data into the existing buffer */ ++asn_enc_rval_t uper_encode_to_buffer( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ void *buffer, /* Pre-allocated buffer */ ++ size_t buffer_size /* Initial buffer size (max) */ ++); ++ ++ ++/* ++ * Type of the generic PER encoder function. ++ */ ++typedef asn_enc_rval_t (per_type_encoder_f)( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ asn_per_constraints_t *constraints, ++ void *struct_ptr, ++ asn_per_outp_t *per_output ++); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _PER_ENCODER_H_ */ +diff --git a/asn1/asn1c/per_support.c b/asn1/asn1c/per_support.c +new file mode 100644 +index 0000000000000000000000000000000000000000..c83441931caf1fcc3a79c0062014833db3d141b5 +--- /dev/null ++++ b/asn1/asn1c/per_support.c +@@ -0,0 +1,318 @@ ++/* ++ * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * Extract a small number of bits (<= 31) from the specified PER data pointer. ++ */ ++int32_t ++per_get_few_bits(asn_per_data_t *pd, int nbits) { ++ size_t off; /* Next after last bit offset */ ++ uint32_t accum; ++ const uint8_t *buf; ++ ++ if(nbits < 0 || pd->nboff + nbits > pd->nbits) ++ return -1; ++ ++ ASN_DEBUG("[PER get %d bits from %p+%d bits]", ++ nbits, pd->buffer, pd->nboff); ++ ++ /* ++ * Normalize position indicator. ++ */ ++ if(pd->nboff >= 8) { ++ pd->buffer += (pd->nboff >> 3); ++ pd->nbits -= (pd->nboff & ~0x07); ++ pd->nboff &= 0x07; ++ } ++ off = (pd->nboff += nbits); ++ buf = pd->buffer; ++ ++ /* ++ * Extract specified number of bits. ++ */ ++ if(off <= 8) ++ accum = nbits ? (buf[0]) >> (8 - off) : 0; ++ else if(off <= 16) ++ accum = ((buf[0] << 8) + buf[1]) >> (16 - off); ++ else if(off <= 24) ++ accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); ++ else if(off <= 31) ++ accum = ((buf[0] << 24) + (buf[1] << 16) ++ + (buf[2] << 8) + (buf[3])) >> (32 - off); ++ else if(nbits <= 31) { ++ asn_per_data_t tpd = *pd; ++ /* Here are we with our 31-bits limit plus 1..7 bits offset. */ ++ tpd.nboff -= nbits; ++ accum = per_get_few_bits(&tpd, nbits - 24) << 24; ++ accum |= per_get_few_bits(&tpd, 24); ++ } else { ++ pd->nboff -= nbits; /* Oops, revert back */ ++ return -1; ++ } ++ ++ return (accum & (((uint32_t)1 << nbits) - 1)); ++} ++ ++/* ++ * Extract a large number of bits from the specified PER data pointer. ++ */ ++int ++per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { ++ int32_t value; ++ ++ if(alright && (nbits & 7)) { ++ /* Perform right alignment of a first few bits */ ++ value = per_get_few_bits(pd, nbits & 0x07); ++ if(value < 0) return -1; ++ *dst++ = value; /* value is already right-aligned */ ++ nbits &= ~7; ++ } ++ ++ while(nbits) { ++ if(nbits >= 24) { ++ value = per_get_few_bits(pd, 24); ++ if(value < 0) return -1; ++ *(dst++) = value >> 16; ++ *(dst++) = value >> 8; ++ *(dst++) = value; ++ nbits -= 24; ++ } else { ++ value = per_get_few_bits(pd, nbits); ++ if(value < 0) return -1; ++ if(nbits & 7) { /* implies left alignment */ ++ value <<= 8 - (nbits & 7), ++ nbits += 8 - (nbits & 7); ++ if(nbits > 24) ++ *dst++ = value >> 24; ++ } ++ if(nbits > 16) ++ *dst++ = value >> 16; ++ if(nbits > 8) ++ *dst++ = value >> 8; ++ *dst++ = value; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Get the length "n" from the stream. ++ */ ++ssize_t ++uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { ++ ssize_t value; ++ ++ *repeat = 0; ++ ++ if(ebits >= 0) return per_get_few_bits(pd, ebits); ++ ++ value = per_get_few_bits(pd, 8); ++ if(value < 0) return -1; ++ if((value & 128) == 0) /* #10.9.3.6 */ ++ return (value & 0x7F); ++ if((value & 64) == 0) { /* #10.9.3.7 */ ++ value = ((value & 63) << 8) | per_get_few_bits(pd, 8); ++ if(value < 0) return -1; ++ return value; ++ } ++ value &= 63; /* this is "m" from X.691, #10.9.3.8 */ ++ if(value < 1 || value > 4) ++ return -1; ++ *repeat = 1; ++ return (16384 * value); ++} ++ ++/* ++ * Get the normally small non-negative whole number. ++ * X.691, #10.6 ++ */ ++ssize_t ++uper_get_nsnnwn(asn_per_data_t *pd) { ++ ssize_t value; ++ ++ value = per_get_few_bits(pd, 7); ++ if(value & 64) { /* implicit (value < 0) */ ++ value &= 63; ++ value <<= 2; ++ value |= per_get_few_bits(pd, 2); ++ if(value & 128) /* implicit (value < 0) */ ++ return -1; ++ if(value == 0) ++ return 0; ++ if(value >= 3) ++ return -1; ++ value = per_get_few_bits(pd, 8 * value); ++ return value; ++ } ++ ++ return value; ++} ++ ++/* ++ * Put the normally small non-negative whole number. ++ * X.691, #10.6 ++ */ ++int ++uper_put_nsnnwn(asn_per_outp_t *po, int n) { ++ int bytes; ++ ++ if(n <= 63) { ++ if(n < 0) return -1; ++ return per_put_few_bits(po, n, 7); ++ } ++ if(n < 256) ++ bytes = 1; ++ else if(n < 65536) ++ bytes = 2; ++ else if(n < 256 * 65536) ++ bytes = 3; ++ else ++ return -1; /* This is not a "normally small" value */ ++ if(per_put_few_bits(po, bytes, 8)) ++ return -1; ++ ++ return per_put_few_bits(po, n, 8 * bytes); ++} ++ ++ ++/* ++ * Put a small number of bits (<= 31). ++ */ ++int ++per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { ++ size_t off; /* Next after last bit offset */ ++ size_t omsk; /* Existing last byte meaningful bits mask */ ++ uint8_t *buf; ++ ++ if(obits <= 0 || obits >= 32) return obits ? -1 : 0; ++ ++ ASN_DEBUG("[PER put %d bits to %p+%d bits]", ++ obits, po->buffer, po->nboff); ++ ++ /* ++ * Normalize position indicator. ++ */ ++ if(po->nboff >= 8) { ++ po->buffer += (po->nboff >> 3); ++ po->nbits -= (po->nboff & ~0x07); ++ po->nboff &= 0x07; ++ } ++ ++ /* ++ * Flush whole-bytes output, if necessary. ++ */ ++ if(po->nboff + obits > po->nbits) { ++ int complete_bytes = (po->buffer - po->tmpspace); ++ if(po->outper(po->buffer, complete_bytes, po->op_key) < 0) ++ return -1; ++ if(po->nboff) ++ po->tmpspace[0] = po->buffer[0]; ++ po->buffer = po->tmpspace; ++ po->nbits = 8 * sizeof(po->tmpspace); ++ po->flushed_bytes += complete_bytes; ++ } ++ ++ /* ++ * Now, due to sizeof(tmpspace), we are guaranteed large enough space. ++ */ ++ buf = po->buffer; ++ omsk = ~((1 << (8 - po->nboff)) - 1); ++ off = (po->nboff += obits); ++ ++ /* Clear data of debris before meaningful bits */ ++ bits &= (((uint32_t)1 << obits) - 1); ++ ++ ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, bits, bits, ++ po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk); ++ ++ if(off <= 8) /* Completely within 1 byte */ ++ bits <<= (8 - off), ++ buf[0] = (buf[0] & omsk) | bits; ++ else if(off <= 16) ++ bits <<= (16 - off), ++ buf[0] = (buf[0] & omsk) | (bits >> 8), ++ buf[1] = bits; ++ else if(off <= 24) ++ bits <<= (24 - off), ++ buf[0] = (buf[0] & omsk) | (bits >> 16), ++ buf[1] = bits >> 8, ++ buf[2] = bits; ++ else if(off <= 31) ++ bits <<= (32 - off), ++ buf[0] = (buf[0] & omsk) | (bits >> 24), ++ buf[1] = bits >> 16, ++ buf[2] = bits >> 8, ++ buf[3] = bits; ++ else { ++ ASN_DEBUG("->[PER out split %d]", obits); ++ per_put_few_bits(po, bits >> 8, 24); ++ per_put_few_bits(po, bits, obits - 24); ++ ASN_DEBUG("<-[PER out split %d]", obits); ++ } ++ ++ ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", ++ bits, bits, buf[0], po->buffer - po->tmpspace); ++ ++ return 0; ++} ++ ++ ++/* ++ * Output a large number of bits. ++ */ ++int ++per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { ++ ++ while(nbits) { ++ uint32_t value; ++ ++ if(nbits >= 24) { ++ value = (src[0] << 16) | (src[1] << 8) | src[2]; ++ src += 3; ++ nbits -= 24; ++ if(per_put_few_bits(po, value, 24)) ++ return -1; ++ } else { ++ value = src[0]; ++ if(nbits > 8) ++ value = (value << 8) | src[1]; ++ if(nbits > 16) ++ value = (value << 8) | src[2]; ++ if(nbits & 0x07) ++ value >>= (8 - (nbits & 0x07)); ++ if(per_put_few_bits(po, value, nbits)) ++ return -1; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Put the length "n" (or part of it) into the stream. ++ */ ++ssize_t ++uper_put_length(asn_per_outp_t *po, size_t length) { ++ ++ if(length <= 127) /* #10.9.3.6 */ ++ return per_put_few_bits(po, length, 8) ++ ? -1 : (ssize_t)length; ++ else if(length < 16384) /* #10.9.3.7 */ ++ return per_put_few_bits(po, length|0x8000, 16) ++ ? -1 : (ssize_t)length; ++ ++ length >>= 14; ++ if(length > 4) length = 4; ++ ++ return per_put_few_bits(po, 0xC0 | length, 8) ++ ? -1 : (ssize_t)(length << 14); ++} ++ +diff --git a/asn1/asn1c/per_support.h b/asn1/asn1c/per_support.h +new file mode 100644 +index 0000000000000000000000000000000000000000..420bb83c58d081ba3949951b67709e3200e7192a +--- /dev/null ++++ b/asn1/asn1c/per_support.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _PER_SUPPORT_H_ ++#define _PER_SUPPORT_H_ ++ ++#include /* Platform-specific types */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * Pre-computed PER constraints. ++ */ ++typedef struct asn_per_constraint_s { ++ enum asn_per_constraint_flags { ++ APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ ++ APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ ++ APC_CONSTRAINED = 0x2, /* Fully constrained */ ++ APC_EXTENSIBLE = 0x4 /* May have extension */ ++ } flags; ++ int range_bits; /* Full number of bits in the range */ ++ int effective_bits; /* Effective bits */ ++ long lower_bound; /* "lb" value */ ++ long upper_bound; /* "ub" value */ ++} asn_per_constraint_t; ++typedef struct asn_per_constraints_s { ++ asn_per_constraint_t value; ++ asn_per_constraint_t size; ++} asn_per_constraints_t; ++ ++/* ++ * This structure describes a position inside an incoming PER bit stream. ++ */ ++typedef struct asn_per_data_s { ++ const uint8_t *buffer; /* Pointer to the octet stream */ ++ size_t nboff; /* Bit offset to the meaningful bit */ ++ size_t nbits; /* Number of bits in the stream */ ++} asn_per_data_t; ++ ++/* ++ * Extract a small number of bits (<= 31) from the specified PER data pointer. ++ * This function returns -1 if the specified number of bits could not be ++ * extracted due to EOD or other conditions. ++ */ ++int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); ++ ++/* ++ * Extract a large number of bits from the specified PER data pointer. ++ * This function returns -1 if the specified number of bits could not be ++ * extracted due to EOD or other conditions. ++ */ ++int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, ++ int get_nbits); ++ ++/* ++ * Get the length "n" from the Unaligned PER stream. ++ */ ++ssize_t uper_get_length(asn_per_data_t *pd, ++ int effective_bound_bits, ++ int *repeat); ++ ++/* ++ * Get the normally small non-negative whole number. ++ */ ++ssize_t uper_get_nsnnwn(asn_per_data_t *pd); ++ ++/* ++ * This structure supports forming PER output. ++ */ ++typedef struct asn_per_outp_s { ++ uint8_t *buffer; /* Pointer into the (tmpspace) */ ++ size_t nboff; /* Bit offset to the meaningful bit */ ++ size_t nbits; /* Number of bits left in (tmpspace) */ ++ uint8_t tmpspace[32]; /* Preliminary storage to hold data */ ++ int (*outper)(const void *data, size_t size, void *op_key); ++ void *op_key; /* Key for (outper) data callback */ ++ size_t flushed_bytes; /* Bytes already flushed through (outper) */ ++} asn_per_outp_t; ++ ++/* Output a small number of bits (<= 31) */ ++int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); ++ ++/* Output a large number of bits */ ++int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); ++ ++/* ++ * Put the length "n" to the Unaligned PER stream. ++ * This function returns the number of units which may be flushed ++ * in the next units saving iteration. ++ */ ++ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); ++ ++/* ++ * Put the normally small non-negative whole number. ++ */ ++int uper_put_nsnnwn(asn_per_outp_t *po, int n); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _PER_SUPPORT_H_ */ +diff --git a/asn1/asn1c/xer_decoder.c b/asn1/asn1c/xer_decoder.c +new file mode 100644 +index 0000000000000000000000000000000000000000..161dc78ce5320368d07c0cd9b01032d07997e0fb +--- /dev/null ++++ b/asn1/asn1c/xer_decoder.c +@@ -0,0 +1,363 @@ ++/* ++ * Copyright (c) 2004, 2005 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include /* XER/XML parsing support */ ++ ++ ++/* ++ * Decode the XER encoding of a given type. ++ */ ++asn_dec_rval_t ++xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ void **struct_ptr, const void *buffer, size_t size) { ++ asn_codec_ctx_t s_codec_ctx; ++ ++ /* ++ * Stack checker requires that the codec context ++ * must be allocated on the stack. ++ */ ++ if(opt_codec_ctx) { ++ if(opt_codec_ctx->max_stack_size) { ++ s_codec_ctx = *opt_codec_ctx; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ } else { ++ /* If context is not given, be security-conscious anyway */ ++ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); ++ s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ ++ /* ++ * Invoke type-specific decoder. ++ */ ++ return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size); ++} ++ ++ ++ ++struct xer__cb_arg { ++ pxml_chunk_type_e chunk_type; ++ size_t chunk_size; ++ const void *chunk_buf; ++ int callback_not_invoked; ++}; ++ ++static int ++xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) { ++ struct xer__cb_arg *arg = (struct xer__cb_arg *)key; ++ arg->chunk_type = type; ++ arg->chunk_size = _chunk_size; ++ arg->chunk_buf = _chunk_data; ++ arg->callback_not_invoked = 0; ++ return -1; /* Terminate the XML parsing */ ++} ++ ++/* ++ * Fetch the next token from the XER/XML stream. ++ */ ++ssize_t ++xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) { ++ struct xer__cb_arg arg; ++ int new_stateContext = *stateContext; ++ ssize_t ret; ++ ++ arg.callback_not_invoked = 1; ++ ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg); ++ if(ret < 0) return -1; ++ if(arg.callback_not_invoked) { ++ assert(ret == 0); /* No data was consumed */ ++ return 0; /* Try again with more data */ ++ } else { ++ assert(arg.chunk_size); ++ assert(arg.chunk_buf == buffer); ++ } ++ ++ /* ++ * Translate the XML chunk types into more convenient ones. ++ */ ++ switch(arg.chunk_type) { ++ case PXML_TEXT: ++ *ch_type = PXER_TEXT; ++ break; ++ case PXML_TAG: return 0; /* Want more */ ++ case PXML_TAG_END: ++ *ch_type = PXER_TAG; ++ break; ++ case PXML_COMMENT: ++ case PXML_COMMENT_END: ++ *ch_type = PXER_COMMENT; ++ break; ++ } ++ ++ *stateContext = new_stateContext; ++ return arg.chunk_size; ++} ++ ++#define CSLASH 0x2f /* '/' */ ++#define LANGLE 0x3c /* '<' */ ++#define RANGLE 0x3e /* '>' */ ++ ++xer_check_tag_e ++xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { ++ const char *buf = (const char *)buf_ptr; ++ const char *end; ++ xer_check_tag_e ct = XCT_OPENING; ++ ++ if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) { ++ if(size >= 2) ++ ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]); ++ return XCT_BROKEN; ++ } ++ ++ /* ++ * Determine the tag class. ++ */ ++ if(buf[1] == CSLASH) { ++ buf += 2; /* advance past "" */ ++ ct = XCT_CLOSING; ++ if(size > 0 && buf[size-1] == CSLASH) ++ return XCT_BROKEN; /* */ ++ } else { ++ buf++; /* advance past "<" */ ++ size -= 2; /* strip "<" and ">" */ ++ if(size > 0 && buf[size-1] == CSLASH) { ++ ct = XCT_BOTH; ++ size--; /* One more, for "/" */ ++ } ++ } ++ ++ /* Sometimes we don't care about the tag */ ++ if(!need_tag || !*need_tag) ++ return (xer_check_tag_e)(XCT__UNK__MASK | ct); ++ ++ /* ++ * Determine the tag name. ++ */ ++ for(end = buf + size; buf < end; buf++, need_tag++) { ++ int b = *buf, n = *need_tag; ++ if(b != n) { ++ if(n == 0) { ++ switch(b) { ++ case 0x09: case 0x0a: case 0x0c: case 0x0d: ++ case 0x20: ++ /* "": whitespace is normal */ ++ return ct; ++ } ++ } ++ return (xer_check_tag_e)(XCT__UNK__MASK | ct); ++ } ++ if(b == 0) ++ return XCT_BROKEN; /* Embedded 0 in buf?! */ ++ } ++ if(*need_tag) ++ return (xer_check_tag_e)(XCT__UNK__MASK | ct); ++ ++ return ct; ++} ++ ++ ++#undef ADVANCE ++#define ADVANCE(num_bytes) do { \ ++ size_t num = (num_bytes); \ ++ buf_ptr = ((const char *)buf_ptr) + num; \ ++ size -= num; \ ++ consumed_myself += num; \ ++ } while(0) ++ ++#undef RETURN ++#define RETURN(_code) do { \ ++ rval.code = _code; \ ++ rval.consumed = consumed_myself; \ ++ if(rval.code != RC_OK) \ ++ ASN_DEBUG("Failed with %d", rval.code); \ ++ return rval; \ ++ } while(0) ++ ++#define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ ++ ssize_t converted_size = body_receiver \ ++ (struct_key, chunk_buf, chunk_size, \ ++ (size_t)chunk_size < size); \ ++ if(converted_size == -1) RETURN(RC_FAIL); \ ++ if(converted_size == 0 \ ++ && size == (size_t)chunk_size) \ ++ RETURN(RC_WMORE); \ ++ chunk_size = converted_size; \ ++ } while(0) ++#define XER_GOT_EMPTY() do { \ ++ if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ ++ RETURN(RC_FAIL); \ ++ } while(0) ++ ++/* ++ * Generalized function for decoding the primitive values. ++ */ ++asn_dec_rval_t ++xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, ++ asn_struct_ctx_t *ctx, /* Type decoder context */ ++ void *struct_key, ++ const char *xml_tag, /* Expected XML tag */ ++ const void *buf_ptr, size_t size, ++ int (*opt_unexpected_tag_decoder) ++ (void *struct_key, const void *chunk_buf, size_t chunk_size), ++ ssize_t (*body_receiver) ++ (void *struct_key, const void *chunk_buf, size_t chunk_size, ++ int have_more) ++ ) { ++ ++ asn_dec_rval_t rval; ++ ssize_t consumed_myself = 0; ++ ++ (void)opt_codec_ctx; ++ ++ /* ++ * Phases of XER/XML processing: ++ * Phase 0: Check that the opening tag matches our expectations. ++ * Phase 1: Processing body and reacting on closing tag. ++ */ ++ if(ctx->phase > 1) RETURN(RC_FAIL); ++ for(;;) { ++ pxer_chunk_type_e ch_type; /* XER chunk type */ ++ ssize_t ch_size; /* Chunk size */ ++ xer_check_tag_e tcv; /* Tag check value */ ++ ++ /* ++ * Get the next part of the XML stream. ++ */ ++ ch_size = xer_next_token(&ctx->context, buf_ptr, size, ++ &ch_type); ++ switch(ch_size) { ++ case -1: RETURN(RC_FAIL); ++ case 0: ++ RETURN(RC_WMORE); ++ default: ++ switch(ch_type) { ++ case PXER_COMMENT: /* Got XML comment */ ++ ADVANCE(ch_size); /* Skip silently */ ++ continue; ++ case PXER_TEXT: ++ if(ctx->phase == 0) { ++ /* ++ * We have to ignore whitespace here, ++ * but in order to be forward compatible ++ * with EXTENDED-XER (EMBED-VALUES, #25) ++ * any text is just ignored here. ++ */ ++ } else { ++ XER_GOT_BODY(buf_ptr, ch_size, size); ++ } ++ ADVANCE(ch_size); ++ continue; ++ case PXER_TAG: ++ break; /* Check the rest down there */ ++ } ++ } ++ ++ assert(ch_type == PXER_TAG && size); ++ ++ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); ++ /* ++ * Phase 0: ++ * Expecting the opening tag ++ * for the type being processed. ++ * Phase 1: ++ * Waiting for the closing XML tag. ++ */ ++ switch(tcv) { ++ case XCT_BOTH: ++ if(ctx->phase) break; ++ /* Finished decoding of an empty element */ ++ XER_GOT_EMPTY(); ++ ADVANCE(ch_size); ++ ctx->phase = 2; /* Phase out */ ++ RETURN(RC_OK); ++ case XCT_OPENING: ++ if(ctx->phase) break; ++ ADVANCE(ch_size); ++ ctx->phase = 1; /* Processing body phase */ ++ continue; ++ case XCT_CLOSING: ++ if(!ctx->phase) break; ++ ADVANCE(ch_size); ++ ctx->phase = 2; /* Phase out */ ++ RETURN(RC_OK); ++ case XCT_UNKNOWN_BO: ++ /* ++ * Certain tags in the body may be expected. ++ */ ++ if(opt_unexpected_tag_decoder ++ && opt_unexpected_tag_decoder(struct_key, ++ buf_ptr, ch_size) >= 0) { ++ /* Tag's processed fine */ ++ ADVANCE(ch_size); ++ if(!ctx->phase) { ++ /* We are not expecting ++ * the closing tag anymore. */ ++ ctx->phase = 2; /* Phase out */ ++ RETURN(RC_OK); ++ } ++ continue; ++ } ++ /* Fall through */ ++ default: ++ break; /* Unexpected tag */ ++ } ++ ++ ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag); ++ break; /* Dark and mysterious things have just happened */ ++ } ++ ++ RETURN(RC_FAIL); ++} ++ ++ ++int ++xer_is_whitespace(const void *chunk_buf, size_t chunk_size) { ++ const char *p = (const char *)chunk_buf; ++ const char *pend = p + chunk_size; ++ ++ for(; p < pend; p++) { ++ switch(*p) { ++ /* X.693, #8.1.4 ++ * HORISONTAL TAB (9) ++ * LINE FEED (10) ++ * CARRIAGE RETURN (13) ++ * SPACE (32) ++ */ ++ case 0x09: case 0x0a: case 0x0d: case 0x20: ++ break; ++ default: ++ return 0; ++ } ++ } ++ return 1; /* All whitespace */ ++} ++ ++/* ++ * This is a vastly simplified, non-validating XML tree skipper. ++ */ ++int ++xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) { ++ assert(*depth > 0); ++ switch(tcv) { ++ case XCT_BOTH: ++ case XCT_UNKNOWN_BO: ++ /* These negate each other. */ ++ return 0; ++ case XCT_OPENING: ++ case XCT_UNKNOWN_OP: ++ ++(*depth); ++ return 0; ++ case XCT_CLOSING: ++ case XCT_UNKNOWN_CL: ++ if(--(*depth) == 0) ++ return (tcv == XCT_CLOSING) ? 2 : 1; ++ return 0; ++ default: ++ return -1; ++ } ++} +diff --git a/asn1/asn1c/xer_decoder.h b/asn1/asn1c/xer_decoder.h +new file mode 100644 +index 0000000000000000000000000000000000000000..cf0d846fe72d66d0c03548e9f6f4b2c3ecab716d +--- /dev/null ++++ b/asn1/asn1c/xer_decoder.h +@@ -0,0 +1,106 @@ ++/*- ++ * Copyright (c) 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _XER_DECODER_H_ ++#define _XER_DECODER_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++ ++/* ++ * The XER decoder of any ASN.1 type. May be invoked by the application. ++ */ ++asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void **struct_ptr, /* Pointer to a target structure's pointer */ ++ const void *buffer, /* Data to be decoded */ ++ size_t size /* Size of data buffer */ ++ ); ++ ++/* ++ * Type of the type-specific XER decoder function. ++ */ ++typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void **struct_ptr, ++ const char *opt_mname, /* Member name */ ++ const void *buf_ptr, size_t size ++ ); ++ ++/******************************* ++ * INTERNALLY USEFUL FUNCTIONS * ++ *******************************/ ++ ++/* ++ * Generalized function for decoding the primitive values. ++ * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 ++ * and others. This function should not be used by applications, as its API ++ * is subject to changes. ++ */ ++asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, ++ asn_struct_ctx_t *ctx, /* Type decoder context */ ++ void *struct_key, /* Treated as opaque pointer */ ++ const char *xml_tag, /* Expected XML tag name */ ++ const void *buf_ptr, size_t size, ++ int (*opt_unexpected_tag_decoder) ++ (void *struct_key, const void *chunk_buf, size_t chunk_size), ++ ssize_t (*body_receiver) ++ (void *struct_key, const void *chunk_buf, size_t chunk_size, ++ int have_more) ++ ); ++ ++ ++/* ++ * Fetch the next XER (XML) token from the stream. ++ * The function returns the number of bytes occupied by the chunk type, ++ * returned in the _ch_type. The _ch_type is only set (and valid) when ++ * the return value is greater than 0. ++ */ ++ typedef enum pxer_chunk_type { ++ PXER_TAG, /* Complete XER tag */ ++ PXER_TEXT, /* Plain text between XER tags */ ++ PXER_COMMENT /* A comment, may be part of */ ++ } pxer_chunk_type_e; ++ssize_t xer_next_token(int *stateContext, ++ const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); ++ ++/* ++ * This function checks the buffer against the tag name is expected to occur. ++ */ ++ typedef enum xer_check_tag { ++ XCT_BROKEN = 0, /* The tag is broken */ ++ XCT_OPENING = 1, /* This is the tag */ ++ XCT_CLOSING = 2, /* This is the tag */ ++ XCT_BOTH = 3, /* This is the tag */ ++ XCT__UNK__MASK = 4, /* Mask of everything unexpected */ ++ XCT_UNKNOWN_OP = 5, /* Unexpected tag */ ++ XCT_UNKNOWN_CL = 6, /* Unexpected tag */ ++ XCT_UNKNOWN_BO = 7 /* Unexpected tag */ ++ } xer_check_tag_e; ++xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, ++ const char *need_tag); ++ ++/* ++ * Check whether this buffer consists of entirely XER whitespace characters. ++ * RETURN VALUES: ++ * 1: Whitespace or empty string ++ * 0: Non-whitespace ++ */ ++int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); ++ ++/* ++ * Skip the series of anticipated extensions. ++ */ ++int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _XER_DECODER_H_ */ +diff --git a/asn1/asn1c/xer_encoder.c b/asn1/asn1c/xer_encoder.c +new file mode 100644 +index 0000000000000000000000000000000000000000..aa7cf040ad874dc1f8bfd8e353c3061b71493fdb +--- /dev/null ++++ b/asn1/asn1c/xer_encoder.c +@@ -0,0 +1,67 @@ ++/*- ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++#include ++ ++/* ++ * The XER encoder of any type. May be invoked by the application. ++ */ ++asn_enc_rval_t ++xer_encode(asn_TYPE_descriptor_t *td, void *sptr, ++ enum xer_encoder_flags_e xer_flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_enc_rval_t er, tmper; ++ const char *mname; ++ size_t mlen; ++ int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2; ++ ++ if(!td || !sptr) goto cb_failed; ++ ++ mname = td->xml_tag; ++ mlen = strlen(mname); ++ ++ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); ++ ++ tmper = td->xer_encoder(td, sptr, 1, xer_flags, cb, app_key); ++ if(tmper.encoded == -1) return tmper; ++ ++ _ASN_CALLBACK3("\n", xcan); ++ ++ er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; ++ ++ _ASN_ENCODED_OK(er); ++cb_failed: ++ _ASN_ENCODE_FAILED; ++} ++ ++/* ++ * This is a helper function for xer_fprint, which directs all incoming data ++ * into the provided file descriptor. ++ */ ++static int ++xer__print2fp(const void *buffer, size_t size, void *app_key) { ++ FILE *stream = (FILE *)app_key; ++ ++ if(fwrite(buffer, 1, size, stream) != size) ++ return -1; ++ ++ return 0; ++} ++ ++int ++xer_fprint(FILE *stream, asn_TYPE_descriptor_t *td, void *sptr) { ++ asn_enc_rval_t er; ++ ++ if(!stream) stream = stdout; ++ if(!td || !sptr) ++ return -1; ++ ++ er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream); ++ if(er.encoded == -1) ++ return -1; ++ ++ return fflush(stream); ++} +diff --git a/asn1/asn1c/xer_encoder.h b/asn1/asn1c/xer_encoder.h +new file mode 100644 +index 0000000000000000000000000000000000000000..055e73c0c8b0dfd330c8d3f80c6d2b02270b3100 +--- /dev/null ++++ b/asn1/asn1c/xer_encoder.h +@@ -0,0 +1,59 @@ ++/*- ++ * Copyright (c) 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _XER_ENCODER_H_ ++#define _XER_ENCODER_H_ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++struct asn_TYPE_descriptor_s; /* Forward declaration */ ++ ++/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ ++enum xer_encoder_flags_e { ++ /* Mode of encoding */ ++ XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ ++ XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ ++}; ++ ++/* ++ * The XER encoder of any type. May be invoked by the application. ++ */ ++asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ enum xer_encoder_flags_e xer_flags, ++ asn_app_consume_bytes_f *consume_bytes_cb, ++ void *app_key /* Arbitrary callback argument */ ++ ); ++ ++/* ++ * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) ++ * output into the chosen file pointer. ++ * RETURN VALUES: ++ * 0: The structure is printed. ++ * -1: Problem printing the structure. ++ * WARNING: No sensible errno value is returned. ++ */ ++int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); ++ ++/* ++ * Type of the generic XER encoder. ++ */ ++typedef asn_enc_rval_t (xer_type_encoder_f)( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ int ilevel, /* Level of indentation */ ++ enum xer_encoder_flags_e xer_flags, ++ asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ ++ void *app_key /* Arbitrary callback argument */ ++ ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _XER_ENCODER_H_ */ +diff --git a/asn1/asn1c/xer_support.c b/asn1/asn1c/xer_support.c +new file mode 100644 +index 0000000000000000000000000000000000000000..9e34e6923467a436e20690633c4091b6db4683cd +--- /dev/null ++++ b/asn1/asn1c/xer_support.c +@@ -0,0 +1,233 @@ ++/* ++ * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. ++ * Copyright (c) 2003, 2004, 2005 Lev Walkin . ++ * All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#include ++#include ++ ++/* Parser states */ ++typedef enum { ++ ST_TEXT, ++ ST_TAG_START, ++ ST_TAG_BODY, ++ ST_TAG_QUOTE_WAIT, ++ ST_TAG_QUOTED_STRING, ++ ST_TAG_UNQUOTED_STRING, ++ ST_COMMENT_WAIT_DASH1, /* ""[0] */ ++ ST_COMMENT_CLO_RT /* "-->"[1] */ ++} pstate_e; ++ ++static pxml_chunk_type_e final_chunk_type[] = { ++ PXML_TEXT, ++ PXML_TAG_END, ++ PXML_COMMENT_END, ++ PXML_TAG_END, ++ PXML_COMMENT_END, ++}; ++ ++ ++static int ++_charclass[256] = { ++ 0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0, ++ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, ++ 1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, ++ 2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0, /* 01234567 89 */ ++ 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* ABCDEFG HIJKLMNO */ ++ 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0, /* PQRSTUVW XYZ */ ++ 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* abcdefg hijklmno */ ++ 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0 /* pqrstuvw xyz */ ++}; ++#define WHITESPACE(c) (_charclass[(unsigned char)(c)] == 1) ++#define ALNUM(c) (_charclass[(unsigned char)(c)] >= 2) ++#define ALPHA(c) (_charclass[(unsigned char)(c)] == 3) ++ ++/* Aliases for characters, ASCII/UTF-8 */ ++#define EXCLAM 0x21 /* '!' */ ++#define CQUOTE 0x22 /* '"' */ ++#define CDASH 0x2d /* '-' */ ++#define CSLASH 0x2f /* '/' */ ++#define LANGLE 0x3c /* '<' */ ++#define CEQUAL 0x3d /* '=' */ ++#define RANGLE 0x3e /* '>' */ ++#define CQUEST 0x3f /* '?' */ ++ ++/* Invoke token callback */ ++#define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ ++ int _ret; \ ++ pstate_e ns = _ns; \ ++ ssize_t _sz = (p - chunk_start) + _current_too; \ ++ if (!_sz) { \ ++ /* Shortcut */ \ ++ state = _ns; \ ++ break; \ ++ } \ ++ _ret = cb(type, chunk_start, _sz, key); \ ++ if(_ret < _sz) { \ ++ if(_current_too && _ret == -1) \ ++ state = ns; \ ++ goto finish; \ ++ } \ ++ chunk_start = p + _current_too; \ ++ state = ns; \ ++ } while(0) ++ ++#define TOKEN_CB(_type, _ns, _current_too) \ ++ TOKEN_CB_CALL(_type, _ns, _current_too, 0) ++ ++#define TOKEN_CB_FINAL(_type, _ns, _current_too) \ ++ TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1) ++ ++/* ++ * Parser itself ++ */ ++ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) { ++ pstate_e state = (pstate_e)*stateContext; ++ const char *chunk_start = (const char *)xmlbuf; ++ const char *p = chunk_start; ++ const char *end = p + size; ++ ++ for(; p < end; p++) { ++ int C = *(const unsigned char *)p; ++ switch(state) { ++ case ST_TEXT: ++ /* ++ * Initial state: we're in the middle of some text, ++ * or just have started. ++ */ ++ if (C == LANGLE) ++ /* We're now in the tag, probably */ ++ TOKEN_CB(PXML_TEXT, ST_TAG_START, 0); ++ break; ++ case ST_TAG_START: ++ if (ALPHA(C) || (C == CSLASH)) ++ state = ST_TAG_BODY; ++ else if (C == EXCLAM) ++ state = ST_COMMENT_WAIT_DASH1; ++ else ++ /* ++ * Not characters and not whitespace. ++ * Must be something like "3 < 4". ++ */ ++ TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */ ++ break; ++ case ST_TAG_BODY: ++ switch(C) { ++ case RANGLE: ++ /* End of the tag */ ++ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); ++ break; ++ case LANGLE: ++ /* ++ * The previous tag wasn't completed, but still ++ * recognized as valid. (Mozilla-compatible) ++ */ ++ TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0); ++ break; ++ case CEQUAL: ++ state = ST_TAG_QUOTE_WAIT; ++ break; ++ } ++ break; ++ case ST_TAG_QUOTE_WAIT: ++ /* ++ * State after the equal sign ("=") in the tag. ++ */ ++ switch(C) { ++ case CQUOTE: ++ state = ST_TAG_QUOTED_STRING; ++ break; ++ case RANGLE: ++ /* End of the tag */ ++ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); ++ break; ++ default: ++ if(!WHITESPACE(C)) ++ /* Unquoted string value */ ++ state = ST_TAG_UNQUOTED_STRING; ++ } ++ break; ++ case ST_TAG_QUOTED_STRING: ++ /* ++ * Tag attribute's string value in quotes. ++ */ ++ if(C == CQUOTE) { ++ /* Return back to the tag state */ ++ state = ST_TAG_BODY; ++ } ++ break; ++ case ST_TAG_UNQUOTED_STRING: ++ if(C == RANGLE) { ++ /* End of the tag */ ++ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); ++ } else if(WHITESPACE(C)) { ++ /* Return back to the tag state */ ++ state = ST_TAG_BODY; ++ } ++ break; ++ case ST_COMMENT_WAIT_DASH1: ++ if(C == CDASH) { ++ state = ST_COMMENT_WAIT_DASH2; ++ } else { ++ /* Some ordinary tag. */ ++ state = ST_TAG_BODY; ++ } ++ break; ++ case ST_COMMENT_WAIT_DASH2: ++ if(C == CDASH) { ++ /* Seen "<--" */ ++ state = ST_COMMENT; ++ } else { ++ /* Some ordinary tag */ ++ state = ST_TAG_BODY; ++ } ++ break; ++ case ST_COMMENT: ++ if(C == CDASH) { ++ state = ST_COMMENT_CLO_DASH2; ++ } ++ break; ++ case ST_COMMENT_CLO_DASH2: ++ if(C == CDASH) { ++ state = ST_COMMENT_CLO_RT; ++ } else { ++ /* This is not an end of a comment */ ++ state = ST_COMMENT; ++ } ++ break; ++ case ST_COMMENT_CLO_RT: ++ if(C == RANGLE) { ++ TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1); ++ } else if(C == CDASH) { ++ /* Maintain current state, still waiting for '>' */ ++ } else { ++ state = ST_COMMENT; ++ } ++ break; ++ } /* switch(*ptr) */ ++ } /* for() */ ++ ++ /* ++ * Flush the partially processed chunk, state permitting. ++ */ ++ if(p - chunk_start) { ++ switch (state) { ++ case ST_COMMENT: ++ TOKEN_CB(PXML_COMMENT, state, 0); ++ break; ++ case ST_TEXT: ++ TOKEN_CB(PXML_TEXT, state, 0); ++ break; ++ default: break; /* a no-op */ ++ } ++ } ++ ++finish: ++ *stateContext = (int)state; ++ return chunk_start - (const char *)xmlbuf; ++} ++ +diff --git a/asn1/asn1c/xer_support.h b/asn1/asn1c/xer_support.h +new file mode 100644 +index 0000000000000000000000000000000000000000..8b01944ab584c4bca90139c4b322fa5103030f49 +--- /dev/null ++++ b/asn1/asn1c/xer_support.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. ++ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. ++ * Redistribution and modifications are permitted subject to BSD license. ++ */ ++#ifndef _XER_SUPPORT_H_ ++#define _XER_SUPPORT_H_ ++ ++#include /* Platform-specific types */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * Types of data transferred to the application. ++ */ ++typedef enum { ++ PXML_TEXT, /* Plain text between XML tags. */ ++ PXML_TAG, /* A tag, starting with '<'. */ ++ PXML_COMMENT, /* An XML comment, including "". */ ++ /* ++ * The following chunk types are reported if the chunk ++ * terminates the specified XML element. ++ */ ++ PXML_TAG_END, /* Tag ended */ ++ PXML_COMMENT_END /* Comment ended */ ++} pxml_chunk_type_e; ++ ++/* ++ * Callback function that is called by the parser when parsed data is ++ * available. The _opaque is the pointer to a field containing opaque user ++ * data specified in pxml_create() call. The chunk type is _type and the text ++ * data is the piece of buffer identified by _bufid (as supplied to ++ * pxml_feed() call) starting at offset _offset and of _size bytes size. ++ * The chunk is NOT '\0'-terminated. ++ */ ++typedef int (pxml_callback_f)(pxml_chunk_type_e _type, ++ const void *_chunk_data, size_t _chunk_size, void *_key); ++ ++/* ++ * Parse the given buffer as it were a chunk of XML data. ++ * Invoke the specified callback each time the meaninful data is found. ++ * This function returns number of bytes consumed from the bufer. ++ * It will always be lesser than or equal to the specified _size. ++ * The next invocation of this function must account the difference. ++ */ ++ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, ++ pxml_callback_f *cb, void *_key); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _XER_SUPPORT_H_ */ +diff --git a/asn1/configure.ac b/asn1/configure.ac +new file mode 100644 +index 0000000000000000000000000000000000000000..c3e398ea20d4112ed8308ba5eb822ab22d256436 +--- /dev/null ++++ b/asn1/configure.ac +@@ -0,0 +1,24 @@ ++AC_PREREQ(2.59) ++m4_include(../version.m4) ++AC_INIT([ipa-server], ++ IPA_VERSION, ++ [https://hosted.fedoraproject.org/projects/freeipa/newticket]) ++ ++AC_CONFIG_HEADERS([config.h]) ++AC_PROG_CC_C99 ++AC_PROG_LIBTOOL ++ ++AM_INIT_AUTOMAKE([foreign]) ++ ++AM_MAINTAINER_MODE ++ ++AC_SUBST(VERSION) ++ ++# Files ++ ++AC_CONFIG_FILES([ ++ Makefile ++ asn1c/Makefile ++]) ++ ++AC_OUTPUT +diff --git a/asn1/ipa_asn1.c b/asn1/ipa_asn1.c +new file mode 100644 +index 0000000000000000000000000000000000000000..50851a804f59bdb3fcb9ba832b093860d914452d +--- /dev/null ++++ b/asn1/ipa_asn1.c +@@ -0,0 +1,229 @@ ++#include ++#include ++#include "ipa_asn1.h" ++#include "GetKeytabControl.h" ++ ++static bool encode_GetKeytabControl(GetKeytabControl_t *gkctrl, ++ void **buf, size_t *len) ++{ ++ asn_enc_rval_t rval; ++ char *buffer = NULL; ++ size_t buflen; ++ bool ret = false; ++ ++ /* dry run to compute the size */ ++ rval = der_encode(&asn_DEF_GetKeytabControl, gkctrl, NULL, NULL); ++ if (rval.encoded == -1) goto done; ++ ++ buflen = rval.encoded; ++ buffer = malloc(buflen); ++ if (!buffer) goto done; ++ ++ /* now for real */ ++ rval = der_encode_to_buffer(&asn_DEF_GetKeytabControl, ++ gkctrl, buffer, buflen); ++ if (rval.encoded == -1) goto done; ++ ++ *buf = buffer; ++ *len = buflen; ++ ret = true; ++ ++done: ++ if (!ret) { ++ free(buffer); ++ } ++ return ret; ++} ++ ++bool ipaasn1_enc_getkt(bool newkt, const char *princ, const char *pwd, ++ long *etypes, int numtypes, void **buf, size_t *len) ++{ ++ GetKeytabControl_t gkctrl = { 0 }; ++ bool ret = false; ++ ++ if (newkt) { ++ gkctrl.present = GetKeytabControl_PR_newkeys; ++ if (OCTET_STRING_fromString(&gkctrl.choice.newkeys.serviceIdentity, ++ princ) != 0) goto done; ++ ++ for (int i = 0; i < numtypes; i++) { ++ long *tmp; ++ tmp = malloc(sizeof(long)); ++ if (!tmp) goto done; ++ *tmp = etypes[i]; ++ ASN_SEQUENCE_ADD(&gkctrl.choice.newkeys.enctypes.list, tmp); ++ } ++ ++ if (pwd) { ++ gkctrl.choice.newkeys.password = ++ OCTET_STRING_new_fromBuf(&asn_DEF_OCTET_STRING, pwd, -1); ++ if (!gkctrl.choice.newkeys.password) goto done; ++ } ++ } else { ++ gkctrl.present = GetKeytabControl_PR_curkeys; ++ if (OCTET_STRING_fromString(&gkctrl.choice.curkeys.serviceIdentity, ++ princ) != 0) goto done; ++ } ++ ++ ret = encode_GetKeytabControl(&gkctrl, buf, len); ++ ++done: ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GetKeytabControl, &gkctrl); ++ return ret; ++} ++ ++bool ipaasn1_enc_getktreply(int kvno, struct keys_container *keys, ++ void **buf, size_t *len) ++{ ++ GetKeytabControl_t gkctrl = { 0 }; ++ bool ret = false; ++ ++ gkctrl.present = GetKeytabControl_PR_reply; ++ gkctrl.choice.reply.newkvno = kvno; ++ ++ for (int i = 0; i < keys->nkeys; i++) { ++ KrbKey_t *KK; ++ KK = calloc(1, sizeof(KrbKey_t)); ++ if (!KK) goto done; ++ KK->key.type = keys->ksdata[i].key.enctype; ++ KK->key.value.buf = malloc(keys->ksdata[i].key.length); ++ if (!KK->key.value.buf) goto done; ++ memcpy(KK->key.value.buf, ++ keys->ksdata[i].key.contents, keys->ksdata[i].key.length); ++ KK->key.value.size = keys->ksdata[i].key.length; ++ ++ if (keys->ksdata[i].salt.data != NULL) { ++ KK->salt = calloc(1, sizeof(TypeValuePair_t)); ++ if (!KK->salt) goto done; ++ KK->salt->type = keys->ksdata[i].salttype; ++ KK->salt->value.buf = malloc(keys->ksdata[i].salt.length); ++ if (!KK->salt->value.buf) goto done; ++ memcpy(KK->salt->value.buf, ++ keys->ksdata[i].salt.data, keys->ksdata[i].salt.length); ++ KK->salt->value.size = keys->ksdata[i].salt.length; ++ } ++ ++ /* KK->key.s2kparams not used for now */ ++ ++ ASN_SEQUENCE_ADD(&gkctrl.choice.reply.keys.list, KK); ++ } ++ ++ ret = encode_GetKeytabControl(&gkctrl, buf, len); ++ ++done: ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GetKeytabControl, &gkctrl); ++ return ret; ++} ++ ++static GetKeytabControl_t *decode_GetKeytabControl(void *buf, size_t len) ++{ ++ GetKeytabControl_t *gkctrl = NULL; ++ asn_dec_rval_t rval; ++ ++ rval = ber_decode(NULL, &asn_DEF_GetKeytabControl, ++ (void **)&gkctrl, buf, len); ++ if (rval.code == RC_OK) { ++ return gkctrl; ++ } ++ return NULL; ++} ++ ++bool ipaasn1_dec_getkt(void *buf, size_t len, bool *newkt, ++ char **princ, char **pwd, long **etypes, int *numtypes) ++{ ++ GetKeytabControl_t *gkctrl; ++ bool ret = false; ++ int num; ++ ++ gkctrl = decode_GetKeytabControl(buf, len); ++ if (!gkctrl) return false; ++ ++ switch (gkctrl->present) { ++ case GetKeytabControl_PR_newkeys: ++ *newkt = true; ++ *princ = strndup((char *)gkctrl->choice.newkeys.serviceIdentity.buf, ++ gkctrl->choice.newkeys.serviceIdentity.size); ++ if (!*princ) goto done; ++ ++ num = gkctrl->choice.newkeys.enctypes.list.count; ++ *etypes = malloc(num * sizeof(long)); ++ *numtypes = 0; ++ if (!*etypes) goto done; ++ for (int i = 0; i < num; i++) { ++ (*etypes)[i] = *gkctrl->choice.newkeys.enctypes.list.array[i]; ++ (*numtypes)++; ++ } ++ ++ if (gkctrl->choice.newkeys.password) { ++ *pwd = strndup((char *)gkctrl->choice.newkeys.password->buf, ++ gkctrl->choice.newkeys.password->size); ++ if (!*pwd) goto done; ++ } ++ break; ++ case GetKeytabControl_PR_curkeys: ++ *newkt = false; ++ *princ = strndup((char *)gkctrl->choice.curkeys.serviceIdentity.buf, ++ gkctrl->choice.curkeys.serviceIdentity.size); ++ if (!*princ) goto done; ++ break; ++ default: ++ goto done; ++ } ++ ++ ret = true; ++ ++done: ++ ASN_STRUCT_FREE(asn_DEF_GetKeytabControl, gkctrl); ++ return ret; ++} ++ ++bool ipaasn1_dec_getktreply(void *buf, size_t len, ++ int *kvno, struct keys_container *keys) ++{ ++ GetKeytabControl_t *gkctrl; ++ struct KrbKey *KK; ++ bool ret = false; ++ int nkeys; ++ ++ gkctrl = decode_GetKeytabControl(buf, len); ++ if (!gkctrl) return false; ++ ++ if (gkctrl->present != GetKeytabControl_PR_reply) goto done; ++ ++ *kvno = gkctrl->choice.reply.newkvno; ++ ++ nkeys = gkctrl->choice.reply.keys.list.count; ++ ++ keys->nkeys = 0; ++ keys->ksdata = calloc(nkeys, sizeof(struct krb_key_salt)); ++ if (!keys->ksdata) goto done; ++ ++ for (int i = 0; i < nkeys; i++) { ++ KK = gkctrl->choice.reply.keys.list.array[i]; ++ keys->ksdata[i].enctype = KK->key.type; ++ keys->ksdata[i].key.enctype = KK->key.type; ++ keys->ksdata[i].key.contents = malloc(KK->key.value.size); ++ if (!keys->ksdata[i].key.contents) goto done; ++ memcpy(keys->ksdata[i].key.contents, ++ KK->key.value.buf, KK->key.value.size); ++ keys->ksdata[i].key.length = KK->key.value.size; ++ ++ if (KK->salt) { ++ keys->ksdata[i].salttype = KK->salt->type; ++ keys->ksdata[i].salt.data = malloc(KK->salt->value.size); ++ if (!keys->ksdata[i].salt.data) goto done; ++ memcpy(keys->ksdata[i].salt.data, ++ KK->salt->value.buf, KK->salt->value.size); ++ keys->ksdata[i].salt.length = KK->salt->value.size; ++ } ++ ++ /* KK->s2kparams is ignored for now */ ++ keys->nkeys++; ++ } ++ ++ ret = true; ++ ++done: ++ ASN_STRUCT_FREE(asn_DEF_GetKeytabControl, gkctrl); ++ return ret; ++} +diff --git a/asn1/ipa_asn1.h b/asn1/ipa_asn1.h +new file mode 100644 +index 0000000000000000000000000000000000000000..6ffcc5cc81992966654c21e923a1f8883b32833b +--- /dev/null ++++ b/asn1/ipa_asn1.h +@@ -0,0 +1,76 @@ ++#ifndef __IPA_ASN1_H_ ++#define __IPA_ASN1_H_ ++ ++#include "ipa_krb5.h" ++ ++/** ++ * @brief Encodes a Get Keytab Request Control ++ * ++ * @param newkt Whether this is a New Key request or a Current Key one ++ * @param princ The principal the keys belong to (this is required) ++ * @param pwd Optional, only for New Key reqs, the password to use to ++ * create the new keys ++ * @param etypes Optional, only for New Key reqs, list of desired ++ * enctypes ++ * @param numtypes Optional, Number of desired enctypes in etypes ++ * @param buf A void pointer wil lcontain pointer to an allocated ++ * buffer with the serialized control, must be freed ++ * @param len Length of the returned buffer ++ * ++ * @return True on success or False on failure ++ */ ++bool ipaasn1_enc_getkt(bool newkt, const char *princ, const char *pwd, ++ long *etypes, int numtypes, void **buf, size_t *len); ++ ++/** ++ * @brief Encodes a Get Keytab Reply Control ++ * ++ * @param kvno The new key version number ++ * @param keys A set of keys to return to the caller ++ * @param buf A void pointer wil lcontain pointer to an allocated ++ * buffer with the serialized control, must be freed ++ * @param len Length of the returned buffer ++ * ++ * @return True on success or False on failure ++ */ ++bool ipaasn1_enc_getktreply(int kvno, struct keys_container *keys, ++ void **buf, size_t *len); ++ ++/** ++ * @brief Decodes a Get Keytab Requst Control ++ * ++ * @param buf A pointer to the serialized buffer ++ * @param len The lenght of the buffer ++ * @param newkt Returns whether this is a New Key or Current Key request ++ * @param princ Returns the principal the keys belong to. ++ * @param pwd Optional: The password to use to create keys ++ * @param etypes Optional: The desired enctypes ++ * @param numtypes Optional: Number of desired enctypes in etypes ++ * ++ * @return True on success or False on failure ++ * ++ * NOTE: princ, pwd, etypes and numtypes should be zeroed before being ++ * passed in input, and the caller may need to free them even in ++ * case of failure. ++ */ ++bool ipaasn1_dec_getkt(void *buf, size_t len, bool *newkt, ++ char **princ, char **pwd, ++ long **etypes, int *numtypes); ++ ++/** ++ * @brief Decodes a Get Keytab Reply Control ++ * ++ * @param buf A pointer to the serialized buffer ++ * @param len The lenght of the buffer ++ * @param kvno The new key version number ++ * @param keys A set of keys generated by the server ++ * ++ * @return True on success or False on failure ++ * ++ * NOTE: keys should be a zeroed structure and the caller may need to free ++ * it even in case of failure. ++ */ ++bool ipaasn1_dec_getktreply(void *buf, size_t len, ++ int *kvno, struct keys_container *keys); ++ ++#endif /* __IPA_ASN1_H_ */ +diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h +index 1e036e4f8eb8f9a92af6fb6190f507e02ae38934..7b877aa665dd6cb4e0c1cf9d8153319cc8f61a20 100644 +--- a/util/ipa_krb5.h ++++ b/util/ipa_krb5.h +@@ -1,6 +1,7 @@ + #ifndef __IPA_KRB5_H_ + #define __IPA_KRB5_H_ + ++#include + #include + #include + +-- +2.1.0 + diff --git a/0006-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch b/0006-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch new file mode 100644 index 0000000..399b841 --- /dev/null +++ b/0006-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch @@ -0,0 +1,812 @@ +From b1a30bff04fe9763b8b270590ec37084fd19b4e0 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Mon, 17 Nov 2014 15:19:57 -0500 +Subject: [PATCH 3/3] Use asn1c helpers to encode/decode the getkeytab control + +Replaces manual encoding with automatically generated code. + +Fixes: +https://fedorahosted.org/freeipa/ticket/4718 +https://fedorahosted.org/freeipa/ticket/4728 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Nathaniel McCallum +--- + Makefile | 1 + + daemons/configure.ac | 2 + + .../ipa-slapi-plugins/ipa-pwd-extop/Makefile.am | 7 +- + .../ipa-pwd-extop/ipa_pwd_extop.c | 239 ++++---------------- + ipa-client/Makefile.am | 4 + + ipa-client/configure.ac | 2 + + ipa-client/ipa-getkeytab.c | 246 ++++----------------- + 7 files changed, 106 insertions(+), 395 deletions(-) + +diff --git a/Makefile b/Makefile +index 9321c81fe5deebdd5d8b3d7e406347fc5d159610..3225a61b5b80e1ca0968e0c45f18c0ec3645df05 100644 +--- a/Makefile ++++ b/Makefile +@@ -76,6 +76,7 @@ client: client-autogen + + bootstrap-autogen: version-update client-autogen + @echo "Building IPA $(IPA_VERSION)" ++ cd asn1; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi + cd daemons; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR) --with-openldap; fi + cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi + +diff --git a/daemons/configure.ac b/daemons/configure.ac +index bfcdeadcd1dc73762d8c773ee50210d9bdb91e92..e81aa60e381e035aff73bf27475fc0f101a5fbf9 100644 +--- a/daemons/configure.ac ++++ b/daemons/configure.ac +@@ -5,6 +5,7 @@ AC_INIT([ipa-server], + [https://hosted.fedoraproject.org/projects/freeipa/newticket]) + + AC_CONFIG_HEADERS([config.h]) ++AC_CONFIG_SUBDIRS([../asn1]) + + AM_INIT_AUTOMAKE([foreign]) + m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) +@@ -305,6 +306,7 @@ AC_SUBST(LDFLAGS) + + AC_CONFIG_FILES([ + Makefile ++ ../asn1/Makefile + ipa-kdb/Makefile + ipa-sam/Makefile + ipa-otpd/Makefile +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am +index 4cf80ec802b40bb579a44fc9357c6a8119dab577..77beca2da0810ed5507d95b21f99d22f63b05fc1 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am +@@ -6,6 +6,7 @@ KRB5_UTIL_DIR = ../../../util + KRB5_UTIL_SRCS = $(KRB5_UTIL_DIR)/ipa_krb5.c \ + $(KRB5_UTIL_DIR)/ipa_pwd.c \ + $(KRB5_UTIL_DIR)/ipa_pwd_ntlm.c ++ASN1_UTIL_DIR=../../../asn1 + + AM_CPPFLAGS = \ + -I. \ +@@ -13,6 +14,7 @@ AM_CPPFLAGS = \ + -I$(srcdir)/../libotp \ + -I$(PLUGIN_COMMON_DIR) \ + -I$(KRB5_UTIL_DIR) \ ++ -I$(ASN1_UTIL_DIR) \ + -I$(COMMON_BER_DIR) \ + -DPREFIX=\""$(prefix)"\" \ + -DBINDIR=\""$(bindir)"\" \ +@@ -38,7 +40,10 @@ AM_LDFLAGS = \ + # Plugin Binary + plugindir = $(libdir)/dirsrv/plugins + plugin_LTLIBRARIES = libipa_pwd_extop.la +-libipa_pwd_extop_la_LIBADD = $(builddir)/../libotp/libotp.la ++libipa_pwd_extop_la_LIBADD = \ ++ $(builddir)/../libotp/libotp.la \ ++ $(ASN1_UTIL_DIR)/libipaasn1.la \ ++ $(NULL) + libipa_pwd_extop_la_SOURCES = \ + authcfg.c \ + common.c \ +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +index b87ae0dc7a180008228f31293b49212df80584e8..ceea49cab50b0836c882240f210339e60d26729b 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c +@@ -40,6 +40,7 @@ + #include "ipapwd.h" + #include "util.h" + #include "authcfg.h" ++#include "ipa_asn1.h" + + /* + * Password Modify - LDAP Extended Operation. +@@ -1310,31 +1311,7 @@ free_and_return: + return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; + } + +-/* Format of getkeytab request +- * +- * KeytabGetRequest ::= CHOICE { +- * newkeys [0] Newkeys, +- * curkeys [1] CurrentKeys, +- * reply [2] Reply +- * } +- * +- * NewKeys ::= SEQUENCE { +- * serviceIdentity [0] OCTET STRING, +- * enctypes [1] SEQUENCE OF Int16 +- * password [2] OCTET STRING OPTIONAL, +- * } +- * +- * CurrentKeys ::= SEQUENCE { +- * serviceIdentity [0] OCTET STRING, +- * } +- */ +- +-#define GK_REQUEST_NEWKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +-#define GK_REQUEST_CURKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREQ_SVCNAME_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) +- ++/* decode a getkeytab control request using libipaasn1 helpers */ + static int decode_getkeytab_request(struct berval *extop, bool *wantold, + char **_svcname, char **_password, + krb5_key_salt_tuple **kenctypes, +@@ -1342,96 +1319,44 @@ static int decode_getkeytab_request(struct berval *extop, bool *wantold, + { + int rc = LDAP_OPERATIONS_ERROR; + char *err_msg = NULL; +- BerElement *ber = NULL; +- ber_len_t tlen; +- ber_tag_t rtag; +- ber_tag_t ttag; +- ber_tag_t ctag; + char *svcname = NULL; + char *password = NULL; +- ber_int_t enctype; ++ long *etypes = NULL; ++ int numtypes = 0; + krb5_key_salt_tuple *enctypes = NULL; +- int num = 0; ++ bool newkt; ++ bool ret; ++ int i; + +- ber = ber_init(extop); +- if (ber == NULL) { +- err_msg = "KeytabGet Request decode failed.\n"; ++ ret = ipaasn1_dec_getkt(extop->bv_val, extop->bv_len, &newkt, ++ &svcname, &password, &etypes, &numtypes); ++ if (!ret) { ++ err_msg = "Failed to decode GetKeytab Control.\n"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + +- /* check this is a request */ +- rtag = ber_peek_tag(ber, &tlen); +- if (rtag != GK_REQUEST_NEWKEYS && rtag != GK_REQUEST_CURKEYS) { +- LOG_FATAL("ber_peek_tag failed, wrong request type\n"); +- err_msg = "Invalid payload.\n"; +- rc = LDAP_PROTOCOL_ERROR; +- goto done; +- } +- +- /* ber parse code */ +- ttag = ber_scanf(ber, "{ta", &ctag, &svcname); +- if (ttag == LBER_ERROR || ctag != GKREQ_SVCNAME_TAG) { +- LOG_FATAL("ber_scanf failed to decode service name\n"); +- err_msg = "Invalid payload.\n"; +- rc = LDAP_PROTOCOL_ERROR; +- goto done; +- } +- +- if (rtag == GK_REQUEST_CURKEYS) { +- rc = LDAP_SUCCESS; +- goto done; +- } +- +- ttag = ber_peek_tag(ber, &tlen); +- if (ttag != GKREQ_ENCTYPES_TAG) { +- LOG_FATAL("ber_peek_tag failed to find enctypes\n"); +- err_msg = "Invalid payload.\n"; +- rc = LDAP_PROTOCOL_ERROR; +- goto done; +- } +- ttag = ber_peek_tag(ber, &tlen); +- for (num = 0; ttag == LBER_INTEGER; num++) { +- if ((num % 10) == 0) { +- /* allocate space for at least 10 more enctypes */ +- enctypes = realloc(enctypes, +- (num + 10) * sizeof(krb5_key_salt_tuple)); ++ if (newkt) { ++ if (numtypes) { ++ enctypes = malloc(numtypes * sizeof(krb5_key_salt_tuple)); + if (!enctypes) { + LOG_FATAL("allocation failed\n"); + err_msg = "Internal error\n"; + rc = LDAP_OPERATIONS_ERROR; + goto done; + } +- } + +- ttag = ber_scanf(ber, "i", &enctype); +- if (ttag == LBER_ERROR) { +- LOG_FATAL("ber_scanf failed to decode enctype\n"); +- err_msg = "Invalid payload.\n"; +- rc = LDAP_PROTOCOL_ERROR; +- goto done; +- } +- +- enctypes[num].ks_enctype = enctype; +- enctypes[num].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; +- ttag = ber_peek_tag(ber, &tlen); +- } +- +- /* ttag peek done as last step of the previous for loop */ +- if (ttag == GKREQ_PASSWORD_TAG) { +- /* optional password present */ +- ttag = ber_scanf(ber, "a", &password); +- if (ttag == LBER_ERROR) { +- LOG_FATAL("ber_scanf failed to decode password\n"); +- err_msg = "Invalid payload.\n"; +- rc = LDAP_PROTOCOL_ERROR; +- goto done; ++ for (i = 0; i < numtypes; i++) { ++ enctypes[i].ks_enctype = etypes[i]; ++ enctypes[i].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; ++ } + } + } + + rc = LDAP_SUCCESS; + + done: ++ free(etypes); + if (rc != LDAP_SUCCESS) { + free(password); + free(svcname); +@@ -1440,78 +1365,34 @@ done: + } else { + *_password = password; + *_svcname = svcname; +- *wantold = (rtag == GK_REQUEST_CURKEYS); ++ *wantold = (newkt == false); + *kenctypes = enctypes; +- *num_kenctypes = num; ++ *num_kenctypes = numtypes; + } +- if (ber) ber_free(ber, 1); + return rc; + } + +-/* Format of getkeytab reply +- * +- * Reply ::= SEQUENCE { +- * new_kvno Int32 +- * keys SEQUENCE OF KrbKey, +- * } +- * +- * KrbKey ::= SEQUENCE { +- * key [0] EncryptionKey, +- * salt [1] KrbSalt OPTIONAL, +- * s2kparams [2] OCTET STRING OPTIONAL, +- * } +- * +- * EncryptionKey ::= SEQUENCE { +- * keytype [0] Int32, +- * keyvalue [1] OCTET STRING +- * } +- * +- * KrbSalt ::= SEQUENCE { +- * type [0] Int32, +- * salt [1] OCTET STRING +- * } +- */ +- +-#define GK_REPLY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) +-#define GKREP_KEY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +-#define GKREP_SALT_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREP_S2KPARAMS_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) +-#define GKREP_KEYTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +-#define GKREP_KEYVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREP_SALTTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +-#define GKREP_SALTVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +- + static int encode_getkeytab_reply(krb5_context krbctx, + krb5_keyblock *kmkey, int mkvno, + krb5_key_data *keys, int num_keys, + struct berval **_bvp) + { + int rc = LDAP_OPERATIONS_ERROR; ++ struct krb_key_salt ksdata[num_keys]; ++ struct keys_container ksc = { num_keys, ksdata }; + struct berval *bvp = NULL; +- BerElement *ber = NULL; +- ber_int_t kvno; +- krb5_data plain = { 0 }; ++ int kvno; ++ bool ret; + +- ber = ber_alloc(); +- if (!ber) { +- LOG_OOM(); +- goto done; +- } ++ memset(ksdata, '\0', num_keys * sizeof(struct krb_key_salt)); + + /* uses last key kvno */ + kvno = keys[num_keys-1].key_data_kvno; + +- rc = ber_printf(ber, "t{i{", GK_REPLY_TAG, kvno); +- if (rc == -1) { +- rc = LDAP_OPERATIONS_ERROR; +- LOG_FATAL("Failed to initiate key buffer\n"); +- goto done; +- } +- + for (int i = 0; i < num_keys; i++) { + krb5_enc_data cipher = { 0 }; ++ krb5_data plain = { 0 }; + krb5_int16 plen; +- void *p; + + /* retrieve plain key */ + memcpy(&plen, keys[i].key_data_contents[0], 2); +@@ -1521,13 +1402,12 @@ static int encode_getkeytab_reply(krb5_context krbctx, + cipher.kvno = mkvno; + + plain.length = le16toh(plen); +- p = realloc(plain.data, plain.length); +- if (!p) { ++ plain.data = malloc(plain.length); ++ if (!plain.data) { + LOG_FATAL("Failed to allocate plain buffer\n"); + rc = LDAP_OPERATIONS_ERROR; + goto done; + } +- plain.data = p; + + rc = krb5_c_decrypt(krbctx, kmkey, 0, 0, &cipher, &plain); + if (rc) { +@@ -1536,68 +1416,37 @@ static int encode_getkeytab_reply(krb5_context krbctx, + goto done; + } + +- rc = ber_printf(ber, +- "{t{tito}", +- GKREP_KEY_TAG, +- GKREP_KEYTYPE_TAG, +- (ber_int_t)keys[i].key_data_type[0], +- GKREP_KEYVALUE_TAG, +- plain.data, (ber_len_t)plain.length); +- if (rc == -1) { +- LOG_FATAL("Failed to encode key data\n"); +- rc = LDAP_OPERATIONS_ERROR; +- goto done; +- } ++ ksc.ksdata[i].enctype = keys[i].key_data_type[0]; ++ ksc.ksdata[i].key.enctype = keys[i].key_data_type[0]; ++ ksc.ksdata[i].key.contents = (void *)plain.data; ++ ksc.ksdata[i].key.length = plain.length; + + /* if salt available, add it */ + if (keys[i].key_data_length[1] != 0) { +- rc = ber_printf(ber, +- "t{tito}", +- GKREP_SALT_TAG, +- GKREP_SALTTYPE_TAG, +- (ber_int_t)keys[i].key_data_type[1], +- GKREP_SALTVALUE_TAG, +- keys[i].key_data_contents[1], +- (ber_len_t)keys[i].key_data_length[1]); +- if (rc == -1) { +- LOG_FATAL("Failed to encode salt data\n"); +- rc = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- } +- +- rc = ber_printf(ber, "}"); +- if (rc == -1) { +- LOG_FATAL("Failed to encode data\n"); +- rc = LDAP_OPERATIONS_ERROR; +- goto done; ++ ksc.ksdata[i].salttype = keys[i].key_data_type[1]; ++ ksc.ksdata[i].salt.data = (void *)keys[i].key_data_contents[1]; ++ ksc.ksdata[i].salt.length = keys[i].key_data_length[1]; + } + } + +- rc = ber_printf(ber, "}}"); +- if (rc == -1) { +- LOG_FATAL("Failed to terminate key buffer\n"); +- rc = LDAP_OPERATIONS_ERROR; +- goto done; +- } ++ bvp = calloc(1, sizeof(struct berval)); ++ if (!bvp) goto done; + +- rc = ber_flatten(ber, &bvp); +- if (rc == -1) { +- LOG_FATAL("Failed to encode key buffer\n"); +- rc = LDAP_OPERATIONS_ERROR; +- goto done; +- } ++ ret = ipaasn1_enc_getktreply(kvno, &ksc, ++ (void **)&bvp->bv_val, &bvp->bv_len); ++ if (!ret) goto done; + + rc = LDAP_SUCCESS; + + done: ++ for (int i = 0; i < ksc.nkeys; i ++) { ++ free(ksc.ksdata[i].key.contents); ++ } + if (rc != LDAP_SUCCESS) { + if (bvp) ber_bvfree(bvp); + } else { + *_bvp = bvp; + } +- if (ber) ber_free(ber, 1); +- free(plain.data); + return rc; + } + +diff --git a/ipa-client/Makefile.am b/ipa-client/Makefile.am +index 2df175e53b2a547acdad546db182b38011becd06..b9c7020f3b687b3c0030ed5166625e6ef07e2fa4 100644 +--- a/ipa-client/Makefile.am ++++ b/ipa-client/Makefile.am +@@ -14,11 +14,13 @@ export AM_CFLAGS + + KRB5_UTIL_DIR=../util + KRB5_UTIL_SRCS=$(KRB5_UTIL_DIR)/ipa_krb5.c ++ASN1_UTIL_DIR=../asn1 + + AM_CPPFLAGS = \ + -I. \ + -I$(srcdir) \ + -I$(KRB5_UTIL_DIR) \ ++ -I$(ASN1_UTIL_DIR) \ + -DPREFIX=\""$(prefix)"\" \ + -DBINDIR=\""$(bindir)"\" \ + -DLIBDIR=\""$(libdir)"\" \ +@@ -45,6 +47,7 @@ ipa_getkeytab_SOURCES = \ + $(NULL) + + ipa_getkeytab_LDADD = \ ++ ../asn1/libipaasn1.la \ + $(KRB5_LIBS) \ + $(OPENLDAP_LIBS) \ + $(SASL_LIBS) \ +@@ -80,6 +83,7 @@ ipa_join_LDADD = \ + $(NULL) + + SUBDIRS = \ ++ ../asn1 \ + ipaclient \ + ipa-install \ + man \ +diff --git a/ipa-client/configure.ac b/ipa-client/configure.ac +index 34625622d3e3bb64866b3b0b1a58d29e33f11a7d..78da8e6e413b8becbd4c75422abffb670050f446 100644 +--- a/ipa-client/configure.ac ++++ b/ipa-client/configure.ac +@@ -8,6 +8,7 @@ AC_PROG_LIBTOOL + + AC_CONFIG_SRCDIR([ipaclient/__init__.py]) + AC_CONFIG_HEADERS([config.h]) ++AC_CONFIG_SUBDIRS([../asn1]) + + AM_INIT_AUTOMAKE([foreign]) + +@@ -205,6 +206,7 @@ dnl --------------------------------------------------------------------------- + + AC_CONFIG_FILES([ + Makefile ++ ../asn1/Makefile + ipaclient/Makefile + ipa-install/Makefile + man/Makefile +diff --git a/ipa-client/ipa-getkeytab.c b/ipa-client/ipa-getkeytab.c +index bb43c333dca6560807a120103a1cb535fa87b76a..15255d6a33c8c298f138868ac545d4ebea415fe5 100644 +--- a/ipa-client/ipa-getkeytab.c ++++ b/ipa-client/ipa-getkeytab.c +@@ -40,6 +40,7 @@ + #include "config.h" + + #include "ipa_krb5.h" ++#include "ipa_asn1.h" + #include "ipa-client-common.h" + + static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *sit) +@@ -295,14 +296,15 @@ done: + return ret; + } + +-static BerElement *get_control_data(LDAPControl **list, const char *repoid) ++static int find_control_data(LDAPControl **list, const char *repoid, ++ struct berval *data) + { + LDAPControl *control = NULL; + int i; + + if (!list) { + fprintf(stderr, _("Missing reply control list!\n")); +- return NULL; ++ return LDAP_OPERATIONS_ERROR; + } + + for (i = 0; list[i]; i++) { +@@ -312,10 +314,22 @@ static BerElement *get_control_data(LDAPControl **list, const char *repoid) + } + if (!control) { + fprintf(stderr, _("Missing reply control!\n")); +- return NULL; ++ return LDAP_OPERATIONS_ERROR; + } + +- return ber_init(&control->ldctl_value); ++ *data = control->ldctl_value; ++ return LDAP_SUCCESS; ++} ++ ++static BerElement *get_control_data(LDAPControl **list, const char *repoid) ++{ ++ struct berval data; ++ int ret; ++ ++ ret = find_control_data(list, repoid, &data); ++ if (ret != LDAP_SUCCESS) return NULL; ++ ++ return ber_init(&data); + } + + static int ldap_set_keytab(krb5_context krbctx, +@@ -435,124 +449,42 @@ error_out: + return -1; + } + +-/* Format of getkeytab control +- * +- * KeytabGetRequest ::= CHOICE { +- * newkeys [0] Newkeys, +- * curkeys [1] CurrentKeys, +- * reply [2] Reply +- * } +- * +- * NewKeys ::= SEQUENCE { +- * serviceIdentity [0] OCTET STRING, +- * enctypes [1] SEQUENCE OF Int16 +- * password [2] OCTET STRING OPTIONAL, +- * } +- * +- * CurrentKeys ::= SEQUENCE { +- * serviceIdentity [0] OCTET STRING, +- * } +- * +- * Reply ::= SEQUENCE { +- * new_kvno Int32 +- * keys SEQUENCE OF KrbKey, +- * } +- * +- * KrbKey ::= SEQUENCE { +- * key [0] EncryptionKey, +- * salt [1] KrbSalt OPTIONAL, +- * s2kparams [2] OCTET STRING OPTIONAL, +- * } +- * +- * EncryptionKey ::= SEQUENCE { +- * keytype [0] Int32, +- * keyvalue [1] OCTET STRING +- * } +- * +- * KrbSalt ::= SEQUENCE { +- * type [0] Int32, +- * salt [1] OCTET STRING +- * } +- */ +- +-#define GK_REQUEST_NEWKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) +-#define GK_REQUEST_CURKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREQ_SVCNAME_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) +-#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) +- ++/* use asn1c generated code to fill up control */ + static struct berval *create_getkeytab_control(const char *svc_princ, bool gen, + const char *password, + struct krb_key_salt *encsalts, + int num_encsalts) + { +- struct berval *bval = NULL; +- BerElement *be; +- ber_tag_t ctag; +- ber_int_t e; +- int ret, i; +- +- be = ber_alloc_t(LBER_USE_DER); +- if (!be) { +- return NULL; +- } +- +- if (gen) { +- ctag = GK_REQUEST_NEWKEYS; +- } else { +- ctag = GK_REQUEST_CURKEYS; +- } +- +- ret = ber_printf(be, "t{ts", ctag, GKREQ_SVCNAME_TAG, svc_princ); +- if (ret == -1) { +- ber_free(be, 1); +- goto done; +- } ++ struct berval *result = NULL; ++ void *buffer = NULL; ++ size_t buflen; ++ long ets[num_encsalts]; ++ bool ret; ++ int i; + + if (gen) { +- ret = ber_printf(be, "t{", GKREQ_ENCTYPES_TAG); +- if (ret == -1) { +- ber_free(be, 1); +- goto done; +- } + for (i = 0; i < num_encsalts; i++) { +- e = encsalts[i].enctype; +- ret = ber_printf(be, "i", e); +- if (ret == -1) { +- ber_free(be, 1); +- goto done; +- } +- } +- ret = ber_printf(be, "}"); +- if (ret == -1) { +- ber_free(be, 1); +- goto done; +- } +- +- if (password) { +- ret = ber_printf(be, "ts", GKREQ_PASSWORD_TAG, password); +- if (ret == -1) { +- ber_free(be, 1); +- goto done; +- } ++ ets[i] = encsalts[i].enctype; + } + } ++ ret = ipaasn1_enc_getkt(gen, svc_princ, ++ password, ets, num_encsalts, ++ &buffer, &buflen); ++ if (!ret) goto done; + +- ret = ber_printf(be, "}"); +- if (ret == -1) { +- ber_free(be, 1); +- goto done; +- } ++ result = malloc(sizeof(struct berval)); ++ if (!result) goto done; + +- ret = ber_flatten(be, &bval); +- if (ret == -1) { +- ber_free(be, 1); +- goto done; +- } ++ result->bv_val = buffer; ++ result->bv_len = buflen; + + done: +- ber_free(be, 1); +- return bval; ++ if (result == NULL) { ++ if (buffer) { ++ free(buffer); ++ } ++ } ++ return result; + } + + #define GK_REPLY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) +@@ -571,13 +503,8 @@ static int ldap_get_keytab(krb5_context krbctx, bool generate, char *password, + struct berval *control = NULL; + LDAP *ld = NULL; + LDAPControl **srvctrl = NULL; +- BerElement *ber = NULL; +- ber_tag_t rtag; +- ber_tag_t ctag; +- ber_len_t tlen; +- ber_int_t vno; +- ber_int_t tint; +- struct berval tbval; ++ struct berval data; ++ bool res; + int ret; + + *err_msg = NULL; +@@ -609,98 +536,19 @@ static int ldap_get_keytab(krb5_context krbctx, bool generate, char *password, + goto done; + } + +- ber = get_control_data(srvctrl, KEYTAB_GET_OID); +- if (!ber) { +- *err_msg = _("Failed to find or parse reply control!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- +- rtag = ber_scanf(ber, "t{i{", &ctag, &vno); +- if (rtag == LBER_ERROR || ctag != GK_REPLY_TAG) { +- *err_msg = _("Failed to parse control head!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- +- keys->nkeys = 0; +- keys->ksdata = NULL; +- +- rtag = ber_peek_tag(ber, &tlen); +- for (int i = 0; rtag == LBER_SEQUENCE; i++) { +- if ((i % 5) == 0) { +- struct krb_key_salt *ksdata; +- ksdata = realloc(keys->ksdata, +- (i + 5) * sizeof(struct krb_key_salt)); +- if (!ksdata) { +- *err_msg = _("Out of memory!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- keys->ksdata = ksdata; +- } +- memset(&keys->ksdata[i], 0, sizeof(struct krb_key_salt)); +- keys->nkeys = i + 1; +- +- rtag = ber_scanf(ber, "{t{io}", &ctag, &tint, &tbval); +- if (rtag == LBER_ERROR || ctag != GKREP_KEY_TAG) { +- *err_msg = _("Failed to parse enctype in key data!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- keys->ksdata[i].enctype = tint; +- keys->ksdata[i].key.enctype = tint; +- keys->ksdata[i].key.length = tbval.bv_len; +- keys->ksdata[i].key.contents = malloc(tbval.bv_len); +- if (!keys->ksdata[i].key.contents) { +- *err_msg = _("Out of memory!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- memcpy(keys->ksdata[i].key.contents, tbval.bv_val, tbval.bv_len); +- ber_memfree(tbval.bv_val); +- +- rtag = ber_peek_tag(ber, &tlen); +- if (rtag == GKREP_SALT_TAG) { +- rtag = ber_scanf(ber, "t{io}", &ctag, &tint, &tbval); +- if (rtag == LBER_ERROR) { +- *err_msg = _("Failed to parse salt in key data!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- keys->ksdata[i].salttype = tint; +- keys->ksdata[i].salt.length = tbval.bv_len; +- keys->ksdata[i].salt.data = malloc(tbval.bv_len); +- if (!keys->ksdata[i].salt.data) { +- *err_msg = _("Out of memory!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- memcpy(keys->ksdata[i].salt.data, tbval.bv_val, tbval.bv_len); +- ber_memfree(tbval.bv_val); +- } +- rtag = ber_scanf(ber, "}"); +- if (rtag == LBER_ERROR) { +- *err_msg = _("Failed to parse ending of key data!\n"); +- ret = LDAP_OPERATIONS_ERROR; +- goto done; +- } +- +- rtag = ber_peek_tag(ber, &tlen); +- } ++ ret = find_control_data(srvctrl, KEYTAB_GET_OID, &data); ++ if (ret != LDAP_SUCCESS) goto done; + +- rtag = ber_scanf(ber, "}}"); +- if (rtag == LBER_ERROR) { +- *err_msg = _("Failed to parse ending of control!\n"); ++ res = ipaasn1_dec_getktreply(data.bv_val, data.bv_len, kvno, keys); ++ if (!res) { ++ *err_msg = _("Failed to decode control reply!\n"); + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + +- *kvno = vno; + ret = LDAP_SUCCESS; + + done: +- if (ber) ber_free(ber, 1); + if (ld) ldap_unbind_ext(ld, NULL, NULL); + if (control) ber_bvfree(control); + free(es); +-- +2.1.0 + diff --git a/freeipa.spec b/freeipa.spec index 33950bd..6e0f115 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -25,7 +25,7 @@ Name: freeipa Version: %{VERSION} -Release: 1%{?dist} +Release: 2%{?dist} Summary: The Identity, Policy and Audit system Group: System Environment/Base @@ -34,6 +34,13 @@ URL: http://www.freeipa.org/ Source0: http://www.freeipa.org/downloads/src/freeipa-%{VERSION}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Patch01: 0001-Fix-named-working-directory-permissions.patch +Patch02: 0002-Show-warning-instead-of-error-if-CA-did-not-start.patch +Patch03: 0003-webui-fix-potential-XSS-vulnerabilities.patch +Patch04: 0004-Fix-filtering-of-enctypes-in-server-code.patch +Patch05: 0005-Add-asn1c-generated-code-for-keytab-controls.patch +Patch06: 0006-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch + %if ! %{ONLY_CLIENT} BuildRequires: 389-ds-base-devel >= 1.3.3.5 BuildRequires: svrcore-devel @@ -458,7 +465,6 @@ mkdir -p %{buildroot}%{_usr}/share/ipa/html/ /bin/touch %{buildroot}%{_usr}/share/ipa/html/preferences.html mkdir -p %{buildroot}%{_initrddir} mkdir %{buildroot}%{_sysconfdir}/sysconfig/ -mkdir -p %{buildroot}%{_localstatedir}/named/dyndb-ldap/ipa/ install -m 644 init/ipa_memcached.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa_memcached install -m 644 init/ipa-dnskeysyncd.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa-dnskeysyncd install -m 644 init/ipa-ods-exporter.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa-ods-exporter @@ -698,7 +704,6 @@ fi %config(noreplace) %{_sysconfdir}/sysconfig/ipa-ods-exporter %dir %attr(0700,apache,apache) %{_localstatedir}/run/ipa_memcached/ %dir %attr(0700,root,root) %{_localstatedir}/run/ipa/ -%dir %attr(0770,named,named) %{_localstatedir}/named/dyndb-ldap/ipa/ # NOTE: systemd specific section %{_tmpfilesdir}/%{name}.conf %attr(644,root,root) %{_unitdir}/ipa.service @@ -812,6 +817,7 @@ fi %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade %attr(755,root,root) %dir %{_localstatedir}/lib/ipa/pki-ca %ghost %{_localstatedir}/lib/ipa/pki-ca/publish +%ghost %{_localstatedir}/named/dyndb-ldap/ipa %attr(755,root,root) %{_libdir}/krb5/plugins/kdb/ipadb.so %{_mandir}/man1/ipa-replica-conncheck.1.gz %{_mandir}/man1/ipa-replica-install.1.gz @@ -931,6 +937,12 @@ fi %endif # ONLY_CLIENT %changelog +* Thu Nov 20 2014 Simo Sorce - 4.1.1-2 +- Patch blokers and feature freze exceptions +- Resolves: bz1165674 +- Resolves: bz1165856 (CVE-2014-7850) +- Fixes DNS install issue that prevents the server from working + * Thu Nov 06 2014 Petr Vobornik - 4.1.1-1 - Update to upstream 4.1.1 - see http://www.freeipa.org/page/Releases/4.1.1 - fix CVE-2014-7828