SnmpKit.SnmpLib.ASN1 (snmpkit v0.6.3)
Comprehensive ASN.1 BER (Basic Encoding Rules) encoding and decoding utilities.
Provides low-level ASN.1 operations that are used by the PDU module and can be used for other ASN.1 encoding/decoding needs. This module offers improved performance and better error handling compared to basic implementations.
Features
- Complete BER encoding/decoding support
- Optimized length handling for large values
- Comprehensive error reporting
- Support for constructed and primitive types
- Memory-efficient implementations
- Validation and constraint checking
- RFC-compliant OID multibyte encoding (values ≥ 128)
ASN.1 Types Supported
- INTEGER: Signed integers with arbitrary precision
- OCTET STRING: Binary data of any length
- NULL: Null value representation
- OBJECT IDENTIFIER: Hierarchical object identifiers with multibyte subidentifiers
- SEQUENCE: Constructed type for complex structures
- Custom Tags: Application-specific and context-specific tags
Important: OID Encoding
OID subidentifiers use 7-bit encoding where values ≥ 128 require multibyte encoding:
- Values 0-127: Single byte
- Values 128+: Multibyte with continuation bits
- Example: 200 →
[0x81, 0x48]
(not single byte0xC8
)
Examples
# Integer encoding/decoding
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_integer(42)
iex> {:ok, {value, <<>>}} = SnmpKit.SnmpLib.ASN1.decode_integer(encoded)
iex> value
42
# OCTET STRING encoding/decoding
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_octet_string("Hello")
iex> {:ok, {value, <<>>}} = SnmpKit.SnmpLib.ASN1.decode_octet_string(encoded)
iex> value
"Hello"
# OID encoding/decoding with multibyte values
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_oid([1, 3, 6, 1, 4, 1, 200])
iex> {:ok, {oid, <<>>}} = SnmpKit.SnmpLib.ASN1.decode_oid(encoded)
iex> oid
[1, 3, 6, 1, 4, 1, 200]
# Length encoding for large values
iex> encoded_length = SnmpKit.SnmpLib.ASN1.encode_length(1000)
iex> {:ok, {length, <<>>}} = SnmpKit.SnmpLib.ASN1.decode_length(encoded_length)
iex> length
1000
# NULL encoding
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_null()
iex> {:ok, {value, <<>>}} = SnmpKit.SnmpLib.ASN1.decode_null(encoded)
iex> value
:null
Summary
Functions
Calculates the total length of a BER-encoded structure.
Decodes an ASN.1 INTEGER value.
Decodes an ASN.1 length field.
Decodes an ASN.1 NULL value.
Decodes an ASN.1 OCTET STRING value.
Decodes an ASN.1 OBJECT IDENTIFIER value.
Decodes an ASN.1 SEQUENCE value.
Decodes a generic TLV structure.
Encodes a custom TLV (Tag-Length-Value) structure.
Encodes an ASN.1 INTEGER value using BER (Basic Encoding Rules).
Encodes an ASN.1 length field.
Encodes an ASN.1 NULL value.
Encodes an ASN.1 OCTET STRING value.
Encodes an ASN.1 OBJECT IDENTIFIER (OID) value using BER encoding.
Encodes an ASN.1 SEQUENCE with the given content.
Parses an ASN.1 tag byte.
Validates the structure of BER-encoded data.
Types
@type content() :: binary()
@type length() :: non_neg_integer()
@type oid() :: [non_neg_integer()]
@type tag() :: non_neg_integer()
Functions
@spec calculate_ber_length(binary()) :: {:ok, non_neg_integer()} | {:error, atom()}
Calculates the total length of a BER-encoded structure.
Parameters
data
: BER-encoded binary data
Returns
{:ok, total_length}
on success{:error, reason}
on failure
Examples
{:ok, 10} = SnmpKit.SnmpLib.ASN1.calculate_ber_length(ber_data)
Decodes an ASN.1 INTEGER value.
Parameters
data
: Binary data starting with an INTEGER TLV
Returns
{:ok, {value, remaining_data}}
on success{:error, reason}
on failure
Examples
{:ok, {42, remaining}} = SnmpKit.SnmpLib.ASN1.decode_integer(<<2, 1, 42, 99, 100>>)
# Returns {42, <<99, 100>>}
Decodes an ASN.1 length field.
Parameters
data
: Binary data starting with a length field
Returns
{:ok, {length, remaining_data}}
on success{:error, reason}
on failure
Examples
{:ok, {42, remaining}} = SnmpKit.SnmpLib.ASN1.decode_length(<<42, 1, 2, 3>>)
{:ok, {300, remaining}} = SnmpKit.SnmpLib.ASN1.decode_length(<<0x82, 1, 44, 1, 2, 3>>)
Decodes an ASN.1 NULL value.
Examples
{:ok, {:null, remaining}} = SnmpKit.SnmpLib.ASN1.decode_null(<<5, 0, 1, 2, 3>>)
# Returns {:null, <<1, 2, 3>>}
Decodes an ASN.1 OCTET STRING value.
Examples
{:ok, {"Hello", remaining}} = SnmpKit.SnmpLib.ASN1.decode_octet_string(encoded_data)
Decodes an ASN.1 OBJECT IDENTIFIER value.
Examples
{:ok, {[1, 3, 6, 1], remaining}} = SnmpKit.SnmpLib.ASN1.decode_oid(encoded_data)
Decodes an ASN.1 SEQUENCE value.
Returns the content of the sequence without further parsing.
Examples
{:ok, {sequence_content, remaining}} = SnmpKit.SnmpLib.ASN1.decode_sequence(encoded_data)
Decodes a generic TLV structure.
Parameters
data
: Binary data starting with a TLV
Returns
{:ok, {tag, content, remaining}}
on success{:error, reason}
on failure
Examples
{:ok, {tag, content, remaining}} = SnmpKit.SnmpLib.ASN1.decode_tlv(binary_data)
Encodes a custom TLV (Tag-Length-Value) structure.
Parameters
tag
: ASN.1 tag valuecontent
: Binary content
Examples
{:ok, tlv} = SnmpKit.SnmpLib.ASN1.encode_custom_tlv(0xA0, <<"custom_content">>)
Encodes an ASN.1 INTEGER value using BER (Basic Encoding Rules).
Supports arbitrary precision integers using two's complement representation. The encoded result includes the ASN.1 tag (0x02), length, and content bytes.
Parameters
value
: Integer value to encode (any size)
Returns
{:ok, encoded_bytes}
on success{:error, reason}
on failure
Examples
# Positive integers
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_integer(42)
iex> encoded
<<2, 1, 42>>
# Negative integers (two's complement)
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_integer(-1)
iex> encoded
<<2, 1, 255>>
# Zero
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_integer(0)
iex> encoded
<<2, 1, 0>>
# Large integers
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_integer(32767)
iex> byte_size(encoded) > 3
true
Encodes an ASN.1 length field.
Supports both short form (< 128) and long form encoding.
Parameters
length
: Length value to encode
Returns
- Binary representation of the length
Examples
<<42>> = SnmpKit.SnmpLib.ASN1.encode_length(42)
<<0x81, 200>> = SnmpKit.SnmpLib.ASN1.encode_length(200)
<<0x82, 1, 44>> = SnmpKit.SnmpLib.ASN1.encode_length(300)
@spec encode_null() :: {:ok, binary()}
Encodes an ASN.1 NULL value.
Examples
{:ok, <<5, 0>>} = SnmpKit.SnmpLib.ASN1.encode_null()
Encodes an ASN.1 OCTET STRING value.
Parameters
value
: Binary data to encode
Examples
{:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_octet_string("Hello")
{:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_octet_string(<<1, 2, 3, 4>>)
Encodes an ASN.1 OBJECT IDENTIFIER (OID) value using BER encoding.
OIDs are hierarchical identifiers where each component is encoded using 7-bit subidentifiers. Values ≥ 128 require multibyte encoding with continuation bits, which is correctly handled by this implementation.
Parameters
oid_list
: List of non-negative integers representing the OID (minimum 2 components)
Returns
{:ok, encoded_bytes}
on success{:error, reason}
on failure (invalid OID format)
Encoding Rules
- First two components are combined:
first * 40 + second
- Remaining components use 7-bit encoding with continuation bits
- Values 0-127: single byte
- Values 128+: multibyte with high bit indicating continuation
Examples
# Standard SNMP OID (sysDescr.0)
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_oid([1, 3, 6, 1, 2, 1, 1, 1, 0])
iex> {:ok, {decoded, <<>>}} = SnmpKit.SnmpLib.ASN1.decode_oid(encoded)
iex> decoded
[1, 3, 6, 1, 2, 1, 1, 1, 0]
# OID with multibyte values (≥ 128)
iex> {:ok, encoded} = SnmpKit.SnmpLib.ASN1.encode_oid([1, 3, 6, 1, 4, 1, 200])
iex> {:ok, {decoded, <<>>}} = SnmpKit.SnmpLib.ASN1.decode_oid(encoded)
iex> decoded
[1, 3, 6, 1, 4, 1, 200]
# Invalid OIDs
iex> SnmpKit.SnmpLib.ASN1.encode_oid([])
{:error, :invalid_oid}
iex> SnmpKit.SnmpLib.ASN1.encode_oid([1])
{:ok, <<6, 1, 1>>}
Encodes an ASN.1 SEQUENCE with the given content.
Parameters
content
: Pre-encoded content for the sequence
Examples
content = encode_integer_content(42) <> encode_octet_string_content("test")
{:ok, sequence} = SnmpKit.SnmpLib.ASN1.encode_sequence(content)
Parses an ASN.1 tag byte.
Returns information about the tag including class, constructed bit, and tag number.
Parameters
tag_byte
: Single byte representing the tag
Returns
- Map with tag information
Examples
info = SnmpKit.SnmpLib.ASN1.parse_tag(0x30)
# Returns %{class: :universal, constructed: true, tag_number: 16}
Validates the structure of BER-encoded data.
Performs basic validation without full decoding.
Parameters
data
: BER-encoded binary data
Returns
:ok
if structure is valid{:error, reason}
if structure is invalid
Examples
:ok = SnmpKit.SnmpLib.ASN1.validate_ber_structure(valid_ber_data)
{:error, :invalid_length} = SnmpKit.SnmpLib.ASN1.validate_ber_structure(malformed_data)