encoding::asn1
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 {
cons: bool,
class: class,
tagid: u32,
start: size,
data: size,
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, VIDEOTEX_STRING = 21,
IA5_STRING = 22,
UTC_TIME = 23,
GENERALIZED_TIME = 24,
GRAPHIC_STRING = 25,
VISIBLE_STRING = 26, 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,
};
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;
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);
fn t61_chardecode(in: []u8) (rune | insufficient | invalid);
Types
type class
type class = enum u8 {
UNIVERSAL = 0,
APPLICATION = 1,
CONTEXT = 2,
PRIVATE = 3,
};
Data types specified in the standard
type head
type head = struct {
cons: bool,
class: class,
tagid: u32,
start: size,
data: size,
end: size,
implicit: bool,
};
Each DER entry starts with an header that describes the content.
type oid
type oid = u32;
Numeric id of an oid which is unique within an oiddb.
type oiddb
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
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, VIDEOTEX_STRING = 21,
IA5_STRING = 22,
UTC_TIME = 23,
GENERALIZED_TIME = 24,
GRAPHIC_STRING = 25,
VISIBLE_STRING = 26, 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
type utf8stream = struct {
stream: io::stream,
d: *decoder,
strdec: *strdecoder,
};
An io::stream reader that returns only valid utf8 chunks on read.
type bytestream
Show undocumented member
type bytestream = struct {
stream: io::stream,
d: *decoder,
};
type bytewstream
Show undocumented member
type bytewstream = struct {
stream: io::stream,
e: *encoder,
};
type datasz
Show undocumented member
type datasz = u32;
type decoder
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
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
Show undocumented member
type strdecoder = fn(s: *utf8stream, buf: []u8) (size | io::EOF | io::error);
Errors
type badformat = !void;
Unexpected data format.
type error
type error = !(...io::error | ...asn1error);
Any error within the asn1 module.
type invalid
type invalid = !void;
Encountered invalid DER encoded data.
type overflow
type overflow = !void;
Data does not fit into the encoder buffer.
type truncated
type truncated = !void;
Premature EOF.
type insufficient
Show undocumented member
type insufficient = !void;
Constants
def MAXHEADSZ
def MAXHEADSZ = 1 + 5 + 1 + size(datasz);
The maximum header size possible for u32 tag ids.
def MAXUTAGHEADSZ
def MAXUTAGHEADSZ = 1 + 1 + size(datasz);
The maximum header size possible for entries of utag.
Functions
fn bitstr_isset
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
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
fn close_explicit(d: *decoder) (void | badformat);
Closes an EXPLICIT encoded field.
fn close_seq
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
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
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
fn create_seq(e: *encoder) (void | overflow);
Creates a sequence. The user must call finish_seq to close the associated DER entry.
fn derdecoder
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
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
fn derencoder_nested(b: *bytewstream) encoder;
Creates a DER encoder nested within another DER entry, using the buffer of the parent.
fn dsz
fn dsz(d: head) size;
Size of the encoded data.
fn encode
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
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
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
fn finish(d: *decoder) (void | error);
Verifies that the entire input to the decoder was read.
fn finish_explicit
fn finish_explicit(e: *encoder) void;
Finishes an explicit constructed entry.
fn finish_seq
fn finish_seq(e: *encoder) void;
Finishes a sequence.
fn octetstrreader
fn octetstrreader(d: *decoder) (bytestream | error);
Returns an io::reader for octet string data.
fn octetstrwriter
fn octetstrwriter(e: *encoder) (bytewstream | overflow);
Creates an io::writer that encodes data written to it as an OctetString.
fn oid_from_der
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
fn oid_to_der(db: *oiddb, o: oid) []u8;
Borrows the DER representation of a known oid from 'db'.
fn open_explicit
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
fn open_seq(d: *decoder) (void | error);
Opens a sequence. Call close_seq after reading.
fn open_set
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
fn peek(d: *decoder) (head | error);
Peeks the header of the next data field. Fails with badformat if no data follows.
fn read_bitstr
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
fn read_bool(d: *decoder) (bool | error);
Reads a boolean value.
fn read_gtime
fn read_gtime(d: *decoder) (date::date | error);
Reads a generalized datetime value.
fn read_int
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
fn read_null(d: *decoder) (void | error);
Reads a null entry.
fn read_octetstr
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
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
fn read_printstr(d: *decoder, buf: []u8) (size | error);
Reads a printable string into 'buf'.
fn read_rawoid
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
fn read_u16(d: *decoder) (u16 | error);
Reads an integer that is expected to fit into u16.
fn read_u32
fn read_u32(d: *decoder) (u32 | error);
Reads an integer that is expected to fit into u32.
fn read_u64
fn read_u64(d: *decoder) (u64 | error);
Reads an integer that is expected to fit into u64.
fn read_u8
fn read_u8(d: *decoder) (u8 | error);
Reads an integer that is expected to fit into u8.
fn read_uint
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
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
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
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
fn strclass(c: class) str;
String representation of 'c'.
fn strerror
fn strerror(e: error) str;
Converts an error into a user-friendly string.
fn stroid
fn stroid(db: *oiddb, o: oid) str;
Looks up a str representation of an oid from the database.
fn strrawoid
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
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
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
fn sz(d: head) size;
Size of current element (header size + data size)
fn trypeek
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
fn unwrap_err(e: io::error) error;
Unwraps an io::error returned by ASN.1 readers as an error.
fn write_bool
fn write_bool(e: *encoder, b: bool) (void | overflow);
Writes a boolean.
fn write_int
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
fn write_null(e: *encoder) (void | overflow);
Writes a null value.
fn write_oid
fn write_oid(e: *encoder, db: *oiddb, oid: oid) (void | overflow);
Writes given oid from the oiddb 'db'.
fn write_uint
fn write_uint(e: *encoder, n: []u8) (void | overflow);
Writes an integer asuming 'n' is unsigned.
fn write_utf8str
fn write_utf8str(e: *encoder, s: str) (void | overflow);
Writes 's' as Utf8String.
fn t61_chardecode
Show undocumented member
fn t61_chardecode(in: []u8) (rune | insufficient | invalid);