Documentation ¶
Overview ¶
Package cryptobyte implements building and parsing of byte strings for DER-encoded ASN.1 and TLS messages. See the examples for the Builder and String types to get started.
Index ¶
- type Builder
- func (b *Builder) AddASN1(tag Tag, f BuilderContinuation)
- func (b *Builder) AddASN1BigInt(n *big.Int)
- func (b *Builder) AddASN1BitString(s asn1.BitString)
- func (b *Builder) AddASN1Enum(v int64)
- func (b *Builder) AddASN1GeneralizedTime(t time.Time)
- func (b *Builder) AddASN1Int64(v int64)
- func (b *Builder) AddASN1OctetString(bytes []byte)
- func (b *Builder) AddASN1Uint64(v uint64)
- func (b *Builder) AddBytes(v []byte)
- func (b *Builder) AddUint16(v uint16)
- func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation)
- func (b *Builder) AddUint24(v uint32)
- func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation)
- func (b *Builder) AddUint32(v uint32)
- func (b *Builder) AddUint8(v uint8)
- func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation)
- func (b *Builder) AddValue(v MarshalingValue)
- func (b *Builder) Bytes() ([]byte, error)
- func (b *Builder) BytesOrPanic() []byte
- func (b *Builder) MarshalASN1(v interface{})
- type BuilderContinuation
- type MarshalingValue
- type String
- func (s *String) CopyBytes(out []byte) bool
- func (s String) Empty() bool
- func (s String) PeekASN1Tag(tag Tag) bool
- func (s *String) ReadASN1(out *String, tag Tag) bool
- func (s *String) ReadASN1BitString(out *asn1.BitString) bool
- func (s *String) ReadASN1Bytes(out *[]byte, tag Tag) bool
- func (s *String) ReadASN1Element(out *String, tag Tag) bool
- func (s *String) ReadASN1Enum(out *int) bool
- func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool
- func (s *String) ReadASN1Integer(out interface{}) bool
- func (s *String) ReadASN1ObjectIdentifier(out *asn1.ObjectIdentifier) bool
- func (s *String) ReadAnyASN1(out *String, outTag *Tag) bool
- func (s *String) ReadAnyASN1Element(out *String, outTag *Tag) bool
- func (s *String) ReadBytes(out *[]byte, n int) bool
- func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag Tag) bool
- func (s *String) ReadOptionalASN1Integer(out interface{}, tag Tag, defaultValue interface{}) bool
- func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag Tag) bool
- func (s *String) ReadUint16(out *uint16) bool
- func (s *String) ReadUint16LengthPrefixed(out *String) bool
- func (s *String) ReadUint24(out *uint32) bool
- func (s *String) ReadUint24LengthPrefixed(out *String) bool
- func (s *String) ReadUint32(out *uint32) bool
- func (s *String) ReadUint8(out *uint8) bool
- func (s *String) ReadUint8LengthPrefixed(out *String) bool
- func (s *String) Skip(n int) bool
- type Tag
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
A Builder builds byte strings from fixed-length and length-prefixed values. The zero value is a usable Builder that allocates space as needed.
Example (Asn1) ¶
package main import ( "encoding/asn1" "fmt" "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/cryptobyte" ) func main() { // This is an example of building ASN.1 data that looks like: // Foo ::= SEQUENCE { // version [6] INTEGER DEFAULT 0 // data OCTET STRING // } version := int64(2) data := []byte("hello") const defaultVersion = 0 var b cryptobyte.Builder b.AddASN1(cryptobyte.Tag(asn1.TagSequence).Constructed(), func(b *cryptobyte.Builder) { if version != defaultVersion { b.AddASN1(cryptobyte.Tag(6).Constructed().ContextSpecific(), func(b *cryptobyte.Builder) { b.AddASN1Int64(version) }) } b.AddASN1OctetString(data) }) result, err := b.Bytes() if err != nil { panic(err) } fmt.Printf("%x\n", result) }
Output: 300ca603020102040568656c6c6f
Example (LengthPrefixed) ¶
package main import ( "fmt" "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/cryptobyte" ) func main() { // This is an example of building length-prefixed data (as found in, // for example, TLS). Imagine a 16-bit prefixed series of 8-bit // prefixed strings. input := []string{"hello", "world"} var b cryptobyte.Builder b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { for _, value := range input { b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes([]byte(value)) }) } }) result, err := b.Bytes() if err != nil { panic(err) } fmt.Printf("%x\n", result) }
Output: 000c0568656c6c6f05776f726c64
func NewBuilder ¶
NewBuilder creates a Builder that appends its output to the given buffer. Like append(), the slice will be reallocated if its capacity is exceeded. Use Bytes to get the final buffer.
func NewFixedBuilder ¶
NewFixedBuilder creates a Builder that appends its output into the given buffer. This builder does not reallocate the output buffer. Writes that would exceed the buffer's capacity are treated as an error.
func (*Builder) AddASN1 ¶
func (b *Builder) AddASN1(tag Tag, f BuilderContinuation)
AddASN1 appends an ASN.1 object. The object is prefixed with the given tag. Tags greater than 30 are not supported and result in an error (i.e. low-tag-number form only). The child builder passed to the BuilderContinuation can be used to build the content of the ASN.1 object.
func (*Builder) AddASN1BigInt ¶
AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
func (*Builder) AddASN1BitString ¶
AddASN1BitString appends a DER-encoded ASN.1 BIT STRING.
func (*Builder) AddASN1Enum ¶
AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
func (*Builder) AddASN1GeneralizedTime ¶
AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
func (*Builder) AddASN1Int64 ¶
AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
func (*Builder) AddASN1OctetString ¶
AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
func (*Builder) AddASN1Uint64 ¶
AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
func (*Builder) AddUint16LengthPrefixed ¶
func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation)
AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
func (*Builder) AddUint24 ¶
AddUint24 appends a big-endian, 24-bit value to the byte string. The highest byte of the 32-bit input value is silently truncated.
func (*Builder) AddUint24LengthPrefixed ¶
func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation)
AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
func (*Builder) AddUint8LengthPrefixed ¶
func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation)
AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
func (*Builder) AddValue ¶
func (b *Builder) AddValue(v MarshalingValue)
AddValue calls Marshal on v, passing a pointer to the builder to append to. If Marshal returns an error, it is set on the Builder so that subsequent appends don't have an effect.
func (*Builder) Bytes ¶
Bytes returns the bytes written by the builder or an error if one has occurred during during building.
func (*Builder) BytesOrPanic ¶
BytesOrPanic returns the bytes written by the builder or panics if an error has occurred during building.
func (*Builder) MarshalASN1 ¶
func (b *Builder) MarshalASN1(v interface{})
MarshalASN1 calls asn1.Marshal on its input and appends the result if successful or records an error if one occurred.
type BuilderContinuation ¶
type BuilderContinuation func(child *Builder)
BuilderContinuation is continuation-passing interface for building length-prefixed byte sequences. Builder methods for length-prefixed sequences (AddUint8LengthPrefixed etc.) will invoke the BuilderContinuation supplied to them. The child builder passed to the continuation can be used to build the content of the length-prefixed sequence. Example:
parent := cryptobyte.NewBuilder() parent.AddUint8LengthPrefixed(func (child *Builder) { child.AddUint8(42) child.AddUint8LengthPrefixed(func (grandchild *Builder) { grandchild.AddUint8(5) }) })
It is an error to write more bytes to the child than allowed by the reserved length prefix. After the continuation returns, the child must be considered invalid, i.e. users must not store any copies or references of the child that outlive the continuation.
type MarshalingValue ¶
type MarshalingValue interface { // Marshal is called by Builder.AddValue. It receives a pointer to a builder // to marshal itself into. It may return an error that occurred during // marshaling, such as unset or invalid values. Marshal(b *Builder) error }
A MarshalingValue marshals itself into a Builder.
type String ¶
type String []byte
String represents a string of bytes. It provides methods for parsing fixed-length and length-prefixed values from it.
Example (Asn1) ¶
package main import ( "encoding/asn1" "fmt" "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/cryptobyte" ) func main() { // This is an example of parsing ASN.1 data that looks like: // Foo ::= SEQUENCE { // version [6] INTEGER DEFAULT 0 // data OCTET STRING // } input := cryptobyte.String([]byte{0x30, 12, 0xa6, 3, 2, 1, 2, 4, 5, 'h', 'e', 'l', 'l', 'o'}) var ( version int64 data, inner, versionBytes cryptobyte.String haveVersion bool ) if !input.ReadASN1(&inner, cryptobyte.Tag(asn1.TagSequence).Constructed()) || !input.Empty() || !inner.ReadOptionalASN1(&versionBytes, &haveVersion, cryptobyte.Tag(6).Constructed().ContextSpecific()) || (haveVersion && !versionBytes.ReadASN1Integer(&version)) || (haveVersion && !versionBytes.Empty()) || !inner.ReadASN1(&data, asn1.TagOctetString) || !inner.Empty() { panic("bad format") } fmt.Printf("haveVersion: %t, version: %d, data: %s\n", haveVersion, version, string(data)) }
Output: haveVersion: true, version: 2, data: hello
Example (LengthPrefixed) ¶
package main import ( "fmt" "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/cryptobyte" ) func main() { // This is an example of parsing length-prefixed data (as found in, for // example, TLS). Imagine a 16-bit prefixed series of 8-bit prefixed // strings. input := cryptobyte.String([]byte{0, 12, 5, 'h', 'e', 'l', 'l', 'o', 5, 'w', 'o', 'r', 'l', 'd'}) var result []string var values cryptobyte.String if !input.ReadUint16LengthPrefixed(&values) || !input.Empty() { panic("bad format") } for !values.Empty() { var value cryptobyte.String if !values.ReadUint8LengthPrefixed(&value) { panic("bad format") } result = append(result, string(value)) } fmt.Printf("%#v\n", result) }
Output: []string{"hello", "world"}
func (*String) CopyBytes ¶
CopyBytes copies len(out) bytes into out and advances over them. It returns true on success and false on error.
func (String) PeekASN1Tag ¶
PeekASN1Tag returns true if the next ASN.1 value on the string starts with the given tag.
func (*String) ReadASN1 ¶
ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including tag and length bytes) into out, and advances. The element must match the given tag. It returns true on success and false on error.
Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (*String) ReadASN1BitString ¶
ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It returns true on success and false on error.
func (*String) ReadASN1Bytes ¶
ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including tag and length bytes) into out, and advances. The element must match the given tag. It returns true on success and false on error.
func (*String) ReadASN1Element ¶
ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including tag and length bytes) into out, and advances. The element must match the given tag. It returns true on success and false on error.
Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (*String) ReadASN1Enum ¶
ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns true on success and false on error.
func (*String) ReadASN1GeneralizedTime ¶
ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and advances. It returns true on success and false on error.
func (*String) ReadASN1Integer ¶
ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does not point to an integer or to a big.Int, it panics. It returns true on success and false on error.
func (*String) ReadASN1ObjectIdentifier ¶
func (s *String) ReadASN1ObjectIdentifier(out *asn1.ObjectIdentifier) bool
ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and advances. It returns true on success and false on error.
func (*String) ReadAnyASN1 ¶
ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including tag and length bytes) into out, sets outTag to its tag, and advances. It returns true on success and false on error.
Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (*String) ReadAnyASN1Element ¶
ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element (including tag and length bytes) into out, sets outTag to is tag, and advances. It returns true on success and false on error.
Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (*String) ReadBytes ¶
ReadBytes reads n bytes into out and advances over them. It returns true on success and false and error.
func (*String) ReadOptionalASN1 ¶
ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.Element (not including tag and length bytes) tagged with the given tag into out. It stores whether an element with the tag was found in outPresent, unless outPresent is nil. It returns true on success and false on error.
func (*String) ReadOptionalASN1Integer ¶
ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER explicitly tagged with tag into out and advances. If no element with a matching tag is present, it writes defaultValue into out instead. If out does not point to an integer or to a big.Int, it panics. It returns true on success and false on error.
func (*String) ReadOptionalASN1OctetString ¶
ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING explicitly tagged with tag into out and advances. If no element with a matching tag is present, it writes defaultValue into out instead. It returns true on success and false on error.
func (*String) ReadUint16 ¶
ReadUint16 decodes a big-endian, 16-bit value into out and advances over it. It returns true on success and false on error.
func (*String) ReadUint16LengthPrefixed ¶
ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit length-prefixed value into out and advances over it. It returns true on success and false on error.
func (*String) ReadUint24 ¶
ReadUint24 decodes a big-endian, 24-bit value into out and advances over it. It returns true on success and false on error.
func (*String) ReadUint24LengthPrefixed ¶
ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit length-prefixed value into out and advances over it. It returns true on success and false on error.
func (*String) ReadUint32 ¶
ReadUint32 decodes a big-endian, 32-bit value into out and advances over it. It returns true on success and false on error.
func (*String) ReadUint8 ¶
ReadUint8 decodes an 8-bit value into out and advances over it. It returns true on success and false on error.
func (*String) ReadUint8LengthPrefixed ¶
ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value into out and advances over it. It returns true on success and false on error.
type Tag ¶
type Tag uint8
Tag represents an ASN.1 tag number and class (together also referred to as identifier octets). Methods in this package only support the low-tag-number form, i.e. a single identifier octet with bits 7-8 encoding the class and bits 1-6 encoding the tag number.
func (Tag) Constructed ¶
Contructed returns t with the constructed class bit set.
func (Tag) ContextSpecific ¶
Contructed returns t with the context-specific class bit set.