pax_global_header00006660000000000000000000000064142231622670014517gustar00rootroot0000000000000052 comment=71130c8caa28c7b6a8f66a46934ca6d8268d7762 asn1-ber-1.5.4/000077500000000000000000000000001422316226700131365ustar00rootroot00000000000000asn1-ber-1.5.4/.github/000077500000000000000000000000001422316226700144765ustar00rootroot00000000000000asn1-ber-1.5.4/.github/workflows/000077500000000000000000000000001422316226700165335ustar00rootroot00000000000000asn1-ber-1.5.4/.github/workflows/pr.yml000066400000000000000000000016371422316226700177060ustar00rootroot00000000000000name: PR on: pull_request: branches: [ master ] jobs: gomod: runs-on: ubuntu-latest strategy: matrix: go: [ '1.18', '1.17', '1.16', '1.15', '1.14', '1.13', ] name: Go ${{ matrix.go }}.x PR Validate steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go }} - name: Version run: go version - name: Build and Validate run: | go vet . go test . go test -cover -race -cpu 1,2,4 . go build . lint: name: Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: golangci-lint uses: golangci/golangci-lint-action@v2 with: version: v1.45 only-new-issues: true asn1-ber-1.5.4/LICENSE000066400000000000000000000022071422316226700141440ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com) Portions copyright (c) 2015-2016 go-asn1-ber Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. asn1-ber-1.5.4/README.md000066400000000000000000000014471422316226700144230ustar00rootroot00000000000000[![GoDoc](https://godoc.org/gopkg.in/asn1-ber.v1?status.svg)](https://godoc.org/gopkg.in/asn1-ber.v1) [![Build Status](https://travis-ci.org/go-asn1-ber/asn1-ber.svg)](https://travis-ci.org/go-asn1-ber/asn1-ber) ASN1 BER Encoding / Decoding Library for the GO programming language. --------------------------------------------------------------------- Required libraries: None Working: Very basic encoding / decoding needed for LDAP protocol Tests Implemented: A few TODO: Fix all encoding / decoding to conform to ASN1 BER spec Implement Tests / Benchmarks --- The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) The design is licensed under the Creative Commons 3.0 Attributions license. Read this article for more details: http://blog.golang.org/gopher asn1-ber-1.5.4/ber.go000066400000000000000000000346371422316226700142520ustar00rootroot00000000000000package ber import ( "bytes" "errors" "fmt" "io" "math" "os" "reflect" "time" "unicode/utf8" ) // MaxPacketLengthBytes specifies the maximum allowed packet size when calling ReadPacket or DecodePacket. Set to 0 for // no limit. var MaxPacketLengthBytes int64 = math.MaxInt32 type Packet struct { Identifier Value interface{} ByteValue []byte Data *bytes.Buffer Children []*Packet Description string } type Identifier struct { ClassType Class TagType Type Tag Tag } type Tag uint64 const ( TagEOC Tag = 0x00 TagBoolean Tag = 0x01 TagInteger Tag = 0x02 TagBitString Tag = 0x03 TagOctetString Tag = 0x04 TagNULL Tag = 0x05 TagObjectIdentifier Tag = 0x06 TagObjectDescriptor Tag = 0x07 TagExternal Tag = 0x08 TagRealFloat Tag = 0x09 TagEnumerated Tag = 0x0a TagEmbeddedPDV Tag = 0x0b TagUTF8String Tag = 0x0c TagRelativeOID Tag = 0x0d TagSequence Tag = 0x10 TagSet Tag = 0x11 TagNumericString Tag = 0x12 TagPrintableString Tag = 0x13 TagT61String Tag = 0x14 TagVideotexString Tag = 0x15 TagIA5String Tag = 0x16 TagUTCTime Tag = 0x17 TagGeneralizedTime Tag = 0x18 TagGraphicString Tag = 0x19 TagVisibleString Tag = 0x1a TagGeneralString Tag = 0x1b TagUniversalString Tag = 0x1c TagCharacterString Tag = 0x1d TagBMPString Tag = 0x1e TagBitmask Tag = 0x1f // xxx11111b // HighTag indicates the start of a high-tag byte sequence HighTag Tag = 0x1f // xxx11111b // HighTagContinueBitmask indicates the high-tag byte sequence should continue HighTagContinueBitmask Tag = 0x80 // 10000000b // HighTagValueBitmask obtains the tag value from a high-tag byte sequence byte HighTagValueBitmask Tag = 0x7f // 01111111b ) const ( // LengthLongFormBitmask is the mask to apply to the length byte to see if a long-form byte sequence is used LengthLongFormBitmask = 0x80 // LengthValueBitmask is the mask to apply to the length byte to get the number of bytes in the long-form byte sequence LengthValueBitmask = 0x7f // LengthIndefinite is returned from readLength to indicate an indefinite length LengthIndefinite = -1 ) var tagMap = map[Tag]string{ TagEOC: "EOC (End-of-Content)", TagBoolean: "Boolean", TagInteger: "Integer", TagBitString: "Bit String", TagOctetString: "Octet String", TagNULL: "NULL", TagObjectIdentifier: "Object Identifier", TagObjectDescriptor: "Object Descriptor", TagExternal: "External", TagRealFloat: "Real (float)", TagEnumerated: "Enumerated", TagEmbeddedPDV: "Embedded PDV", TagUTF8String: "UTF8 String", TagRelativeOID: "Relative-OID", TagSequence: "Sequence and Sequence of", TagSet: "Set and Set OF", TagNumericString: "Numeric String", TagPrintableString: "Printable String", TagT61String: "T61 String", TagVideotexString: "Videotex String", TagIA5String: "IA5 String", TagUTCTime: "UTC Time", TagGeneralizedTime: "Generalized Time", TagGraphicString: "Graphic String", TagVisibleString: "Visible String", TagGeneralString: "General String", TagUniversalString: "Universal String", TagCharacterString: "Character String", TagBMPString: "BMP String", } type Class uint8 const ( ClassUniversal Class = 0 // 00xxxxxxb ClassApplication Class = 64 // 01xxxxxxb ClassContext Class = 128 // 10xxxxxxb ClassPrivate Class = 192 // 11xxxxxxb ClassBitmask Class = 192 // 11xxxxxxb ) var ClassMap = map[Class]string{ ClassUniversal: "Universal", ClassApplication: "Application", ClassContext: "Context", ClassPrivate: "Private", } type Type uint8 const ( TypePrimitive Type = 0 // xx0xxxxxb TypeConstructed Type = 32 // xx1xxxxxb TypeBitmask Type = 32 // xx1xxxxxb ) var TypeMap = map[Type]string{ TypePrimitive: "Primitive", TypeConstructed: "Constructed", } var Debug = false func PrintBytes(out io.Writer, buf []byte, indent string) { dataLines := make([]string, (len(buf)/30)+1) numLines := make([]string, (len(buf)/30)+1) for i, b := range buf { dataLines[i/30] += fmt.Sprintf("%02x ", b) numLines[i/30] += fmt.Sprintf("%02d ", (i+1)%100) } for i := 0; i < len(dataLines); i++ { _, _ = out.Write([]byte(indent + dataLines[i] + "\n")) _, _ = out.Write([]byte(indent + numLines[i] + "\n\n")) } } func WritePacket(out io.Writer, p *Packet) { printPacket(out, p, 0, false) } func PrintPacket(p *Packet) { printPacket(os.Stdout, p, 0, false) } func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) { indentStr := "" for len(indentStr) != indent { indentStr += " " } classStr := ClassMap[p.ClassType] tagTypeStr := TypeMap[p.TagType] tagStr := fmt.Sprintf("0x%02X", p.Tag) if p.ClassType == ClassUniversal { tagStr = tagMap[p.Tag] } value := fmt.Sprint(p.Value) description := "" if p.Description != "" { description = p.Description + ": " } _, _ = fmt.Fprintf(out, "%s%s(%s, %s, %s) Len=%d %q\n", indentStr, description, classStr, tagTypeStr, tagStr, p.Data.Len(), value) if printBytes { PrintBytes(out, p.Bytes(), indentStr) } for _, child := range p.Children { printPacket(out, child, indent+1, printBytes) } } // ReadPacket reads a single Packet from the reader. func ReadPacket(reader io.Reader) (*Packet, error) { p, _, err := readPacket(reader) if err != nil { return nil, err } return p, nil } func DecodeString(data []byte) string { return string(data) } func ParseInt64(bytes []byte) (ret int64, err error) { if len(bytes) > 8 { // We'll overflow an int64 in this case. err = fmt.Errorf("integer too large") return } for bytesRead := 0; bytesRead < len(bytes); bytesRead++ { ret <<= 8 ret |= int64(bytes[bytesRead]) } // Shift up and down in order to sign extend the result. ret <<= 64 - uint8(len(bytes))*8 ret >>= 64 - uint8(len(bytes))*8 return } func encodeInteger(i int64) []byte { n := int64Length(i) out := make([]byte, n) var j int for ; n > 0; n-- { out[j] = byte(i >> uint((n-1)*8)) j++ } return out } func int64Length(i int64) (numBytes int) { numBytes = 1 for i > 127 { numBytes++ i >>= 8 } for i < -128 { numBytes++ i >>= 8 } return } // DecodePacket decodes the given bytes into a single Packet // If a decode error is encountered, nil is returned. func DecodePacket(data []byte) *Packet { p, _, _ := readPacket(bytes.NewBuffer(data)) return p } // DecodePacketErr decodes the given bytes into a single Packet // If a decode error is encountered, nil is returned. func DecodePacketErr(data []byte) (*Packet, error) { p, _, err := readPacket(bytes.NewBuffer(data)) if err != nil { return nil, err } return p, nil } // readPacket reads a single Packet from the reader, returning the number of bytes read. func readPacket(reader io.Reader) (*Packet, int, error) { identifier, length, read, err := readHeader(reader) if err != nil { return nil, read, err } p := &Packet{ Identifier: identifier, } p.Data = new(bytes.Buffer) p.Children = make([]*Packet, 0, 2) p.Value = nil if p.TagType == TypeConstructed { // TODO: if universal, ensure tag type is allowed to be constructed // Track how much content we've read contentRead := 0 for { if length != LengthIndefinite { // End if we've read what we've been told to if contentRead == length { break } // Detect if a packet boundary didn't fall on the expected length if contentRead > length { return nil, read, fmt.Errorf("expected to read %d bytes, read %d", length, contentRead) } } // Read the next packet child, r, err := readPacket(reader) if err != nil { return nil, read, err } contentRead += r read += r // Test is this is the EOC marker for our packet if isEOCPacket(child) { if length == LengthIndefinite { break } return nil, read, errors.New("eoc child not allowed with definite length") } // Append and continue p.AppendChild(child) } return p, read, nil } if length == LengthIndefinite { return nil, read, errors.New("indefinite length used with primitive type") } // Read definite-length content if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes { return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes) } content := make([]byte, length) if length > 0 { _, err := io.ReadFull(reader, content) if err != nil { if err == io.EOF { return nil, read, io.ErrUnexpectedEOF } return nil, read, err } read += length } if p.ClassType == ClassUniversal { p.Data.Write(content) p.ByteValue = content switch p.Tag { case TagEOC: case TagBoolean: val, _ := ParseInt64(content) p.Value = val != 0 case TagInteger: p.Value, _ = ParseInt64(content) case TagBitString: case TagOctetString: // the actual string encoding is not known here // (e.g. for LDAP content is already an UTF8-encoded // string). Return the data without further processing p.Value = DecodeString(content) case TagNULL: case TagObjectIdentifier: case TagObjectDescriptor: case TagExternal: case TagRealFloat: p.Value, err = ParseReal(content) case TagEnumerated: p.Value, _ = ParseInt64(content) case TagEmbeddedPDV: case TagUTF8String: val := DecodeString(content) if !utf8.Valid([]byte(val)) { err = errors.New("invalid UTF-8 string") } else { p.Value = val } case TagRelativeOID: case TagSequence: case TagSet: case TagNumericString: case TagPrintableString: val := DecodeString(content) if err = isPrintableString(val); err == nil { p.Value = val } case TagT61String: case TagVideotexString: case TagIA5String: val := DecodeString(content) for i, c := range val { if c >= 0x7F { err = fmt.Errorf("invalid character for IA5String at pos %d: %c", i, c) break } } if err == nil { p.Value = val } case TagUTCTime: case TagGeneralizedTime: p.Value, err = ParseGeneralizedTime(content) case TagGraphicString: case TagVisibleString: case TagGeneralString: case TagUniversalString: case TagCharacterString: case TagBMPString: } } else { p.Data.Write(content) } return p, read, err } func isPrintableString(val string) error { for i, c := range val { switch { case c >= 'a' && c <= 'z': case c >= 'A' && c <= 'Z': case c >= '0' && c <= '9': default: switch c { case '\'', '(', ')', '+', ',', '-', '.', '=', '/', ':', '?', ' ': default: return fmt.Errorf("invalid character in position %d", i) } } } return nil } func (p *Packet) Bytes() []byte { var out bytes.Buffer out.Write(encodeIdentifier(p.Identifier)) out.Write(encodeLength(p.Data.Len())) out.Write(p.Data.Bytes()) return out.Bytes() } func (p *Packet) AppendChild(child *Packet) { p.Data.Write(child.Bytes()) p.Children = append(p.Children, child) } func Encode(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet { p := new(Packet) p.ClassType = classType p.TagType = tagType p.Tag = tag p.Data = new(bytes.Buffer) p.Children = make([]*Packet, 0, 2) p.Value = value p.Description = description if value != nil { v := reflect.ValueOf(value) if classType == ClassUniversal { switch tag { case TagOctetString: sv, ok := v.Interface().(string) if ok { p.Data.Write([]byte(sv)) } case TagEnumerated: bv, ok := v.Interface().([]byte) if ok { p.Data.Write(bv) } case TagEmbeddedPDV: bv, ok := v.Interface().([]byte) if ok { p.Data.Write(bv) } } } else if classType == ClassContext { switch tag { case TagEnumerated: bv, ok := v.Interface().([]byte) if ok { p.Data.Write(bv) } case TagEmbeddedPDV: bv, ok := v.Interface().([]byte) if ok { p.Data.Write(bv) } } } } return p } func NewSequence(description string) *Packet { return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, description) } func NewBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet { intValue := int64(0) if value { intValue = 1 } p := Encode(classType, tagType, tag, nil, description) p.Value = value p.Data.Write(encodeInteger(intValue)) return p } // NewLDAPBoolean returns a RFC 4511-compliant Boolean packet. func NewLDAPBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet { intValue := int64(0) if value { intValue = 255 } p := Encode(classType, tagType, tag, nil, description) p.Value = value p.Data.Write(encodeInteger(intValue)) return p } func NewInteger(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet { p := Encode(classType, tagType, tag, nil, description) p.Value = value switch v := value.(type) { case int: p.Data.Write(encodeInteger(int64(v))) case uint: p.Data.Write(encodeInteger(int64(v))) case int64: p.Data.Write(encodeInteger(v)) case uint64: // TODO : check range or add encodeUInt... p.Data.Write(encodeInteger(int64(v))) case int32: p.Data.Write(encodeInteger(int64(v))) case uint32: p.Data.Write(encodeInteger(int64(v))) case int16: p.Data.Write(encodeInteger(int64(v))) case uint16: p.Data.Write(encodeInteger(int64(v))) case int8: p.Data.Write(encodeInteger(int64(v))) case uint8: p.Data.Write(encodeInteger(int64(v))) default: // TODO : add support for big.Int ? panic(fmt.Sprintf("Invalid type %T, expected {u|}int{64|32|16|8}", v)) } return p } func NewString(classType Class, tagType Type, tag Tag, value, description string) *Packet { p := Encode(classType, tagType, tag, nil, description) p.Value = value p.Data.Write([]byte(value)) return p } func NewGeneralizedTime(classType Class, tagType Type, tag Tag, value time.Time, description string) *Packet { p := Encode(classType, tagType, tag, nil, description) var s string if value.Nanosecond() != 0 { s = value.Format(`20060102150405.000000000Z`) } else { s = value.Format(`20060102150405Z`) } p.Value = s p.Data.Write([]byte(s)) return p } func NewReal(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet { p := Encode(classType, tagType, tag, nil, description) switch v := value.(type) { case float64: p.Data.Write(encodeFloat(v)) case float32: p.Data.Write(encodeFloat(float64(v))) default: panic(fmt.Sprintf("Invalid type %T, expected float{64|32}", v)) } return p } asn1-ber-1.5.4/ber_test.go000066400000000000000000000113701422316226700152760ustar00rootroot00000000000000package ber import ( "bytes" "io" "math" "testing" ) func TestEncodeDecodeInteger(t *testing.T) { for _, v := range []int64{0, 10, 128, 1024, math.MaxInt64, -1, -100, -128, -1024, math.MinInt64} { enc := encodeInteger(v) dec, err := ParseInt64(enc) if err != nil { t.Fatalf("Error decoding %d : %s", v, err) } if v != dec { t.Errorf("TestEncodeDecodeInteger failed for %d (got %d)", v, dec) } } } func TestBoolean(t *testing.T) { packet := NewBoolean(ClassUniversal, TypePrimitive, TagBoolean, true, "first Packet, True") newBoolean, ok := packet.Value.(bool) if !ok || newBoolean != true { t.Error("error during creating packet") } encodedPacket := packet.Bytes() newPacket := DecodePacket(encodedPacket) newBoolean, ok = newPacket.Value.(bool) if !ok || newBoolean != true { t.Error("error during decoding packet") } } func TestLDAPBoolean(t *testing.T) { packet := NewLDAPBoolean(ClassUniversal, TypePrimitive, TagBoolean, true, "first Packet, True") newBoolean, ok := packet.Value.(bool) if !ok || newBoolean != true { t.Error("error during creating packet") } encodedPacket := packet.Bytes() newPacket := DecodePacket(encodedPacket) newBoolean, ok = newPacket.Value.(bool) if !ok || newBoolean != true { t.Error("error during decoding packet") } } func TestInteger(t *testing.T) { var value int64 = 10 packet := NewInteger(ClassUniversal, TypePrimitive, TagInteger, value, "Integer, 10") { newInteger, ok := packet.Value.(int64) if !ok || newInteger != value { t.Error("error creating packet") } } encodedPacket := packet.Bytes() newPacket := DecodePacket(encodedPacket) { newInteger, ok := newPacket.Value.(int64) if !ok || newInteger != value { t.Error("error decoding packet") } } } func TestString(t *testing.T) { var value = "Hic sunt dracones" packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, value, "String") newValue, ok := packet.Value.(string) if !ok || newValue != value { t.Error("error during creating packet") } encodedPacket := packet.Bytes() newPacket := DecodePacket(encodedPacket) newValue, ok = newPacket.Value.(string) if !ok || newValue != value { t.Error("error during decoding packet") } } func TestSequenceAndAppendChild(t *testing.T) { values := []string{ "HIC SVNT LEONES", "Iñtërnâtiônàlizætiøn", "Terra Incognita", } sequence := NewSequence("a sequence") for _, s := range values { sequence.AppendChild(NewString(ClassUniversal, TypePrimitive, TagOctetString, s, "String")) } if len(sequence.Children) != len(values) { t.Errorf("wrong length for children array should be %d, got %d", len(values), len(sequence.Children)) } encodedSequence := sequence.Bytes() decodedSequence := DecodePacket(encodedSequence) if len(decodedSequence.Children) != len(values) { t.Errorf("wrong length for children array should be %d => %d", len(values), len(decodedSequence.Children)) } for i, s := range values { if decodedSequence.Children[i].Value.(string) != s { t.Errorf("expected %d to be %q, got %q", i, s, decodedSequence.Children[i].Value.(string)) } } } func TestReadPacket(t *testing.T) { packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, "Ad impossibilia nemo tenetur", "string") var buffer io.ReadWriter = new(bytes.Buffer) if _, err := buffer.Write(packet.Bytes()); err != nil { t.Error("error writing packet", err) } newPacket, err := ReadPacket(buffer) if err != nil { t.Error("error during ReadPacket", err) } newPacket.ByteValue = nil if !bytes.Equal(newPacket.ByteValue, packet.ByteValue) { t.Error("packets should be the same") } } func TestBinaryInteger(t *testing.T) { // data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.7 var data = []struct { v int64 e []byte }{ {v: 0, e: []byte{0x02, 0x01, 0x00}}, {v: 127, e: []byte{0x02, 0x01, 0x7F}}, {v: 128, e: []byte{0x02, 0x02, 0x00, 0x80}}, {v: 256, e: []byte{0x02, 0x02, 0x01, 0x00}}, {v: -128, e: []byte{0x02, 0x01, 0x80}}, {v: -129, e: []byte{0x02, 0x02, 0xFF, 0x7F}}, {v: math.MaxInt64, e: []byte{0x02, 0x08, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}, {v: math.MinInt64, e: []byte{0x02, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, } for _, d := range data { if b := NewInteger(ClassUniversal, TypePrimitive, TagInteger, d.v, "").Bytes(); !bytes.Equal(d.e, b) { t.Errorf("Wrong binary generated for %d : got % X, expected % X", d.v, b, d.e) } } } func TestBinaryOctetString(t *testing.T) { // data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.10 if !bytes.Equal([]byte{0x04, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, NewString(ClassUniversal, TypePrimitive, TagOctetString, "\x01\x23\x45\x67\x89\xab\xcd\xef", "").Bytes()) { t.Error("wrong binary generated") } } asn1-ber-1.5.4/content_int.go000066400000000000000000000004661422316226700160170ustar00rootroot00000000000000package ber func encodeUnsignedInteger(i uint64) []byte { n := uint64Length(i) out := make([]byte, n) var j int for ; n > 0; n-- { out[j] = byte(i >> uint((n-1)*8)) j++ } return out } func uint64Length(i uint64) (numBytes int) { numBytes = 1 for i > 255 { numBytes++ i >>= 8 } return } asn1-ber-1.5.4/generalizedTime.go000066400000000000000000000047111422316226700166000ustar00rootroot00000000000000package ber import ( "bytes" "errors" "fmt" "strconv" "time" ) // ErrInvalidTimeFormat is returned when the generalizedTime string was not correct. var ErrInvalidTimeFormat = errors.New("invalid time format") var zeroTime = time.Time{} // ParseGeneralizedTime parses a string value and if it conforms to // GeneralizedTime[^0] format, will return a time.Time for that value. // // [^0]: https://www.itu.int/rec/T-REC-X.690-201508-I/en Section 11.7 func ParseGeneralizedTime(v []byte) (time.Time, error) { var format string var fract time.Duration str := []byte(DecodeString(v)) tzIndex := bytes.IndexAny(str, "Z+-") if tzIndex < 0 { return zeroTime, ErrInvalidTimeFormat } dot := bytes.IndexAny(str, ".,") switch dot { case -1: switch tzIndex { case 10: format = `2006010215Z` case 12: format = `200601021504Z` case 14: format = `20060102150405Z` default: return zeroTime, ErrInvalidTimeFormat } case 10, 12: if tzIndex < dot { return zeroTime, ErrInvalidTimeFormat } // a "," is also allowed, but would not be parsed by time.Parse(): str[dot] = '.' // If is omitted, then represents a fraction of an // hour; otherwise, if and are omitted, then // represents a fraction of a minute; otherwise, // represents a fraction of a second. // parse as float from dot to timezone f, err := strconv.ParseFloat(string(str[dot:tzIndex]), 64) if err != nil { return zeroTime, fmt.Errorf("failed to parse float: %s", err) } // ...and strip that part str = append(str[:dot], str[tzIndex:]...) tzIndex = dot if dot == 10 { fract = time.Duration(int64(f * float64(time.Hour))) format = `2006010215Z` } else { fract = time.Duration(int64(f * float64(time.Minute))) format = `200601021504Z` } case 14: if tzIndex < dot { return zeroTime, ErrInvalidTimeFormat } str[dot] = '.' // no need for fractional seconds, time.Parse() handles that format = `20060102150405Z` default: return zeroTime, ErrInvalidTimeFormat } l := len(str) switch l - tzIndex { case 1: if str[l-1] != 'Z' { return zeroTime, ErrInvalidTimeFormat } case 3: format += `0700` str = append(str, []byte("00")...) case 5: format += `0700` default: return zeroTime, ErrInvalidTimeFormat } t, err := time.Parse(format, string(str)) if err != nil { return zeroTime, fmt.Errorf("%s: %s", ErrInvalidTimeFormat, err) } return t.Add(fract), nil } asn1-ber-1.5.4/generalizedTime_test.go000066400000000000000000000034331422316226700176370ustar00rootroot00000000000000package ber import ( "testing" "time" ) func TestParseGeneralizedTime(t *testing.T) { for _, test := range []struct { str string wanted time.Time err error }{ { "20170222190527Z", time.Date(2017, time.Month(2), 22, 19, 05, 27, 0, time.UTC), nil, }, { "201702221905Z", time.Date(2017, time.Month(2), 22, 19, 05, 0, 0, time.UTC), nil, }, { "2017022219Z", time.Date(2017, time.Month(2), 22, 19, 0, 0, 0, time.UTC), nil, }, { "2017022219.25Z", time.Date(2017, time.Month(2), 22, 19, 15, 0, 0, time.UTC), nil, }, { "201702221905.25Z", time.Date(2017, time.Month(2), 22, 19, 5, 15, 0, time.UTC), nil, }, { "20170222190525-0100", time.Date(2017, time.Month(2), 22, 19, 5, 25, 0, time.FixedZone("", -3600)), nil, }, { "20170222190525+0100", time.Date(2017, time.Month(2), 22, 19, 5, 25, 0, time.FixedZone("", 3600)), nil, }, { "20170222190525+01", time.Date(2017, time.Month(2), 22, 19, 5, 25, 0, time.FixedZone("", 3600)), nil, }, { "20170222190527.123Z", time.Date(2017, time.Month(2), 22, 19, 05, 27, 123*1000*1000, time.UTC), nil, }, { "20170222190527,123Z", time.Date(2017, time.Month(2), 22, 19, 05, 27, 123*1000*1000, time.UTC), nil, }, { "2017022219-0100", time.Date(2017, time.Month(2), 22, 19, 0, 0, 0, time.FixedZone("", -3600)), nil, }, } { genTime, err := ParseGeneralizedTime([]byte(test.str)) if err != nil { if test.err != nil { if err != test.err { t.Errorf("unexpected error in %s: %s", test.str, err) } } else { t.Errorf("test %s failed with error: %s", test.str, err) } } else { if !genTime.Equal(test.wanted) { t.Errorf("test got unexpected result: wanted=%s, got=%s", test.wanted, genTime) } } } } asn1-ber-1.5.4/go.mod000066400000000000000000000000601422316226700142400ustar00rootroot00000000000000module github.com/go-asn1-ber/asn1-ber go 1.13 asn1-ber-1.5.4/header.go000066400000000000000000000014311422316226700147140ustar00rootroot00000000000000package ber import ( "errors" "fmt" "io" ) func readHeader(reader io.Reader) (identifier Identifier, length int, read int, err error) { var ( c, l int i Identifier ) if i, c, err = readIdentifier(reader); err != nil { return Identifier{}, 0, read, err } identifier = i read += c if l, c, err = readLength(reader); err != nil { return Identifier{}, 0, read, err } length = l read += c // Validate length type with identifier (x.600, 8.1.3.2.a) if length == LengthIndefinite && identifier.TagType == TypePrimitive { return Identifier{}, 0, read, errors.New("indefinite length used with primitive type") } if length < LengthIndefinite { err = fmt.Errorf("length cannot be less than %d", LengthIndefinite) return } return identifier, length, read, nil } asn1-ber-1.5.4/header_test.go000066400000000000000000000066251422316226700157650ustar00rootroot00000000000000package ber import ( "bytes" "io" "testing" ) func TestReadHeader(t *testing.T) { testCases := map[string]struct { Data []byte ExpectedIdentifier Identifier ExpectedLength int ExpectedBytesRead int ExpectedError string }{ "empty": { Data: []byte{}, ExpectedIdentifier: Identifier{}, ExpectedLength: 0, ExpectedBytesRead: 0, ExpectedError: io.ErrUnexpectedEOF.Error(), }, "valid short form": { Data: []byte{ byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString), 127, }, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypePrimitive, Tag: TagCharacterString, }, ExpectedLength: 127, ExpectedBytesRead: 2, ExpectedError: "", }, "valid long form": { Data: []byte{ // 2-byte encoding of tag byte(ClassUniversal) | byte(TypePrimitive) | byte(HighTag), byte(TagCharacterString), // 2-byte encoding of length LengthLongFormBitmask | 1, 127, }, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypePrimitive, Tag: TagCharacterString, }, ExpectedLength: 127, ExpectedBytesRead: 4, ExpectedError: "", }, "valid indefinite length": { Data: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString), LengthLongFormBitmask, }, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagCharacterString, }, ExpectedLength: LengthIndefinite, ExpectedBytesRead: 2, ExpectedError: "", }, "invalid indefinite length": { Data: []byte{ byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString), LengthLongFormBitmask, }, ExpectedIdentifier: Identifier{}, ExpectedLength: 0, ExpectedBytesRead: 2, ExpectedError: "indefinite length used with primitive type", }, } for k, tc := range testCases { reader := bytes.NewBuffer(tc.Data) identifier, length, read, err := readHeader(reader) if err != nil { if tc.ExpectedError == "" { t.Errorf("%s: unexpected error: %v", k, err) } else if err.Error() != tc.ExpectedError { t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err) } } else if tc.ExpectedError != "" { t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError) continue } if read != tc.ExpectedBytesRead { t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read) } if identifier.ClassType != tc.ExpectedIdentifier.ClassType { t.Errorf("%s: expected class type %d (%s), got %d (%s)", k, tc.ExpectedIdentifier.ClassType, ClassMap[tc.ExpectedIdentifier.ClassType], identifier.ClassType, ClassMap[identifier.ClassType], ) } if identifier.TagType != tc.ExpectedIdentifier.TagType { t.Errorf("%s: expected tag type %d (%s), got %d (%s)", k, tc.ExpectedIdentifier.TagType, TypeMap[tc.ExpectedIdentifier.TagType], identifier.TagType, TypeMap[identifier.TagType], ) } if identifier.Tag != tc.ExpectedIdentifier.Tag { t.Errorf("%s: expected tag %d (%s), got %d (%s)", k, tc.ExpectedIdentifier.Tag, tagMap[tc.ExpectedIdentifier.Tag], identifier.Tag, tagMap[identifier.Tag], ) } if length != tc.ExpectedLength { t.Errorf("%s: expected length %d, got %d", k, tc.ExpectedLength, length) } } } asn1-ber-1.5.4/identifier.go000066400000000000000000000050531422316226700156120ustar00rootroot00000000000000package ber import ( "errors" "fmt" "io" ) func readIdentifier(reader io.Reader) (Identifier, int, error) { identifier := Identifier{} read := 0 // identifier byte b, err := readByte(reader) if err != nil { if Debug { fmt.Printf("error reading identifier byte: %v\n", err) } return Identifier{}, read, err } read++ identifier.ClassType = Class(b) & ClassBitmask identifier.TagType = Type(b) & TypeBitmask if tag := Tag(b) & TagBitmask; tag != HighTag { // short-form tag identifier.Tag = tag return identifier, read, nil } // high-tag-number tag tagBytes := 0 for { b, err := readByte(reader) if err != nil { if Debug { fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err) } return Identifier{}, read, err } tagBytes++ read++ // Lowest 7 bits get appended to the tag value (x.690, 8.1.2.4.2.b) identifier.Tag <<= 7 identifier.Tag |= Tag(b) & HighTagValueBitmask // First byte may not be all zeros (x.690, 8.1.2.4.2.c) if tagBytes == 1 && identifier.Tag == 0 { return Identifier{}, read, errors.New("invalid first high-tag-number tag byte") } // Overflow of int64 // TODO: support big int tags? if tagBytes > 9 { return Identifier{}, read, errors.New("high-tag-number tag overflow") } // Top bit of 0 means this is the last byte in the high-tag-number tag (x.690, 8.1.2.4.2.a) if Tag(b)&HighTagContinueBitmask == 0 { break } } return identifier, read, nil } func encodeIdentifier(identifier Identifier) []byte { b := []byte{0x0} b[0] |= byte(identifier.ClassType) b[0] |= byte(identifier.TagType) if identifier.Tag < HighTag { // Short-form b[0] |= byte(identifier.Tag) } else { // high-tag-number b[0] |= byte(HighTag) tag := identifier.Tag b = append(b, encodeHighTag(tag)...) } return b } func encodeHighTag(tag Tag) []byte { // set cap=4 to hopefully avoid additional allocations b := make([]byte, 0, 4) for tag != 0 { // t := last 7 bits of tag (HighTagValueBitmask = 0x7F) t := tag & HighTagValueBitmask // right shift tag 7 to remove what was just pulled off tag >>= 7 // if b already has entries this entry needs a continuation bit (0x80) if len(b) != 0 { t |= HighTagContinueBitmask } b = append(b, byte(t)) } // reverse // since bits were pulled off 'tag' small to high the byte slice is in reverse order. // example: tag = 0xFF results in {0x7F, 0x01 + 0x80 (continuation bit)} // this needs to be reversed into 0x81 0x7F for i, j := 0, len(b)-1; i < len(b)/2; i++ { b[i], b[j-i] = b[j-i], b[i] } return b } asn1-ber-1.5.4/identifier_test.go000066400000000000000000000253651422316226700166610ustar00rootroot00000000000000package ber import ( "bytes" "io" "math" "testing" ) func TestReadIdentifier(t *testing.T) { testCases := map[string]struct { Data []byte ExpectedIdentifier Identifier ExpectedBytesRead int ExpectedError string }{ "empty": { Data: []byte{}, ExpectedBytesRead: 0, ExpectedError: io.ErrUnexpectedEOF.Error(), }, "universal primitive eoc": { Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)}, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypePrimitive, Tag: TagEOC, }, ExpectedBytesRead: 1, }, "universal primitive character string": { Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)}, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypePrimitive, Tag: TagCharacterString, }, ExpectedBytesRead: 1, }, "universal constructed bit string": { Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)}, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagBitString, }, ExpectedBytesRead: 1, }, "universal constructed character string": { Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)}, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagCharacterString, }, ExpectedBytesRead: 1, }, "application constructed object descriptor": { Data: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)}, ExpectedIdentifier: Identifier{ ClassType: ClassApplication, TagType: TypeConstructed, Tag: TagObjectDescriptor, }, ExpectedBytesRead: 1, }, "context constructed object descriptor": { Data: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)}, ExpectedIdentifier: Identifier{ ClassType: ClassContext, TagType: TypeConstructed, Tag: TagObjectDescriptor, }, ExpectedBytesRead: 1, }, "private constructed object descriptor": { Data: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)}, ExpectedIdentifier: Identifier{ ClassType: ClassPrivate, TagType: TypeConstructed, Tag: TagObjectDescriptor, }, ExpectedBytesRead: 1, }, "high-tag-number tag missing bytes": { Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag)}, ExpectedError: io.ErrUnexpectedEOF.Error(), ExpectedBytesRead: 1, }, "high-tag-number tag invalid first byte": { Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), 0x0}, ExpectedError: "invalid first high-tag-number tag byte", ExpectedBytesRead: 2, }, "high-tag-number tag invalid first byte with continue bit": { Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask)}, ExpectedError: "invalid first high-tag-number tag byte", ExpectedBytesRead: 2, }, "high-tag-number tag continuation missing bytes": { Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x1)}, ExpectedError: io.ErrUnexpectedEOF.Error(), ExpectedBytesRead: 2, }, "high-tag-number tag overflow": { Data: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(HighTagContinueBitmask | 0x1), byte(0x1), }, ExpectedError: "high-tag-number tag overflow", ExpectedBytesRead: 11, }, "max high-tag-number tag": { Data: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(0x7f), }, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: Tag(0x7FFFFFFFFFFFFFFF), // 01111111...(63)...11111b }, ExpectedBytesRead: 10, }, "high-tag-number encoding of low-tag value": { Data: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(TagObjectDescriptor), }, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagObjectDescriptor, }, ExpectedBytesRead: 2, }, "max high-tag-number tag ignores extra data": { Data: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(0x7f), byte(0x01), // extra data, shouldn't be read byte(0x02), // extra data, shouldn't be read byte(0x03), // extra data, shouldn't be read }, ExpectedIdentifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: Tag(0x7FFFFFFFFFFFFFFF), // 01111111...(63)...11111b }, ExpectedBytesRead: 10, }, } for k, tc := range testCases { reader := bytes.NewBuffer(tc.Data) identifier, read, err := readIdentifier(reader) if err != nil { if tc.ExpectedError == "" { t.Errorf("%s: unexpected error: %v", k, err) } else if err.Error() != tc.ExpectedError { t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err) } } else if tc.ExpectedError != "" { t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError) continue } if read != tc.ExpectedBytesRead { t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read) } if identifier.ClassType != tc.ExpectedIdentifier.ClassType { t.Errorf("%s: expected class type %d (%s), got %d (%s)", k, tc.ExpectedIdentifier.ClassType, ClassMap[tc.ExpectedIdentifier.ClassType], identifier.ClassType, ClassMap[identifier.ClassType], ) } if identifier.TagType != tc.ExpectedIdentifier.TagType { t.Errorf("%s: expected tag type %d (%s), got %d (%s)", k, tc.ExpectedIdentifier.TagType, TypeMap[tc.ExpectedIdentifier.TagType], identifier.TagType, TypeMap[identifier.TagType], ) } if identifier.Tag != tc.ExpectedIdentifier.Tag { t.Errorf("%s: expected tag %d (%s), got %d (%s)", k, tc.ExpectedIdentifier.Tag, tagMap[tc.ExpectedIdentifier.Tag], identifier.Tag, tagMap[identifier.Tag], ) } } } func TestEncodeIdentifier(t *testing.T) { testCases := map[string]struct { Identifier Identifier ExpectedBytes []byte }{ "universal primitive eoc": { Identifier: Identifier{ ClassType: ClassUniversal, TagType: TypePrimitive, Tag: TagEOC, }, ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)}, }, "universal primitive character string": { Identifier: Identifier{ ClassType: ClassUniversal, TagType: TypePrimitive, Tag: TagCharacterString, }, ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)}, }, "universal constructed bit string": { Identifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagBitString, }, ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)}, }, "universal constructed character string": { Identifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagCharacterString, }, ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)}, }, "application constructed object descriptor": { Identifier: Identifier{ ClassType: ClassApplication, TagType: TypeConstructed, Tag: TagObjectDescriptor, }, ExpectedBytes: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)}, }, "context constructed object descriptor": { Identifier: Identifier{ ClassType: ClassContext, TagType: TypeConstructed, Tag: TagObjectDescriptor, }, ExpectedBytes: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)}, }, "private constructed object descriptor": { Identifier: Identifier{ ClassType: ClassPrivate, TagType: TypeConstructed, Tag: TagObjectDescriptor, }, ExpectedBytes: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)}, }, "max low-tag-number tag": { Identifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagBMPString, }, ExpectedBytes: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBMPString), }, }, "min high-tag-number tag": { Identifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: TagBMPString + 1, }, ExpectedBytes: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(TagBMPString + 1), }, }, "max high-tag-number tag": { Identifier: Identifier{ ClassType: ClassUniversal, TagType: TypeConstructed, Tag: Tag(math.MaxInt64), }, ExpectedBytes: []byte{ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(HighTagContinueBitmask | 0x7f), byte(0x7f), }, }, } for k, tc := range testCases { b := encodeIdentifier(tc.Identifier) if !bytes.Equal(tc.ExpectedBytes, b) { t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedBytes, b) } } } func TestEncodeHighTag(t *testing.T) { cases := []struct { tag Tag want []byte }{ {134, []byte{0x80 + 0x01, 0x06}}, {123456, []byte{0x80 + 0x07, 0x80 + 0x44, 0x40}}, {0xFF, []byte{0x81, 0x7F}}, } for _, c := range cases { got := encodeHighTag(c.tag) if !bytes.Equal(c.want, got) { t.Errorf("tag: %d want: %#v got: %#v", c.tag, c.want, got) } } } asn1-ber-1.5.4/length.go000066400000000000000000000037521422316226700147550ustar00rootroot00000000000000package ber import ( "errors" "fmt" "io" ) func readLength(reader io.Reader) (length int, read int, err error) { // length byte b, err := readByte(reader) if err != nil { if Debug { fmt.Printf("error reading length byte: %v\n", err) } return 0, 0, err } read++ switch { case b == 0xFF: // Invalid 0xFF (x.600, 8.1.3.5.c) return 0, read, errors.New("invalid length byte 0xff") case b == LengthLongFormBitmask: // Indefinite form, we have to decode packets until we encounter an EOC packet (x.600, 8.1.3.6) length = LengthIndefinite case b&LengthLongFormBitmask == 0: // Short definite form, extract the length from the bottom 7 bits (x.600, 8.1.3.4) length = int(b) & LengthValueBitmask case b&LengthLongFormBitmask != 0: // Long definite form, extract the number of length bytes to follow from the bottom 7 bits (x.600, 8.1.3.5.b) lengthBytes := int(b) & LengthValueBitmask // Protect against overflow // TODO: support big int length? if lengthBytes > 8 { return 0, read, errors.New("long-form length overflow") } // Accumulate into a 64-bit variable var length64 int64 for i := 0; i < lengthBytes; i++ { b, err = readByte(reader) if err != nil { if Debug { fmt.Printf("error reading long-form length byte %d: %v\n", i, err) } return 0, read, err } read++ // x.600, 8.1.3.5 length64 <<= 8 length64 |= int64(b) } // Cast to a platform-specific integer length = int(length64) // Ensure we didn't overflow if int64(length) != length64 { return 0, read, errors.New("long-form length overflow") } default: return 0, read, errors.New("invalid length byte") } return length, read, nil } func encodeLength(length int) []byte { lengthBytes := encodeUnsignedInteger(uint64(length)) if length > 127 || len(lengthBytes) > 1 { longFormBytes := []byte{LengthLongFormBitmask | byte(len(lengthBytes))} longFormBytes = append(longFormBytes, lengthBytes...) lengthBytes = longFormBytes } return lengthBytes } asn1-ber-1.5.4/length_test.go000066400000000000000000000101161422316226700160040ustar00rootroot00000000000000package ber import ( "bytes" "io" "math" "testing" ) func TestReadLength(t *testing.T) { testCases := map[string]struct { Data []byte ExpectedLength int64 ExpectedBytesRead int ExpectedError string }{ "empty": { Data: []byte{}, ExpectedBytesRead: 0, ExpectedError: io.ErrUnexpectedEOF.Error(), }, "invalid first byte": { Data: []byte{0xFF}, ExpectedBytesRead: 1, ExpectedError: "invalid length byte 0xff", }, "indefinite form": { Data: []byte{LengthLongFormBitmask}, ExpectedLength: LengthIndefinite, ExpectedBytesRead: 1, }, "short-definite-form zero length": { Data: []byte{0}, ExpectedLength: 0, ExpectedBytesRead: 1, }, "short-definite-form length 1": { Data: []byte{1}, ExpectedLength: 1, ExpectedBytesRead: 1, }, "short-definite-form max length": { Data: []byte{127}, ExpectedLength: 127, ExpectedBytesRead: 1, }, "long-definite-form missing bytes": { Data: []byte{LengthLongFormBitmask | 1}, ExpectedBytesRead: 1, ExpectedError: io.ErrUnexpectedEOF.Error(), }, "long-definite-form overflow": { Data: []byte{LengthLongFormBitmask | 9}, ExpectedBytesRead: 1, ExpectedError: "long-form length overflow", }, "long-definite-form zero length": { Data: []byte{LengthLongFormBitmask | 1, 0x0}, ExpectedLength: 0, ExpectedBytesRead: 2, }, "long-definite-form length 127": { Data: []byte{LengthLongFormBitmask | 1, 127}, ExpectedLength: 127, ExpectedBytesRead: 2, }, "long-definite-form max length (32-bit)": { Data: []byte{ LengthLongFormBitmask | 4, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, }, ExpectedLength: math.MaxInt32, ExpectedBytesRead: 5, }, "long-definite-form max length (64-bit)": { Data: []byte{ LengthLongFormBitmask | 8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, ExpectedLength: math.MaxInt64, ExpectedBytesRead: 9, }, } for k, tc := range testCases { // Skip tests requiring 64-bit integers on platforms that don't support them if tc.ExpectedLength != int64(int(tc.ExpectedLength)) { continue } reader := bytes.NewBuffer(tc.Data) length, read, err := readLength(reader) if err != nil { if tc.ExpectedError == "" { t.Errorf("%s: unexpected error: %v", k, err) } else if err.Error() != tc.ExpectedError { t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err) } } else if tc.ExpectedError != "" { t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError) continue } if read != tc.ExpectedBytesRead { t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read) } if int64(length) != tc.ExpectedLength { t.Errorf("%s: expected length %d, got %d", k, tc.ExpectedLength, length) } } } func TestEncodeLength(t *testing.T) { testCases := map[string]struct { Length int64 ExpectedBytes []byte }{ "0": { Length: 0, ExpectedBytes: []byte{0}, }, "1": { Length: 1, ExpectedBytes: []byte{1}, }, "max short-form length": { Length: 127, ExpectedBytes: []byte{127}, }, "min long-form length": { Length: 128, ExpectedBytes: []byte{LengthLongFormBitmask | 1, 128}, }, "max long-form length (32-bit)": { Length: math.MaxInt32, ExpectedBytes: []byte{ LengthLongFormBitmask | 4, 0x7F, 0xFF, 0xFF, 0xFF, }, }, "max long-form length (64-bit)": { Length: math.MaxInt64, ExpectedBytes: []byte{ LengthLongFormBitmask | 8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, }, } for k, tc := range testCases { // Skip tests requiring 64-bit integers on platforms that don't support them if tc.Length != int64(int(tc.Length)) { continue } b := encodeLength(int(tc.Length)) if !bytes.Equal(tc.ExpectedBytes, b) { t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedBytes, b) } } } asn1-ber-1.5.4/real.go000066400000000000000000000061161422316226700144140ustar00rootroot00000000000000package ber import ( "bytes" "errors" "fmt" "math" "strconv" "strings" ) func encodeFloat(v float64) []byte { switch { case math.IsInf(v, 1): return []byte{0x40} case math.IsInf(v, -1): return []byte{0x41} case math.IsNaN(v): return []byte{0x42} case v == 0.0: if math.Signbit(v) { return []byte{0x43} } return []byte{} default: // we take the easy part ;-) value := []byte(strconv.FormatFloat(v, 'G', -1, 64)) var ret []byte if bytes.Contains(value, []byte{'E'}) { ret = []byte{0x03} } else { ret = []byte{0x02} } ret = append(ret, value...) return ret } } func ParseReal(v []byte) (val float64, err error) { if len(v) == 0 { return 0.0, nil } switch { case v[0]&0x80 == 0x80: val, err = parseBinaryFloat(v) case v[0]&0xC0 == 0x40: val, err = parseSpecialFloat(v) case v[0]&0xC0 == 0x0: val, err = parseDecimalFloat(v) default: return 0.0, fmt.Errorf("invalid info block") } if err != nil { return 0.0, err } if val == 0.0 && !math.Signbit(val) { return 0.0, errors.New("REAL value +0 must be encoded with zero-length value block") } return val, nil } func parseBinaryFloat(v []byte) (float64, error) { var info byte var buf []byte info, v = v[0], v[1:] var base int switch info & 0x30 { case 0x00: base = 2 case 0x10: base = 8 case 0x20: base = 16 case 0x30: return 0.0, errors.New("bits 6 and 5 of information octet for REAL are equal to 11") } scale := uint((info & 0x0c) >> 2) var expLen int switch info & 0x03 { case 0x00: expLen = 1 case 0x01: expLen = 2 case 0x02: expLen = 3 case 0x03: expLen = int(v[0]) if expLen > 8 { return 0.0, errors.New("too big value of exponent") } v = v[1:] } buf, v = v[:expLen], v[expLen:] exponent, err := ParseInt64(buf) if err != nil { return 0.0, err } if len(v) > 8 { return 0.0, errors.New("too big value of mantissa") } mant, err := ParseInt64(v) if err != nil { return 0.0, err } mantissa := mant << scale if info&0x40 == 0x40 { mantissa = -mantissa } return float64(mantissa) * math.Pow(float64(base), float64(exponent)), nil } func parseDecimalFloat(v []byte) (val float64, err error) { switch v[0] & 0x3F { case 0x01: // NR form 1 var iVal int64 iVal, err = strconv.ParseInt(strings.TrimLeft(string(v[1:]), " "), 10, 64) val = float64(iVal) case 0x02, 0x03: // NR form 2, 3 val, err = strconv.ParseFloat(strings.Replace(strings.TrimLeft(string(v[1:]), " "), ",", ".", -1), 64) default: err = errors.New("incorrect NR form") } if err != nil { return 0.0, err } if val == 0.0 && math.Signbit(val) { return 0.0, errors.New("REAL value -0 must be encoded as a special value") } return val, nil } func parseSpecialFloat(v []byte) (float64, error) { if len(v) != 1 { return 0.0, errors.New(`encoding of "special value" must not contain exponent and mantissa`) } switch v[0] { case 0x40: return math.Inf(1), nil case 0x41: return math.Inf(-1), nil case 0x42: return math.NaN(), nil case 0x43: return math.Copysign(0, -1), nil } return 0.0, errors.New(`encoding of "special value" not from ASN.1 standard`) } asn1-ber-1.5.4/real_test.go000066400000000000000000000010301422316226700154410ustar00rootroot00000000000000package ber import ( "math" "testing" ) var negativeZero = math.Copysign(0, -1) func TestRealEncoding(t *testing.T) { for _, value := range []float64{ 0.15625, -0.15625, math.Inf(1), math.Inf(-1), math.NaN(), negativeZero, 0.0, } { enc := encodeFloat(value) dec, err := ParseReal(enc) if err != nil { t.Errorf("Failed to decode %f (%v): %s", value, enc, err) } if dec != value { if !(math.IsNaN(dec) && math.IsNaN(value)) { t.Errorf("decoded value != orig: %f <=> %f", value, dec) } } } } asn1-ber-1.5.4/string_test.go000066400000000000000000000041471422316226700160400ustar00rootroot00000000000000package ber import ( "testing" ) func TestIA5String(t *testing.T) { for _, test := range []struct { value string expectedErr string }{ {"asdfgh", ""}, {"asdfgå", "invalid character for IA5String at pos 5: å"}, } { pkt := NewString(ClassUniversal, TypePrimitive, TagIA5String, test.value, test.value) dec, err := DecodePacketErr(pkt.Bytes()) if err == nil { if test.expectedErr != "" { t.Errorf("got unexpected error for `%s`: %s", test.value, err) } if dec.Value.(string) != test.value { t.Errorf("did not get back original value: %s <=> %s", dec.Value.(string), test.value) } } else if err.Error() != test.expectedErr { t.Errorf("got unexpected error for `%s`: %s", test.value, err) } } } func TestPrintableString(t *testing.T) { for _, test := range []struct { value string expectedErr string }{ {"asdfgh", ""}, {"asdfgå", "invalid character in position 5"}, } { pkt := NewString(ClassUniversal, TypePrimitive, TagPrintableString, test.value, test.value) dec, err := DecodePacketErr(pkt.Bytes()) if err == nil { if test.expectedErr != "" { t.Errorf("got unexpected error for `%s`: %s", test.value, err) } if dec.Value.(string) != test.value { t.Errorf("did not get back original value: %s <=> %s", dec.Value.(string), test.value) } } else if err.Error() != test.expectedErr { t.Errorf("got unexpected error for `%s`: %s", test.value, err) } } } func TestUTF8String(t *testing.T) { for _, test := range []struct { value string expectedErr string }{ {"åäöüß", ""}, {"asdfg\xFF", "invalid UTF-8 string"}, } { pkt := NewString(ClassUniversal, TypePrimitive, TagUTF8String, test.value, test.value) dec, err := DecodePacketErr(pkt.Bytes()) if err == nil { if test.expectedErr != "" { t.Errorf("got unexpected error for `%s`: %s", test.value, err) } if dec.Value.(string) != test.value { t.Errorf("did not get back original value: %s <=> %s", dec.Value.(string), test.value) } } else if err.Error() != test.expectedErr { t.Errorf("got unexpected error for `%s`: %s", test.value, err) } } } asn1-ber-1.5.4/suite_test.go000066400000000000000000000166261422316226700156700ustar00rootroot00000000000000package ber import ( "bytes" "fmt" "io" "io/ioutil" "math" "testing" ) var errEOF = io.ErrUnexpectedEOF.Error() // Tests from http://www.strozhevsky.com/free_docs/free_asn1_testsuite_descr.pdf // Source files and descriptions at http://www.strozhevsky.com/free_docs/TEST_SUITE.zip var testCases = []struct { // File contains the path to the BER-encoded file File string // Error indicates whether a decoding error is expected Error string // AbnormalEncoding indicates whether a normalized re-encoding is expected to differ from the original source AbnormalEncoding bool // IndefiniteEncoding indicates the source file used indefinite-length encoding, so the re-encoding is expected to differ (since the length is known) IndefiniteEncoding bool }{ // Common blocks {File: "tests/tc1.ber", Error: "high-tag-number tag overflow"}, {File: "tests/tc2.ber", Error: errEOF}, {File: "tests/tc3.ber", Error: errEOF}, {File: "tests/tc4.ber", Error: "invalid length byte 0xff"}, {File: "tests/tc5.ber", Error: "", AbnormalEncoding: true}, // Real numbers (some expected failures are disabled until support is added) {File: "tests/tc6.ber", Error: "REAL value +0 must be encoded with zero-length value block"}, {File: "tests/tc7.ber", Error: "REAL value -0 must be encoded as a special value"}, {File: "tests/tc8.ber", Error: `encoding of "special value" must not contain exponent and mantissa`}, {File: "tests/tc9.ber", Error: "bits 6 and 5 of information octet for REAL are equal to 11"}, {File: "tests/tc10.ber", Error: ""}, {File: "tests/tc11.ber", Error: "incorrect NR form"}, {File: "tests/tc12.ber", Error: `encoding of "special value" not from ASN.1 standard`}, {File: "tests/tc13.ber", Error: errEOF}, {File: "tests/tc14.ber", Error: errEOF}, {File: "tests/tc15.ber", Error: "too big value of exponent"}, {File: "tests/tc16.ber", Error: "too big value of mantissa"}, {File: "tests/tc17.ber", Error: "too big value of exponent"}, // Error: "Too big values for exponent and mantissa + using of "scaling factor" value" // Integers {File: "tests/tc18.ber", Error: ""}, {File: "tests/tc19.ber", Error: errEOF}, {File: "tests/tc20.ber", Error: ""}, // Object identifiers {File: "tests/tc21.ber", Error: ""}, {File: "tests/tc22.ber", Error: ""}, {File: "tests/tc23.ber", Error: errEOF}, {File: "tests/tc24.ber", Error: ""}, // Booleans {File: "tests/tc25.ber", Error: ""}, {File: "tests/tc26.ber", Error: ""}, {File: "tests/tc27.ber", Error: errEOF}, {File: "tests/tc28.ber", Error: ""}, {File: "tests/tc29.ber", Error: ""}, // Null {File: "tests/tc30.ber", Error: ""}, {File: "tests/tc31.ber", Error: errEOF}, {File: "tests/tc32.ber", Error: ""}, // Bit string (some expected failures are disabled until support is added) {File: "tests/tc33.ber", Error: ""}, // Error: "Too big value for "unused bits"" {File: "tests/tc34.ber", Error: errEOF}, {File: "tests/tc35.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from BIT STRING types as internal types for constructive encoding" {File: "tests/tc36.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of "unused bits" in internal BIT STRINGs with constructive form of encoding" {File: "tests/tc37.ber", Error: ""}, {File: "tests/tc38.ber", Error: "", IndefiniteEncoding: true}, {File: "tests/tc39.ber", Error: ""}, {File: "tests/tc40.ber", Error: ""}, // Octet string (some expected failures are disabled until support is added) {File: "tests/tc41.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from OCTET STRING types as internal types for constructive encoding" {File: "tests/tc42.ber", Error: errEOF}, {File: "tests/tc43.ber", Error: errEOF}, {File: "tests/tc44.ber", Error: ""}, {File: "tests/tc45.ber", Error: ""}, // Bit string {File: "tests/tc46.ber", Error: "indefinite length used with primitive type"}, {File: "tests/tc47.ber", Error: "eoc child not allowed with definite length"}, {File: "tests/tc48.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of more than 7 "unused bits" in BIT STRING with constrictive encoding form" {File: "tests/tc49.ber", Error: ""}, {File: "tests/tc50.ber", Error: is64bit("length cannot be less than -1", "long-form length overflow")}, {File: "tests/tc51.ber", Error: is64bit(fmt.Sprintf("length 206966894640 greater than maximum %v", MaxPacketLengthBytes), "long-form length overflow")}, } func is64bit(a, b string) string { maxInt64 := int64(math.MaxInt64) length := int(maxInt64) if int64(length) != maxInt64 { return b } return a } func TestSuiteDecodePacket(t *testing.T) { // Debug = true for _, tc := range testCases { file := tc.File dataIn, err := ioutil.ReadFile(file) if err != nil { t.Errorf("%s: %v", file, err) continue } // fmt.Printf("%s: decode %d\n", file, len(dataIn)) packet, err := DecodePacketErr(dataIn) if err != nil { if tc.Error == "" { t.Errorf("%s: unexpected error during DecodePacket: %v", file, err) } else if tc.Error != err.Error() { t.Errorf("%s: expected error %q during DecodePacket, got %q", file, tc.Error, err) } continue } if tc.Error != "" { t.Errorf("%s: expected error %q, got none", file, tc.Error) continue } dataOut := packet.Bytes() if tc.AbnormalEncoding || tc.IndefiniteEncoding { // Abnormal encodings and encodings that used indefinite length should re-encode differently if bytes.Equal(dataOut, dataIn) { t.Errorf("%s: data should have been re-encoded differently", file) } } else if !bytes.Equal(dataOut, dataIn) { // Make sure the serialized data matches the source t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataIn, dataOut) } packet, err = DecodePacketErr(dataOut) if err != nil { t.Errorf("%s: unexpected error: %v", file, err) continue } // Make sure the re-serialized data matches our original serialization dataOut2 := packet.Bytes() if !bytes.Equal(dataOut, dataOut2) { t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataOut, dataOut2) } } } func TestSuiteReadPacket(t *testing.T) { for _, tc := range testCases { file := tc.File dataIn, err := ioutil.ReadFile(file) if err != nil { t.Errorf("%s: %v", file, err) continue } buffer := bytes.NewBuffer(dataIn) packet, err := ReadPacket(buffer) if err != nil { if tc.Error == "" { t.Errorf("%s: unexpected error during ReadPacket: %v", file, err) } else if tc.Error != err.Error() { t.Errorf("%s: expected error %q during ReadPacket, got %q", file, tc.Error, err) } continue } if tc.Error != "" { t.Errorf("%s: expected error %q, got none", file, tc.Error) continue } dataOut := packet.Bytes() if tc.AbnormalEncoding || tc.IndefiniteEncoding { // Abnormal encodings and encodings that used indefinite length should re-encode differently if bytes.Equal(dataOut, dataIn) { t.Errorf("%s: data should have been re-encoded differently", file) } } else if !bytes.Equal(dataOut, dataIn) { // Make sure the serialized data matches the source t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataIn, dataOut) } packet, err = DecodePacketErr(dataOut) if err != nil { t.Errorf("%s: unexpected error: %v", file, err) continue } // Make sure the re-serialized data matches our original serialization dataOut2 := packet.Bytes() if !bytes.Equal(dataOut, dataOut2) { t.Errorf("%s: data should be the same\nwant: %#v\ngot: %#v", file, dataOut, dataOut2) } } } asn1-ber-1.5.4/tests/000077500000000000000000000000001422316226700143005ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc1.ber000066400000000000000000000000151422316226700154550ustar00rootroot00000000000000@asn1-ber-1.5.4/tests/tc10.ber000066400000000000000000000000111422316226700155310ustar00rootroot00000000000000 asn1-ber-1.5.4/tests/tc11.ber000066400000000000000000000000131422316226700155340ustar00rootroot00000000000000  015625asn1-ber-1.5.4/tests/tc12.ber000066400000000000000000000000031422316226700155340ustar00rootroot00000000000000 Iasn1-ber-1.5.4/tests/tc13.ber000066400000000000000000000000131422316226700155360ustar00rootroot00000000000000 asn1-ber-1.5.4/tests/tc14.ber000066400000000000000000000000071422316226700155420ustar00rootroot00000000000000 asn1-ber-1.5.4/tests/tc15.ber000066400000000000000000000000161422316226700155430ustar00rootroot00000000000000 asn1-ber-1.5.4/tests/tc16.ber000066400000000000000000000000161422316226700155440ustar00rootroot00000000000000 asn1-ber-1.5.4/tests/tc17.ber000066400000000000000000000000261422316226700155460ustar00rootroot00000000000000  asn1-ber-1.5.4/tests/tc18.ber000066400000000000000000000000051422316226700155440ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc19.ber000066400000000000000000000000021422316226700155420ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc2.ber000066400000000000000000000000121422316226700154530ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc20.ber000066400000000000000000000000131422316226700155340ustar00rootroot00000000000000 asn1-ber-1.5.4/tests/tc21.ber000066400000000000000000000000101422316226700155320ustar00rootroot00000000000000Qasn1-ber-1.5.4/tests/tc22.ber000066400000000000000000000000221422316226700155360ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc23.ber000066400000000000000000000000101422316226700155340ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc24.ber000066400000000000000000000000271422316226700155450ustar00rootroot00000000000000`HO Jc/asn1-ber-1.5.4/tests/tc25.ber000066400000000000000000000000051422316226700155420ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc26.ber000066400000000000000000000000051422316226700155430ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc27.ber000066400000000000000000000000021422316226700155410ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc28.ber000066400000000000000000000000031422316226700155430ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc29.ber000066400000000000000000000000031422316226700155440ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc3.ber000066400000000000000000000000121422316226700154540ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc30.ber000066400000000000000000000000051422316226700155360ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc31.ber000066400000000000000000000000041422316226700155360ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc32.ber000066400000000000000000000000021422316226700155350ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc33.ber000066400000000000000000000000041422316226700155400ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc34.ber000066400000000000000000000000031422316226700155400ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc35.ber000066400000000000000000000000201422316226700155400ustar00rootroot00000000000000# ;_)asn1-ber-1.5.4/tests/tc36.ber000066400000000000000000000000241422316226700155450ustar00rootroot00000000000000##asn1-ber-1.5.4/tests/tc37.ber000066400000000000000000000000161422316226700155470ustar00rootroot00000000000000# asn1-ber-1.5.4/tests/tc38.ber000066400000000000000000000000201422316226700155430ustar00rootroot00000000000000# ;_)asn1-ber-1.5.4/tests/tc39.ber000066400000000000000000000000021422316226700155440ustar00rootroot00000000000000#asn1-ber-1.5.4/tests/tc4.ber000066400000000000000000000000131422316226700154560ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc40.ber000066400000000000000000000000021422316226700155340ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc41.ber000066400000000000000000000000201422316226700155350ustar00rootroot00000000000000$ ;_)asn1-ber-1.5.4/tests/tc42.ber000066400000000000000000000000161422316226700155430ustar00rootroot00000000000000$_)asn1-ber-1.5.4/tests/tc43.ber000066400000000000000000000000021422316226700155370ustar00rootroot00000000000000$asn1-ber-1.5.4/tests/tc44.ber000066400000000000000000000000021422316226700155400ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc45.ber000066400000000000000000000000021422316226700155410ustar00rootroot00000000000000$asn1-ber-1.5.4/tests/tc46.ber000066400000000000000000000000131422316226700155440ustar00rootroot00000000000000 ;_)asn1-ber-1.5.4/tests/tc47.ber000066400000000000000000000000201422316226700155430ustar00rootroot00000000000000#asn1-ber-1.5.4/tests/tc48.ber000066400000000000000000000000201422316226700155440ustar00rootroot00000000000000#asn1-ber-1.5.4/tests/tc49.ber000066400000000000000000000000041422316226700155470ustar00rootroot00000000000000asn1-ber-1.5.4/tests/tc5.ber000066400000000000000000000000151422316226700154610ustar00rootroot00000000000000@asn1-ber-1.5.4/tests/tc50.ber000066400000000000000000000000121422316226700155360ustar00rootroot000000000000000000000asn1-ber-1.5.4/tests/tc51.ber000066400000000000000000000000071422316226700155430ustar00rootroot0000000000000000000asn1-ber-1.5.4/tests/tc6.ber000066400000000000000000000000111422316226700154560ustar00rootroot00000000000000 +0.E-5asn1-ber-1.5.4/tests/tc7.ber000066400000000000000000000000111422316226700154570ustar00rootroot00000000000000 -0.E-5asn1-ber-1.5.4/tests/tc8.ber000066400000000000000000000000051422316226700154630ustar00rootroot00000000000000 Aasn1-ber-1.5.4/tests/tc9.ber000066400000000000000000000000051422316226700154640ustar00rootroot00000000000000 asn1-ber-1.5.4/util.go000066400000000000000000000007041422316226700144430ustar00rootroot00000000000000package ber import "io" func readByte(reader io.Reader) (byte, error) { bytes := make([]byte, 1) _, err := io.ReadFull(reader, bytes) if err != nil { if err == io.EOF { return 0, io.ErrUnexpectedEOF } return 0, err } return bytes[0], nil } func isEOCPacket(p *Packet) bool { return p != nil && p.Tag == TagEOC && p.ClassType == ClassUniversal && p.TagType == TypePrimitive && len(p.ByteValue) == 0 && len(p.Children) == 0 }