Skip to content

codello/go-asn1

Repository files navigation

ASN.1 Data Structures in Go

Go Reference Test Status

This package provides base types for implementing ASN.1 data structures as defined to Rec. ITU-T X.680 in Go. The goal of this package is not to provide a comprehensive implementation of all ASN.1 features but to provide a framework for modeling, encoding, and decoding ASN.1 data structures in Go. Encoding rules for data structures are implemented in the sub-packages of this module.

Modeling of ASN.1 Data Structures

The codello.dev/asn1 package defines rules for modeling ASN.1 data structures in Go. The details are described in the package documentation. The modeling approach takes inspiration from the encoding packages in the Go standard library by using standard Go types such as structs as base building blocks.

Consider the following data structure:

DEFINITIONS
IMPLICIT TAGS
BEGIN

MyType ::= SEQUENCE {
    Num                  INTEGER
    Str                  UTF8String   OPTIONAL
    Data [APPLICATION 5] OCTET STRING
    ...
}
END

This could be translated into the following Go type:

package main

import "codello.dev/asn1"

type MyType struct {
	Num  int
	Str  string `asn1:"optional"`
	Data []byte `asn1:"application,tag:5"`
	asn1.Extensible
}

Most of the standard Go types such as string, int, float64, or time.Time have defined counterparts in the package. Custom types can also be used, although you probably need to implement support for the encoding rules you need to support.

Encoding and Decoding of ASN.1 Data Structures

Encoding rules for ASN.1 data structures are implemented in the corresponding sub-packages. Currently, the following encoding rules are supported:

Encoding and decoding generally uses the reflect package and works similar to encoding packages in the standard library. Currently only the Basic Encoding Rules are implemented. You can encode or decode an ASN.1 type like this:

package main

import (
	"io"

	"codello.dev/asn1/ber"
)

var val *MyType // see example above

func main() {
	// decode from a byte slice
	var data []byte
	err := ber.Unmarshal(data, &val)

	// decode from an io.Reader
	var r io.Reader
	err = ber.NewDecoder(r).Decode(&val)

	// encode to a byte slice
	data, err = ber.Marshal(val)

	// encode into an io.Writer
	var w io.Writer
	err = ber.NewEncoder(w).Encode(val)
}

If you have a need to implement a custom encoding scheme for a type, you can implement the interfaces ber.BerEncoder, ber.BerDecoder, and ber.BerMatcher. For example if you wanted a custom struct type MyString to encode as if it were a string, you could do this as follows:

Example Implementation
package main

import (
	"io"
	"strings"

	"codello.dev/asn1"
	"codello.dev/asn1/ber"
)

type MyString struct {
	data string
	// other fields
}

// BerEncode defines how s is encoded using BER. It returns identification
// information of the element (its ber.Header) as well as an io.WriterTo.
// The io.WriterTo value will do the actual encoding of the value into bytes.
func (s *MyString) BerEncode() (ber.Header, io.WriterTo, error) {
	return ber.Header{
		Tag:    asn1.Tag{Class: asn1.ClassApplication, Number: 15},
		Length: len(s.data),
	}, strings.NewReader(s.data), nil
}

// BerMatch is used to implement ASN.1 OPTIONAL elements. It is called before
// BerDecode to find out, if an element with the specified tag could be decoded
// by s. If BerMatch is not implemented, a value matches any tag.
func (s *MyString) BerMatch(tag asn1.Tag) bool {
	return tag == asn1.Tag{Class: asn1.ClassApplication, Number: 15}
}

// BerDecode decodes a data stream from r into s. The ber.ElementReader type
// provides various methods to simplify reading primitive or constructed
// types. For constructed types a common strategy is to wrap it in a
// ber.Decoder to do recursive decoding.
func (s *MyString) BerDecode(_ asn1.Tag, r ber.ElementReader) error {
	// you
	buf := strings.Builder{}
	_, err := io.Copy(&buf, r)
	s.data = buf.String()
	return err
}

Contributing

If you encounter a bug or are missing a feature, please do open an issue.

Pull requests are also very welcome, for example to add support for additional encoding rules or ASN.1 features.

About

Go package for modeling ASN.1 Data Structures.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages