encoding::asn1+x86_64 +linux

This module provides functions to decode and encode the distinguished encoding rules (DER) format as defined in the X.690 ITU-T standard.

See derencoder and derdecoder for how to encode or decode values.

This module also provides tools to work with oids. See oiddb for more info.

Submodules

Index

Types

type class = enum u8 {
	UNIVERSAL = 0,
	APPLICATION = 1,
	CONTEXT = 2,
	PRIVATE = 3,
};
type head = struct {
	// Tells whether the data is constructed and encapsulates multiple
	// other data fields; or primitive and the value follows.
	cons: bool,
	// Class info
	class: class,
	// Tag id of the data
	tagid: u32,
	// Start position in stream
	start: size,
	// Start position of data in stream
	data: size,
	// End position in stream
	end: size,
	implicit: bool,
};
type oid = u32;
type oiddb = struct {
	lut: []u8,
	index: []size,
	names: []str,
};
type utag = enum u8 {
	RESERVED = 0,
	BOOLEAN = 1,
	INTEGER = 2,
	BITSTRING = 3,
	OCTET_STRING = 4,
	NULL = 5,
	OID = 6,
	OBJECT_DESCRIPTOR = 7,
	EXTERNAL = 8,
	REAL = 9,
	ENUMERATED = 10,
	EMBEDDED_PDV = 11,
	UTF8_STRING = 12,
	RELATIVE_OID = 13,
	TIME = 14,
	RESERVED2 = 15,
	SEQUENCE = 16,
	SET = 17,
	NUMERIC_STRING = 18,
	PRINTABLE_STRING = 19,
	TELETEX_STRING = 20, // T61String
	VIDEOTEX_STRING = 21,
	IA5_STRING = 22,
	UTC_TIME = 23,
	GENERALIZED_TIME = 24,
	GRAPHIC_STRING = 25,
	VISIBLE_STRING = 26, // iso646String
	GENERAL_STRING = 27,
	UNIVERSAL_STRING = 28,
	UNKNOWN = 29,
	BMP_STRING = 30,
	DATE = 31,
	TIME_OF_DAY = 32,
	DATE_TIME = 33,
	DURATION = 34,
	OID_IRI = 35,
	OID_RELATIVE_IRI = 36,
};
type utf8stream = struct {
	stream: io::stream,
	d: *decoder,
	strdec: *strdecoder,
};

// Undocumented types:
type bytestream = struct {
	stream: io::stream,
	d: *decoder,
};
type bytewstream = struct {
	stream: io::stream,
	e: *encoder,
};
type datasz = u32;
type decoder = struct {
	src: io::handle,
	pos: size,
	cstack: [MAX_CONS_DEPTH]head,
	cstackp: size,
	next: (void | head),
	cur: (void | head),
	unbuf: [3]u8,
	unbufn: u8,
	implicit: bool,
};
type encoder = struct {
	mem: *memio::stream,
	start: io::off,
	pos: size,
	bt: [MAX_CONS_DEPTH](size, datasz),
	btn: size,
	cur_dpos: size,
	cur_prim: bool,
	cur_fixed: bool,
	parent: nullable *bytewstream,
};
type strdecoder = fn(s: *utf8stream, buf: []u8) (size | io::EOF | io::error);

Errors

type badformat = !void;
type error = !(...io::error | ...asn1error);
type invalid = !void;
type overflow = !void;
type truncated = !void;

// Undocumented Errors:
type insufficient = !void;

Constants

def MAXHEADSZ = 1 + 5 + 1 + size(datasz);
def MAXUTAGHEADSZ = 1 + 1 + size(datasz);

Functions

