diff --git a/.gitignore b/.gitignore index caeb661..4468511 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ /freeipa-4.0.3.tar.gz /freeipa-4.1.0.tar.gz /freeipa-4.1.1.tar.gz +/freeipa-4.1.2.tar.gz diff --git a/0001-Fix-named-working-directory-permissions.patch b/0001-Fix-named-working-directory-permissions.patch deleted file mode 100644 index 1908d15..0000000 --- a/0001-Fix-named-working-directory-permissions.patch +++ /dev/null @@ -1,176 +0,0 @@ -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 deleted file mode 100644 index 684b922..0000000 --- a/0002-Show-warning-instead-of-error-if-CA-did-not-start.patch +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index 7e98c47..0000000 --- a/0003-webui-fix-potential-XSS-vulnerabilities.patch +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index 369645f..0000000 --- a/0004-Fix-filtering-of-enctypes-in-server-code.patch +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index f0e19b6..0000000 --- a/0005-Add-asn1c-generated-code-for-keytab-controls.patch +++ /dev/null @@ -1,13109 +0,0 @@ -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 deleted file mode 100644 index 399b841..0000000 --- a/0006-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch +++ /dev/null @@ -1,812 +0,0 @@ -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 6e0f115..a85d39b 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -19,13 +19,13 @@ %global platform_module fedora %endif -%global VERSION 4.1.1 +%global VERSION 4.1.2 %define _hardened_build 1 Name: freeipa Version: %{VERSION} -Release: 2%{?dist} +Release: 1%{?dist} Summary: The Identity, Policy and Audit system Group: System Environment/Base @@ -34,13 +34,6 @@ 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 @@ -157,7 +150,7 @@ Requires: python-dns >= 1.11.1 Requires: zip Requires: policycoreutils >= 2.1.12-5 Requires: tar -Requires(pre): certmonger >= 0.75.13 +Requires(pre): certmonger >= 0.76.8 Requires(pre): 389-ds-base >= 1.3.3.5 Requires: fontawesome-fonts Requires: open-sans-fonts @@ -244,7 +237,7 @@ Requires: wget Requires: libcurl >= 7.21.7-2 Requires: xmlrpc-c >= 1.27.4 Requires: sssd >= 1.12.2 -Requires: certmonger >= 0.75.6 +Requires: certmonger >= 0.76.8 Requires: nss-tools Requires: bind-utils Requires: oddjob-mkhomedir @@ -294,7 +287,7 @@ Requires: gnupg Requires: iproute Requires: keyutils Requires: pyOpenSSL -Requires: python-nss >= 0.15 +Requires: python-nss >= 0.16 Requires: python-lxml Requires: python-netaddr Requires: libipa_hbac-python @@ -937,6 +930,10 @@ fi %endif # ONLY_CLIENT %changelog +* Tue Nov 25 2014 Petr Vobornik - 4.1.2-1 +- Update to upstream 4.1.2 - see http://www.freeipa.org/page/Releases/4.1.2 +- fix CVE-2014-7850 + * Thu Nov 20 2014 Simo Sorce - 4.1.1-2 - Patch blokers and feature freze exceptions - Resolves: bz1165674 diff --git a/sources b/sources index 3e42ab4..f6d97e6 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -6e1ec60f71aa17b65a2a3caadd688f3c freeipa-4.1.1.tar.gz +f40681838166b72a038380a7ad623dae freeipa-4.1.2.tar.gz