hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit dd820bc807337a36e40d0d7a67d8982ac91b556e
parent 6f3e0d3bdaeb318938cc5e05dfa40e3cad5b2db4
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Wed,  7 Feb 2024 19:53:30 +0100

asn1: add types and errors

Signed-off-by: Armin Preiml <apreiml@strohwolke.at>

Diffstat:
Aencoding/asn1/errors.ha | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aencoding/asn1/types.ha | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 204 insertions(+), 0 deletions(-)

diff --git a/encoding/asn1/errors.ha b/encoding/asn1/errors.ha @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use io; + +// Invalid DER encoding. +export type invalid = !void; + +// Unexpected data format. +export type badformat = !void; + +// Premature EOF +export type truncated = !void; + +// Data does not fit into the encoder buffer. +export type overflow = !void; + +type asn1error = !(invalid | badformat | overflow | truncated); + +// Any error within the asn1 module. +export type error = !(...io::error | ...asn1error); + + +// Converts an [[error]] into a user-friendly string. +export fn strerror(e: error) str = { + match (e) { + case invalid => + return "Data encoding does not follow the DER format"; + case badformat => + return "Unexpected data format"; + case truncated => + return "Premature EOF"; + case overflow => + return "Data does not fit into the encoder buffer"; + case let e: io::error => + return io::strerror(e); + }; +}; + +fn wrap_err(e: error) io::error = { + match (e) { + case let e: io::error => + return e; + case let e: asn1error => + static assert(size(asn1error) <= size(errors::opaque_data)); + let w = errors::opaque_ { strerror = &wrap_strerror, ... }; + let ptr = &w.data: *error; + *ptr = e; + return w; + }; +}; + +fn wrap_strerror(err: *errors::opaque_data) const str = { + let e = err: *error; + return strerror(*e); +}; + +// Unwrap [[io::error]] returned by readers into [[error]]. +export fn unwrap_err(e: io::error) error = { + match (e) { + case let e: errors::opaque_ => + let ptr = &e.data: *error; + return *ptr; + case let e: io::error => + return e; + }; +}; diff --git a/encoding/asn1/types.ha b/encoding/asn1/types.ha @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use errors; +use fmt; +use io; +use memio; + + +// Data types specified in the standard +export type class = enum u8 { + UNIVERSAL = 0x0, + APPLICATION = 0x1, + CONTEXT = 0x2, + PRIVATE = 0x3, +}; + +// String representation of 'c'. +export fn strclass(c: class) str = { + switch (c) { + case class::UNIVERSAL => + return "UNIVERSAL"; + case class::APPLICATION => + return "APPLICATION"; + case class::CONTEXT => + return "CONTEXT_SPECIFIC"; + case class::PRIVATE => + return "PRIVATE"; + }; +}; + +// Universal tags as defined in x.690. Not all are supported by this +// implemenation. +export type utag = enum u8 { + RESERVED = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BITSTRING = 0x03, + OCTET_STRING = 0x04, + NULL = 0x05, + OID = 0x06, + OBJECT_DESCRIPTOR = 0x07, + EXTERNAL = 0x08, + REAL = 0x09, + ENUMERATED = 0x0a, + EMBEDDED_PDV = 0x0b, + UTF8_STRING = 0x0c, + RELATIVE_OID = 0x0d, + TIME = 0x0e, + RESERVED2 = 0x0f, + SEQUENCE = 0x10, + SET = 0x11, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + TELETEX_STRING = 0x14, // T61String + VIDEOTEX_STRING = 0x15, + IA5_STRING = 0x16, + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + GRAPHIC_STRING = 0x19, + VISIBLE_STRING = 0x1a, // iso646String + GENERAL_STRING = 0x1b, + UNIVERSAL_STRING = 0x1c, + UNKNOWN = 0x1d, + BMP_STRING = 0x1e, + DATE = 0x1f, + TIME_OF_DAY = 0x20, + DATE_TIME = 0x21, + DURATION = 0x22, + OID_IRI = 0x23, + OID_RELATIVE_IRI = 0x24, +}; + +// String representation of universal tag ids. May return a statically allocated +// string and will be overwritten on the next call. +export fn strtag(dh: head) str = { + static let tagstrbuf: [128]u8 = [0...]; + + if (dh.class != class::UNIVERSAL) { + let tagstr = memio::fixed(tagstrbuf); + + fmt::fprint(&tagstr, "[")!; + if (dh.class != class::CONTEXT) { + fmt::fprintf(&tagstr, "{} ", strclass(dh.class))!; + }; + fmt::fprintf(&tagstr, "{:x}]", dh.tagid)!; + return memio::string(&tagstr)!; + }; + + if (dh.tagid >> 8 != 0) { + return "UNKNOWN"; + }; + + switch (dh.tagid: u8) { + case utag::BOOLEAN => + return "BOOLEAN"; + case utag::INTEGER => + return "INTEGER"; + case utag::BITSTRING => + return "BITSTRING"; + case utag::OCTET_STRING => + return "OCTET_STRING"; + case utag::NULL => + return "NULL"; + case utag::OID => + return "OBJECT_IDENTIFIER"; + case utag::OBJECT_DESCRIPTOR => + return "OBJECT_DESCRIPTOR"; + case utag::EXTERNAL => + return "EXTERNAL"; + case utag::REAL => + return "REAL"; + case utag::ENUMERATED => + return "ENUMERATED"; + case utag::EMBEDDED_PDV => + return "EMBEDDED_PDV"; + case utag::UTF8_STRING => + return "UTF8_STRING"; + case utag::RELATIVE_OID => + return "RELATIVE_OID"; + case utag::TIME => + return "TIME"; + case utag::SEQUENCE => + return "SEQUENCE"; + case utag::SET => + return "SET"; + case utag::PRINTABLE_STRING => + return "PRINTABLE_STRING"; + case utag::TELETEX_STRING => + return "TELETEX_STRING"; + case utag::UTC_TIME => + return "UTC_TIME"; + case => + return "UNKNOWN"; + }; +};