fn bitstr_isset(bitstr: ([]u8, u8), pos: size) (bool | invalid);
fn bytereader(d: *decoder, c: class, tagid: u32) (bytestream | error);
fn close_explicit(d: *decoder) (void | badformat);
fn close_seq(d: *decoder) (void | badformat);
fn close_set(d: *decoder) (void | badformat);
fn create_explicit(e: *encoder, c: class, tag: u32) (void | overflow);
fn create_seq(e: *encoder) (void | overflow);
fn derdecoder(src: io::handle) decoder;
fn derencoder(mem: *memio::stream) encoder;
fn derencoder_nested(b: *bytewstream) encoder;
fn dsz(d: head) size;
fn encode(e: *encoder) ([]u8 | io::error);
fn encodeto(e: *encoder, dest: io::handle) (size | io::error);
fn expect_implicit(d: *decoder, c: class, tag: u32) (void | error);
fn finish(d: *decoder) (void | error);
fn finish_explicit(e: *encoder) void;
fn finish_seq(e: *encoder) void;
fn octetstrreader(d: *decoder) (bytestream | error);
fn octetstrwriter(e: *encoder) (bytewstream | overflow);
fn oid_from_der(db: *oiddb, raw: []u8) (void | oid);
fn oid_to_der(db: *oiddb, o: oid) []u8;
fn open_explicit(d: *decoder, c: class, tag: u32) (void | error);
fn open_seq(d: *decoder) (void | error);
fn open_set(d: *decoder) (void | error);
fn peek(d: *decoder) (head | error);
fn read_bitstr(d: *decoder, buf: []u8) (([]u8, u8) | error);
fn read_bool(d: *decoder) (bool | error);
fn read_gtime(d: *decoder) (date::date | error);
fn read_int(d: *decoder, buf: []u8) (size | error);
fn read_null(d: *decoder) (void | error);
fn read_octetstr(d: *decoder, buf: []u8) (size | error);
fn read_oid(d: *decoder, db: *oiddb) (oid | error);
fn read_printstr(d: *decoder, buf: []u8) (size | error);
fn read_rawoid(d: *decoder) ([]u8 | error);
fn read_u16(d: *decoder) (u16 | error);
fn read_u32(d: *decoder) (u32 | error);
fn read_u64(d: *decoder) (u64 | error);
fn read_u8(d: *decoder) (u8 | error);
fn read_uint(d: *decoder, buf: []u8) (size | error);
fn read_utctime(d: *decoder, maxyear: u16) (date::date | error);
fn read_utf8str(d: *decoder, buf: []u8) (str | error);
fn skip(d: *decoder, tag: utag, max: size) (size | error);
fn strclass(c: class) str;
fn strerror(e: error) str;
fn stroid(db: *oiddb, o: oid) str;
fn strrawoid(der: []u8) (str | io::error);
fn strreader(d: *decoder, t: utag) (utf8stream | error);
fn strtag(dh: head) str;
fn sz(d: head) size;
fn trypeek(d: *decoder) (head | error | io::EOF);
fn unwrap_err(e: io::error) error;
fn write_bool(e: *encoder, b: bool) (void | overflow);
fn write_int(e: *encoder, n: []u8) (void | overflow);
fn write_null(e: *encoder) (void | overflow);
fn write_oid(e: *encoder, db: *oiddb, oid: oid) (void | overflow);
fn write_uint(e: *encoder, n: []u8) (void | overflow);
fn write_utf8str(e: *encoder, s: str) (void | overflow);

// Undocumented functions:
fn t61_chardecode(in: []u8) (rune | insufficient | invalid);

Types

type class[link]

type class = enum u8 {
	UNIVERSAL = 0,
	APPLICATION = 1,
	CONTEXT = 2,
	PRIVATE = 3,
};

Data types specified in the standard

type head = struct {
	// Tells whether the data is constructed and encapsulates multiple
	// other data fields; or primitive and the value follows.
	cons: bool,
	// Class info
	class: class,
	// Tag id of the data
	tagid: u32,
	// Start position in stream
	start: size,
	// Start position of data in stream
	data: size,
	// End position in stream
	end: size,
	implicit: bool,
};

Each DER entry starts with an header that describes the content.

type oid[link]

type oid = u32;

Numeric id of an oid which is unique within an oiddb.

type oiddb[link]

type oiddb = struct {
	lut: []u8,
	index: []size,
	names: []str,
};

An oid database that contains a lookup table of known oids in the DER format. A database of oids required by the standard library can be found in encoding::asn1::stdoid.

The database can be used with oid_from_der and oid_to_der to convert an oid between integer and DER encoding. read_oid and write_oid can be used to decode or encode the oid directly from and to DER.

If the standard oid database is missing entries for the given use case, an individual database can be generated using the genoiddb command found in cmd/. Take a look at encoding/asn1/stdoid/db.txt for an example database file.

type utag[link]

