Documentation
¶
Overview ¶
Package asn1 implements encoding and decoding of ASN.1 data structures using both Basic Encoding Rules (BER) or its subset, the Distinguished Encoding Rules (BER).
This package is highly inspired by the Go standard package "encoding/asn1" while supporting additional features such as BER encoding and decoding and ASN.1 CHOICE types.
By default and for convenience the package uses DER for encoding and BER for decoding. However it's possible to use a Context object to set the desired encoding and decoding rules as well other options.
Restrictions:
- BER allows STRING types, such as OCTET STRING and BIT STRING, to be encoded as constructed types containing inner elements that should be concatenated to form the complete string. The package does not support that, but in the future decoding of constructed strings should be included.
Example ¶
package main import ( "log" "reflect" "github.com/PromonLogicalis/asn1" ) func main() { ctx := asn1.NewContext() // Use BER for encoding and decoding. ctx.SetDer(false, false) // Add a CHOICE ctx.AddChoice("value", []asn1.Choice{ { Type: reflect.TypeOf(""), Options: "tag:0", }, { Type: reflect.TypeOf(int(0)), Options: "tag:1", }, }) type Message struct { Id int Value interface{} `asn1:"choice:value"` } // Encode msg := Message{ Id: 1000, Value: "this is a value", } data, err := ctx.Encode(msg) if err != nil { log.Fatal(err) } // Decode decodedMsg := Message{} _, err = ctx.Decode(data, &decodedMsg) if err != nil { log.Fatal(err) } log.Printf("%+v\n", decodedMsg) }
Output:
Index ¶
- func Decode(data []byte, obj interface{}) (rest []byte, err error)
- func DecodeWithOptions(data []byte, obj interface{}, options string) (rest []byte, err error)
- func Encode(obj interface{}) (data []byte, err error)
- func EncodeWithOptions(obj interface{}, options string) (data []byte, err error)
- type Choice
- type Context
- func (ctx *Context) AddChoice(choice string, entries []Choice) error
- func (ctx *Context) Decode(data []byte, obj interface{}) (rest []byte, err error)
- func (ctx *Context) DecodeWithOptions(data []byte, obj interface{}, options string) (rest []byte, err error)
- func (ctx *Context) Encode(obj interface{}) (data []byte, err error)
- func (ctx *Context) EncodeWithOptions(obj interface{}, options string) (data []byte, err error)
- func (ctx *Context) SetDer(encoding bool, decoding bool)
- func (ctx *Context) SetLogger(logger *log.Logger)
- type Null
- type Oid
- type ParseError
- type SyntaxError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Decode ¶
Decode parses the given BER data into obj. The argument obj should be a reference to the value that will hold the parsed data. Decode uses a default Context and is equivalent to:
rest, err := asn1.NewContext().Decode(data, &obj)
func DecodeWithOptions ¶
DecodeWithOptions parses the given BER data into obj using the additional options. The argument obj should be a reference to the value that will hold the parsed data. Decode uses a default Context and is equivalent to:
rest, err := asn1.NewContext().DecodeWithOptions(data, &obj, options)
func Encode ¶
Encode returns the DER encoding of obj. Encode uses a default Context and it's equivalent to:
data, err = asn1.NewContext().Encode(obj)
func EncodeWithOptions ¶
EncodeWithOptions returns the DER encoding of obj using additional options. EncodeWithOptions uses a default Context and it's equivalent to:
data, err = asn1.NewContext().EncodeWithOptions(obj, options)
Types ¶
type Context ¶
type Context struct {
// contains filtered or unexported fields
}
Context keeps options that affect the ASN.1 encoding and decoding
Use the NewContext() function to create a new Context instance:
ctx := ber.NewContext() // Set options, ex: ctx.SetDer(true, true) // And call decode or encode functions bytes, err := ctx.EncodeWithOptions(value, "explicit,application,tag:5") ...
func NewContext ¶
func NewContext() *Context
NewContext creates and initializes a new context. The returned Context does not contains any registered choice and it's set to DER encoding and BER decoding.
func (*Context) AddChoice ¶
AddChoice registers a list of types as options to a given choice.
The string choice refers to a choice name defined into an element via additional options for DecodeWithOptions and EncodeWithOptions of via struct tags.
For example, considering that a field "Value" can be an INTEGER or an OCTET STRING indicating two types of errors, each error with a different tag number, the following can be used:
// Error types type SimpleError string type ComplextError string // The main object type SomeSequence struct { // ... Value interface{} `asn1:"choice:value"` // ... } // A Context with the registered choices ctx := asn1.NewContext() ctx.AddChoice("value", []asn1.Choice { { Type: reflect.TypeOf(int(0)), }, { Type: reflect.TypeOf(SimpleError("")), Options: "tag:1", }, { Type: reflect.TypeOf(ComplextError("")), Options: "tag:2", }, })
Some important notes:
1. Any choice value must be an interface. During decoding the necessary type will be allocated to keep the parsed value.
2. The INTEGER type will be encoded using its default class and tag number and so it's not necessary to specify any Options for it.
3. The two error types in our example are encoded as strings, in order to make possible to differentiate both types during encoding they actually need to be different types. This is solved by defining two alias types: SimpleError and ComplextError.
4. Since both errors use the same encoding type, ASN.1 says they must have distinguished tags. For that, the appropriate tag is defined for each type.
To encode a choice value, all that is necessary is to set the choice field with the proper object. To decode a choice value, a type switch can be used to determine which type was used.
func (*Context) Decode ¶
Decode parses the given data into obj. The argument obj should be a reference to the value that will hold the parsed data.
See (*Context).DecodeWithOptions() for further details.
func (*Context) DecodeWithOptions ¶
func (ctx *Context) DecodeWithOptions(data []byte, obj interface{}, options string) (rest []byte, err error)
DecodeWithOptions parses the given data into obj using the additional options. The argument obj should be a reference to the value that will hold the parsed data.
It uses the reflect package to inspect obj and because of that only exported struct fields (those that start with a capital letter) are considered.
The Context object defines the decoding rules (BER or DER) and the types available for CHOICE types.
The asn1 package maps Go types to ASN.1 data structures. The package also provides types to specific ASN.1 data structures. The default mapping is shown in the table below:
Go type | ASN.1 universal tag -----------------------|-------------------- bool | BOOLEAN All int and uint types | INTEGER *big.Int | INTEGER string | OCTET STRING []byte | OCTET STRING asn1.Oid | OBJECT INDETIFIER asn1.Null | NULL Any array or slice | SEQUENCE OF Any struct | SEQUENCE
Arrays and slices are decoded using different rules. A slice is always appended while an array requires an exact number of elements, otherwise a ParseError is returned.
The default mapping can be changed using options provided in the argument options (for the root value) or via struct tags for struct fields. Struct tags use the namei space "asn1".
The available options for encoding and decoding are:
tag
This option requires an numeric argument (ie: "tag:1") and indicates that a element is encoded and decoded as a context specific element with the given tag number. The context specific class can be overridden with the options "application" or "universal".
universal
Sets the tag class to universal. Requires "tag".
application
Sets the tag class to application. Requires "tag".
explicit
Indicates the element is encoded with an enclosing tag. It's usually used in conjunction with "tag".
optional
Indicates that an element can be suppressed.
A missing element that is not marked with "optional" or "default" causes a ParseError to be returned during decoding. A missing element marked as optional is left untouched.
During encoding, a zero value elements is suppressed from output if it's marked as optional.
default
This option is handled similarly to the "optional" option but requires a numeric argument (ie: "default:1").
A missing element that is marked with "default" is set to the given default value during decoding.
A zero value marked with "default" is suppressed from output when encoding is set to DER or is encoded with the given default value when encoding is set to BER.
indefinite
This option is used only during encoding and causes a constructed element to be encoded using the indefinite form.
choice
Indicates that an element can be of one of several types as defined by (*Context).AddChoice()
set
Indicates that a struct, array or slice should be encoded and decoded as a SET instead of a SEQUENCE.
It also affects the way that structs are encoded and decoded in DER. A struct marked with "set" has its fields always encoded in the ascending order of its tags, instead of following the order that the fields are defined in the struct.
Similarly, a struct marked with "set" always enforces that same order when decoding in DER.
func (*Context) Encode ¶
Encode returns the ASN.1 encoding of obj.
See (*Context).EncodeWithOptions() for further details.
func (*Context) EncodeWithOptions ¶
EncodeWithOptions returns the ASN.1 encoding of obj using additional options.
See (*Context).DecodeWithOptions() for further details regarding types and options.
type Oid ¶
type Oid []uint
Oid is used to encode and decode ASN.1 OBJECT IDENTIFIERs.
type ParseError ¶
type ParseError struct {
Msg string
}
ParseError is returned by the package to indicate that the given data is invalid.
func (*ParseError) Error ¶
func (e *ParseError) Error() string
Error returns the error message of a ParseError.
type SyntaxError ¶
type SyntaxError struct {
Msg string
}
SyntaxError is returned by the package to indicate that the given value or struct is invalid.
func (*SyntaxError) Error ¶
func (e *SyntaxError) Error() string
Error returns the error message of a SyntaxError.