poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[COMMITTED] pickles: new pickle asn1-ber.pk


From: Jose E. Marchesi
Subject: [COMMITTED] pickles: new pickle asn1-ber.pk
Date: Thu, 23 Dec 2021 20:06:45 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

This commit adds a pickle to manipulate ASN-1 data encoded using the
Basic Encoding Rules as specified by the standard ISO/IEC
8825-1:2003.

At the moment it includes support for the generic encoding of data
values, in the type BER_Data_Value.  The interpretation of the value
contents as the different universal types (boolena, integer, etc) is
still to be done.

2021-12-23  Jose E. Marchesi  <jemarch@gnu.org>

        * pickles/asn1-ber.pk: New file.
        * pickles/Makefile.am (dist_pickles_DATA): Add asn1-ber.pk.
---
 ChangeLog           |   5 ++
 pickles/Makefile.am |   2 +-
 pickles/asn1-ber.pk | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 246 insertions(+), 1 deletion(-)
 create mode 100644 pickles/asn1-ber.pk

diff --git a/ChangeLog b/ChangeLog
index 7a2671f2..883ceb16 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2021-12-23  Jose E. Marchesi  <jemarch@gnu.org>
+
+       * pickles/asn1-ber.pk: New file.
+       * pickles/Makefile.am (dist_pickles_DATA): Add asn1-ber.pk.
+
 2021-12-23  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
 
        * libpoke/ios-dev-file.c (ios_dev_file_open): Add new param `data`.
diff --git a/pickles/Makefile.am b/pickles/Makefile.am
index 35191032..b2cfb27e 100644
--- a/pickles/Makefile.am
+++ b/pickles/Makefile.am
@@ -4,4 +4,4 @@ dist_pickles_DATA = elf-common.pk elf-64.pk elf-32.pk elf.pk 
ctf.pk ctf-dump.pk
                     color.pk rgb24.pk id3v1.pk \
                     dwarf.pk dwarf-common.pk dwarf-frame.pk dwarf-pubnames.pk \
                     dwarf-types.pk time.pk argp.pk pktest.pk mbr.pk ustar.pk \
-                    mcr.pk dwarf-expr.pk dwarf-info.pk id3v2.pk jffs2.pk
+                    mcr.pk dwarf-expr.pk dwarf-info.pk id3v2.pk jffs2.pk 
asn1-ber.pk
diff --git a/pickles/asn1-ber.pk b/pickles/asn1-ber.pk
new file mode 100644
index 00000000..c4f29e61
--- /dev/null
+++ b/pickles/asn1-ber.pk
@@ -0,0 +1,240 @@
+/* asn1-ber.pk - ASN-1 Basic Encoding Rules.  */
+
+/* Copyright (C) 2021 Jose E. Marchesi.  */
+
+/* This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file implements the BER encoding of ASN-1 as specified by the
+   standard ISO/IEC 8825-1:2003.  */
+
+/* The following variables define the set of universal tag numbers for
+   ASN-1 types.  Note that I didn't find these in the standard, but in
+   https://www.obj-sys.com/asn1tutorial/node124.html */
+
+var BER_TAG_RESERVED = 0,
+    BER_TAG_BOOLEAN = 1,
+    BER_TAG_INTEGER = 2,
+    BER_TAG_BIT_STRING = 3,
+    BER_TAG_OCTET_STRING = 4,
+    BER_TAG_NULL = 5,
+    BER_TAG_OBJ_IDENTIFIER = 6,
+    BER_TAG_OBJ_DESCRIPTOR = 7,
+    BER_TAG_INSTANCE = 8,
+    BER_TAG_REAL = 9,
+    BER_TAG_ENUMERATED = 10,
+    BER_TAG_EMBEDDED_PDV = 11,
+    BER_TAG_UTF8_STRING = 12,
+    BER_TAG_RELATIVE_OID = 13,
+    BER_TAG_SEQUENCE = 16,
+    BER_TAG_SET = 17,
+    BER_TAG_NUMERIC_STRING = 18,
+    BER_TAG_PRINTABLE_STRING = 19,
+    BER_TAG_TELETEX_STRING = 20,
+    BER_TAG_VIDEOTEX_STRING = 21,
+    BER_TAG_IA5_STRING = 22,
+    BER_TAG_UTC_TIME = 23,
+    BER_TAG_GENERALIZED_TIME = 24,
+    BER_TAG_GRAPHIC_STRING = 25,
+    BER_TAG_VISIBLE_STRING = 26,
+    BER_TAG_GENERAL_STRING = 27,
+    BER_TAG_UNIVERSAL_STRING = 28,
+    BER_TAG_CHARACTER_STRING = 29,
+    BER_TAG_BMP_STRING = 30;
+
+var ber_tag_name = [
+  "RESERVED", "boolean", "integer", "bit string", "octet string",
+  "null", "object identifier", "object descriptor", "instance",
+  "real", "enumerated", "embedded pdv", "utf8 string", "relative oid",
+  "N/A", "N/A", "sequence", "set", "numeric string", "printable string",
+  "teletex string", "videotex string", "IA5 string", "UTC time",
+  "generalized time", "graphic string", "visible string", "general string",
+  "universal string", "character string", "BMP string",
+];
+
+assert (ber_tag_name'length == 31,
+        "invalid ber_tag_name table");
+
+/* There are several namespaces for tag numbers: universal,
+   application, context specific and private.  */
+
+var BER_TAG_CLASS_UNIVERSAL = 0b00,
+    BER_TAG_CLASS_APPLICATION = 0b10,
+    BER_TAG_CLASS_CTXT_SPECIFIC = 0b10,
+    BER_TAG_CLASS_PRIVATE = 0b11;
+
+var ber_tag_class_name = [
+  "universal", "application", "ctxt-specific", "private"
+];
+
+/* A tag value may use either a `primitive' or a `constructed'
+   encoding. */
+
+var BER_ENCODING_PRIMITIVE = 0b0,
+    BER_ENCODING_CONSTRUCTED = 0b1;
+
+/* The "identifier octects", as they are called in the spec, act as a
+   sort of a header for BER data value.  It specifies the class,
+   encoding and number of a tag.  */
+
+type BER_Identifier =
+  struct
+  {
+    uint<2> tag_class;
+    uint<1> encoding;
+    uint<5> tag_number;
+
+    type Additional_Octet =
+      struct
+      {
+        uint<1> s = 1;
+        uint<7> rest;
+      };
+
+    Additional_Octet[] octects if tag_number == 0b11111;
+
+    method get_tag_number = uint<64>:
+    {
+      if (tag_number < 0b1111)
+       return tag_number;
+      else
+      {
+        var number = 0;
+        for (o in octects)
+          number += o.rest;
+        return number;
+      }
+    }
+
+    method _print = void:
+    {
+      printf ("#<class=%s,number=%u64d,encoding=%s>"
+              ber_tag_class_name[tag_class],
+              get_tag_number,
+              (encoding == BER_ENCODING_PRIMITIVE
+               ? "primitive" : "constructed"));
+    }
+  };
+
+/* BER uses two ways to specify the length of the data in a data value
+   (when it is definite).  A short form which is of fixed length (a
+   byte) and a long form that is of variable length.  */
+
+type BER_Length =
+  union
+  {
+    offset<byte,B> short_form : short_form'magnitude < 0b1000_0000;
+
+    struct
+    {
+      uint<1> first : first == 1;
+      uint<7> len;
+      byte[len] octects;
+    } long_form : long_form.first:::long_form.len != 0b1111_1111;
+
+    method get = offset<uint<64>,B>:
+    {
+      try return short_form;
+      catch if E_elem
+      {
+        var shift = 0;
+        var l = 0UL;
+
+        for (o in long_form.octects)
+          {
+            l += l | (o & 0x7f) <<. shift;
+            shift += 7;
+          }
+
+        return l#B;
+      }
+    }
+  };
+
+/* When the length of the contents of a BER data value is indefinite
+   (not explicitly specified) we shall read bytes until we find an end
+   marker that consists on two consecutive 0 bytes.
+
+   The `get_bytes' method returns an array of the bytes conforming the
+   contents.
+
+   If needed, data'offset and data'size can be used to demarcate the
+   contents as well.  */
+
+type BER_Variable_Contents =
+  struct
+  {
+    type Datum =
+      union
+      {
+        byte[2] pair : pair[1] != 0UB;
+        byte single : single != 0UB;
+      };
+
+    Datum[] data;
+    byte[2] end : end == [0UB,0UB];
+
+    method get_bytes = byte[]:
+    {
+      var bytes = byte[]();
+      for (d in data)
+        try bytes += d.pair;
+        catch if E_elem { bytes += [d.single]; }
+      return bytes;
+    }
+  };
+
+/* Each BER data value encodes an identifier or header, followed by
+   the lenght of the contents and the bytes conforming the contents.
+   The interpretation of these contents depends on the type of data
+   value, i.e. on the tag number.  */
+
+type BER_Data_Value =
+  struct
+  {
+    BER_Identifier identifier;
+    union
+    {
+      BER_Length definite
+        : identifier.encoding == BER_ENCODING_PRIMITIVE;
+      byte indefinite : indefinite == 0b1000_0000;
+
+      method is_indefinite = int:
+      {
+        try return indefinite || 1;
+        catch if E_elem { return 0; }
+      }
+
+      method get = offset<uint<64>,B>:
+      {
+        return is_indefinite ? 0UL#B : definite.get;
+      }
+    } length;
+
+    union
+    {
+      BER_Variable_Contents variable : !length.is_indefinite;
+      byte[length.get] fixed;
+    } contents;
+
+    method _print = void:
+    {
+      print "#<";
+      if (length.is_indefinite)
+        print "length=indefinite";
+      else
+        printf "length=%v", length.get;
+      print ">";
+    }
+  };
-- 
2.11.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]