type utag = enum u8 {
	RESERVED = 0,
	BOOLEAN = 1,
	INTEGER = 2,
	BITSTRING = 3,
	OCTET_STRING = 4,
	NULL = 5,
	OID = 6,
	OBJECT_DESCRIPTOR = 7,
	EXTERNAL = 8,
	REAL = 9,
	ENUMERATED = 10,
	EMBEDDED_PDV = 11,
	UTF8_STRING = 12,
	RELATIVE_OID = 13,
	TIME = 14,
	RESERVED2 = 15,
	SEQUENCE = 16,
	SET = 17,
	NUMERIC_STRING = 18,
	PRINTABLE_STRING = 19,
	TELETEX_STRING = 20, // T61String
	VIDEOTEX_STRING = 21,
	IA5_STRING = 22,
	UTC_TIME = 23,
	GENERALIZED_TIME = 24,
	GRAPHIC_STRING = 25,
	VISIBLE_STRING = 26, // iso646String
	GENERAL_STRING = 27,
	UNIVERSAL_STRING = 28,
	UNKNOWN = 29,
	BMP_STRING = 30,
	DATE = 31,
	TIME_OF_DAY = 32,
	DATE_TIME = 33,
	DURATION = 34,
	OID_IRI = 35,
	OID_RELATIVE_IRI = 36,
};

Universal tags as defined in x.690. Not all are supported by this implemenation.

type utf8stream[link]

type utf8stream = struct {
	stream: io::stream,
	d: *decoder,
	strdec: *strdecoder,
};

An io::stream reader that returns only valid utf8 chunks on read.

type bytestream[link]

Show undocumented member
type bytestream = struct {
	stream: io::stream,
	d: *decoder,
};

type bytewstream[link]

Show undocumented member
type bytewstream = struct {
	stream: io::stream,
	e: *encoder,
};

type datasz[link]

Show undocumented member
type datasz = u32;

type decoder[link]

Show undocumented member
type decoder = struct {
	src: io::handle,
	pos: size,
	cstack: [MAX_CONS_DEPTH]head,
	cstackp: size,
	next: (void | head),
	cur: (void | head),
	unbuf: [3]u8,
	unbufn: u8,
	implicit: bool,
};

type encoder[link]

Show undocumented member
type encoder = struct {
	mem: *memio::stream,
	start: io::off,
	pos: size,
	bt: [MAX_CONS_DEPTH](size, datasz),
	btn: size,
	cur_dpos: size,
	cur_prim: bool,
	cur_fixed: bool,
	parent: nullable *bytewstream,
};

type strdecoder[link]

Show undocumented member
type strdecoder = fn(s: *utf8stream, buf: []u8) (size | io::EOF | io::error);

Errors

type badformat[link]

type badformat = !void;

Unexpected data format.

type error[link]

type error = !(...io::error | ...asn1error);

Any error within the asn1 module.

type invalid[link]

type invalid = !void;

Encountered invalid DER encoded data.

type overflow[link]

type overflow = !void;

Data does not fit into the encoder buffer.

type truncated[link]

type truncated = !void;

Premature EOF.

type insufficient[link]

Show undocumented member
type insufficient = !void;

Constants

def MAXHEADSZ[link]

def MAXHEADSZ = 1 + 5 + 1 + size(datasz);

The maximum header size possible for u32 tag ids.

def MAXUTAGHEADSZ[link]

def MAXUTAGHEADSZ = 1 + 1 + size(datasz);

The maximum header size possible for entries of utag.

Functions

fn bitstr_isset[link]

fn bitstr_isset(bitstr: ([]u8, u8), pos: size) (bool | invalid);

Checks whether bit at 'pos' is set in given bitstring. 'pos' starts from 0, which is the highest order bit in the first byte.

fn bytereader[link]

fn bytereader(d: *decoder, c: class, tagid: u32) (bytestream | error);

Returns an io::reader that reads raw data (in its ASN.1 encoded form) from a decoder. Note that this reader will not perform any kind of validation.

fn close_explicit[link]

fn close_explicit(d: *decoder) (void | badformat);

Closes an EXPLICIT encoded field.

fn close_seq[link]

fn close_seq(d: *decoder) (void | badformat);

Closes the current sequence. If the caller has not read all of the data present in the encoded seqeunce, badformat is returned.

fn close_set[link]

fn close_set(d: *decoder) (void | badformat);

Closes the current set. If the caller has not read all of the data present in the encoded seqeunce, badformat is returned.

fn create_explicit[link]

fn create_explicit(e: *encoder, c: class, tag: u32) (void | overflow);

Creates an explicit constructed entry. The user must call finish_explicit to close the associated DER entry.

fn create_seq[link]

fn create_seq(e: *encoder) (void | overflow);

Creates a sequence. The user must call finish_seq to close the associated DER entry.

fn derdecoder[link]

fn derdecoder(src: io::handle) decoder;

Creates a new DER decoder that reads from 'src'. A buffered stream (see bufio::) is recommended for efficiency, as the decoder performs mostly short reads.

Each entry must be read in its entirety before the next one is attended to. The user must call finish when finished with the decoder to ensure that the entire input was read correctly.

fn derencoder[link]

fn derencoder(mem: *memio::stream) encoder;

Creates a new DER encoder. The user must provide a memio::stream for buffering data before it's encoded. The user may provide a dynamic or fixed stream at their discretion; fixed may be preferred if the user knows the required buffer size in advance.

To encode DER data, the user must call one of the "create_" functions (e.g. create_explicit), followed by the appropriate "write_" functions (e.g. write_int). These operations will be buffered into the provided memio buffer, and the encoded form may be finalized and retrieved via encode or encodeto.

To determine the required buffer size for a fixed buffer, consider the maximum length of the input data (e.g. integer, string, etc length) plus the necessary overhead, which is given by MAXUTAGHEADSZ if only using the provided encoder functions (e.g. "write_" functions), or MAXHEADSZ if using custom tag IDs.

The encoder does not close the provided memio::stream after use; the caller should manage its lifetime accordingly.

fn derencoder_nested[link]

fn derencoder_nested(b: *bytewstream) encoder;

Creates a DER encoder nested within another DER entry, using the buffer of the parent.

fn dsz[link]

fn dsz(d: head) size;

Size of the encoded data.

fn encode[link]

fn encode(e: *encoder) ([]u8 | io::error);

Encodes all buffered data in the encoder and returns a slice representing the encoded entry, borrowed from the encoder's buffer.

fn encodeto[link]

fn encodeto(e: *encoder, dest: io::handle) (size | io::error);

Encodes all buffered data in the encoder and writes it to the provided io::handle.

fn expect_implicit[link]

fn expect_implicit(d: *decoder, c: class, tag: u32) (void | error);

Expects an IMPLICIT defined data field having class 'c' and tag 'tag'. If the requirements are met, a read call (i.e. one of the "read_" or "reader" functions) must follow to read the actual data as stored.

fn finish[link]

fn finish(d: *decoder) (void | error);

Verifies that the entire input to the decoder was read.

fn finish_explicit[link]

fn finish_explicit(e: *encoder) void;

Finishes an explicit constructed entry.

fn finish_seq[link]

fn finish_seq(e: *encoder) void;

Finishes a sequence.

fn octetstrreader[link]

fn octetstrreader(d: *decoder) (bytestream | error);

Returns an io::reader for octet string data.

fn octetstrwriter[link]

fn octetstrwriter(e: *encoder) (bytewstream | overflow);

Creates an io::writer that encodes data written to it as an OctetString.

fn oid_from_der[link]

fn oid_from_der(db: *oiddb, raw: []u8) (void | oid);

Looks up DER encoded oid 'raw' in 'db' and returns an oid if found, or void otheriwse.

fn oid_to_der[link]

fn oid_to_der(db: *oiddb, o: oid) []u8;

Borrows the DER representation of a known oid from 'db'.

fn open_explicit[link]

fn open_explicit(d: *decoder, c: class, tag: u32) (void | error);

Opens an EXPLICIT encoded field of given class 'c' and 'tag'. The user must call close_explicit after containing data has been read.

fn open_seq[link]

fn open_seq(d: *decoder) (void | error);

Opens a sequence. Call close_seq after reading.

fn open_set[link]

fn open_set(d: *decoder) (void | error);

Opens a set. Note that sets must be ordered according to DER, but this module does not validate this constraint. Call close_set after reading.

fn peek[link]

fn peek(d: *decoder) (head | error);

Peeks the header of the next data field. Fails with badformat if no data follows.

fn read_bitstr[link]

fn read_bitstr(d: *decoder, buf: []u8) (([]u8, u8) | error);

Reads a bitstring value. The result tuple contains the bitstring and the number of unused bits in the last byte. The bitstr_isset function may be used to check for set bits.

fn read_bool[link]

fn read_bool(d: *decoder) (bool | error);

Reads a boolean value.

fn read_gtime[link]

fn read_gtime(d: *decoder) (date::date | error);

Reads a generalized datetime value.

fn read_int[link]

fn read_int(d: *decoder, buf: []u8) (size | error);

Reads an arbitrary-length integer into 'buf' and returns its length in bytes. Fails if the encoded integer size exceeds the buffer size. The integer is stored in big endian, and negative values are stored with two's compliment. The minimum integer size is one byte.

fn read_null[link]

fn read_null(d: *decoder) (void | error);

Reads a null entry.

fn read_octetstr[link]

fn read_octetstr(d: *decoder, buf: []u8) (size | error);

Read an octet string into 'buf', returning its length. Returns badformat if 'buf' is too small.

fn read_oid[link]

fn read_oid(d: *decoder, db: *oiddb) (oid | error);

Reads an oid if present in 'db'. Returns badformat if the oid is unknown.

fn read_printstr[link]

fn read_printstr(d: *decoder, buf: []u8) (size | error);

Reads a printable string into 'buf'.

fn read_rawoid[link]

fn read_rawoid(d: *decoder) ([]u8 | error);

Reads any oid and returns the DER encoded form. The returned value is borrowed from a static buffer.

fn read_u16[link]

fn read_u16(d: *decoder) (u16 | error);

Reads an integer that is expected to fit into u16.

fn read_u32[link]

fn read_u32(d: *decoder) (u32 | error);

Reads an integer that is expected to fit into u32.

fn read_u64[link]

fn read_u64(d: *decoder) (u64 | error);

Reads an integer that is expected to fit into u64.

fn read_u8[link]

fn read_u8(d: *decoder) (u8 | error);

Reads an integer that is expected to fit into u8.

fn read_uint[link]

fn read_uint(d: *decoder, buf: []u8) (size | error);

Similar to read_int, but returns badformat if the encoded value is signed. Discards the most significant zero bytes.

fn read_utctime[link]

fn read_utctime(d: *decoder, maxyear: u16) (date::date | error);

Reads an UTC time. Since the stored date only has a two digit year, 'maxyear' is required to define the epoch. For example 'maxyear' = 2046 causes all encoded years <= 46 to be after 2000 and all values > 46 will have 1900 as the century.

fn read_utf8str[link]

fn read_utf8str(d: *decoder, buf: []u8) (str | error);

Reads an utf8 string into 'buf' and returns a str that borrows from buf.

fn skip[link]

fn skip(d: *decoder, tag: utag, max: size) (size | error);

Skips an element and returns the size of the data that has been skipped. Returns an error if the skipped data is invalid.

Presently only supports BOOLEAN, INTEGER, NULL, OCTET_STRING, and BITSTRING utags, and will abort when attempting to skip anything else.

fn strclass[link]

fn strclass(c: class) str;

String representation of 'c'.

fn strerror[link]

fn strerror(e: error) str;

Converts an error into a user-friendly string.

fn stroid[link]

fn stroid(db: *oiddb, o: oid) str;

Looks up a str representation of an oid from the database.

fn strrawoid[link]

fn strrawoid(der: []u8) (str | io::error);

Returns the dot id as string. The caller must free returned value. This function may fail if the oid overflows the internal buffer, or an invalid value is provided.

fn strreader[link]

fn strreader(d: *decoder, t: utag) (utf8stream | error);

Returns an utf8stream for a supported utag 't', which is one of: * utag::NUMERIC_STRING * utag::PRINTABLE_STRING * utag::IA5_STRING * utag::UTF8_STRING * utag::TELETEX_STRING * utag::BMP_STRING * utag::UNIVERSAL_STRING

fn strtag[link]

fn strtag(dh: head) str;

String representation of universal tag ids. May return a statically allocated string and will be overwritten on the next call.

fn sz[link]

fn sz(d: head) size;

Size of current element (header size + data size)

fn trypeek[link]

fn trypeek(d: *decoder) (head | error | io::EOF);

Tries to peek the header of the next data field, or returns EOF if none exists.

fn unwrap_err[link]

fn unwrap_err(e: io::error) error;

Unwraps an io::error returned by ASN.1 readers as an error.

fn write_bool[link]

fn write_bool(e: *encoder, b: bool) (void | overflow);

Writes a boolean.

fn write_int[link]

fn write_int(e: *encoder, n: []u8) (void | overflow);

Writes an integer. 'n' must be stored in big endian order. The highest bit of the first byte marks the sign.

fn write_null[link]

fn write_null(e: *encoder) (void | overflow);

Writes a null value.

fn write_oid[link]

fn write_oid(e: *encoder, db: *oiddb, oid: oid) (void | overflow);

Writes given oid from the oiddb 'db'.

fn write_uint[link]

fn write_uint(e: *encoder, n: []u8) (void | overflow);

Writes an integer asuming 'n' is unsigned.

fn write_utf8str[link]

fn write_utf8str(e: *encoder, s: str) (void | overflow);

Writes 's' as Utf8String.

fn t61_chardecode[link]

Show undocumented member
fn t61_chardecode(in: []u8) (rune | insufficient | invalid);