From 45715bd42227aa7040c95b2831e24ae3d0c93e29 Mon Sep 17 00:00:00 2001 From: Michael Mitton Date: Fri, 18 Feb 2011 01:36:12 -0500 Subject: first commit --- Makefile | 11 ++ README | 14 +++ ber.go | 431 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 ber.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..acda29a --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include $(GOROOT)/src/Make.inc + +TARG=github.com/mmitton/asn1-ber +GOFILES=\ + ber.go\ + +include $(GOROOT)/src/Make.pkg diff --git a/README b/README new file mode 100644 index 0000000..bb785a0 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +ASN1 BER Encoding / Decoding Library for the GO programming language. + +Required Librarys: + None + +Working: + Very basic encoding / decoding needed for LDAP protocol + +Tests Implemented: + None + +TODO: + Fix all encoding / decoding to conform to ASN1 BER spec + Implement Tests / Benchmarks diff --git a/ber.go b/ber.go new file mode 100644 index 0000000..5e2fc0d --- /dev/null +++ b/ber.go @@ -0,0 +1,431 @@ +package ber + +import ( + "bytes" + "fmt" + "io" + "os" + "reflect" +) + +type Packet struct { + ClassType uint8 + TagType uint8 + Tag uint8 + Value interface{} + Data *bytes.Buffer + Children []*Packet + Description string +} + +const ( + TagEOC = 0x00 + TagBoolean = 0x01 + TagInteger = 0x02 + TagBitString = 0x03 + TagOctetString = 0x04 + TagNULL = 0x05 + TagObjectIdentifier = 0x06 + TagObjectDescriptor = 0x07 + TagExternal = 0x08 + TagRealFloat = 0x09 + TagEnumerated = 0x0a + TagEmbeddedPDV = 0x0b + TagUTF8String = 0x0c + TagRelativeOID = 0x0d + TagSequence = 0x10 + TagSet = 0x11 + TagNumericString = 0x12 + TagPrintableString = 0x13 + TagT61String = 0x14 + TagVideotexString = 0x15 + TagIA5String = 0x16 + TagUTCTime = 0x17 + TagGeneralizedTime = 0x18 + TagGraphicString = 0x19 + TagVisibleString = 0x1a + TagGeneralString = 0x1b + TagUniversalString = 0x1c + TagCharacterString = 0x1d + TagBMPString = 0x1e + TagBitmask = 0x1f // xxx11111b +) + +var TagMap = map[uint8] 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", +} + +const ( + ClassUniversal = 0 // 00xxxxxxb + ClassApplication = 64 // 01xxxxxxb + ClassContext = 128 // 10xxxxxxb + ClassPrivate = 192 // 11xxxxxxb + ClassBitmask = 192 // 11xxxxxxb +) + +var ClassMap = map[uint8] string { + ClassUniversal : "Universal", + ClassApplication : "Application", + ClassContext : "Context", + ClassPrivate : "Private", +} + +const ( + TypePrimative = 0 // xx0xxxxxb + TypeConstructed = 32 // xx1xxxxxb + TypeBitmask = 32 // xx1xxxxxb +) + +var TypeMap = map[uint8] string { + TypePrimative : "Primative", + TypeConstructed : "Constructed", +} + +var Debug bool = false + +func PrintBytes( buf []byte, indent string ) { + data_lines := make( []string, ( len( buf ) / 30 ) + 1 ) + num_lines := make( []string, ( len( buf ) / 30 ) + 1 ) + + for i, b := range buf { + data_lines[ i / 30 ] += fmt.Sprintf( "%02x ", b ) + num_lines[ i / 30 ] += fmt.Sprintf( "%02d ", ( i + 1 ) % 100 ) + } + + for i := 0; i < len( data_lines ); i++ { + fmt.Print( indent + data_lines[ i ] + "\n" ) + fmt.Print( indent + num_lines[ i ] + "\n\n" ) + } +} + +func PrintPacket( p *Packet ) { + printPacket( p, 0, false ) +} + +func printPacket( p *Packet, indent int, printBytes bool ) { + indent_str := "" + for len(indent_str) != indent { + indent_str += " " + } + + class_str := ClassMap[ p.ClassType ] + tagtype_str := TypeMap[ p.TagType ] + tag_str := fmt.Sprintf( "0x%02X", p.Tag ) + + if p.ClassType == ClassUniversal { + tag_str = TagMap[ p.Tag ] + } + + value := fmt.Sprint( p.Value ) + description := "" + if p.Description != "" { + description = p.Description + ": " + } + + fmt.Printf( "%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value ) + + if printBytes { + PrintBytes( p.Bytes(), indent_str ) + } + + for _, child := range p.Children { + printPacket( child, indent + 1, printBytes ) + } +} + +func resizeBuffer( in []byte, new_size uint64 ) (out []byte) { + out = make( []byte, new_size ) + copy( out, in ) + return +} + +func readBytes( reader io.Reader, buf []byte ) os.Error { + idx := 0 + buflen := len( buf ) + for idx < buflen { + n, err := reader.Read( buf[ idx: ] ) + if err != nil { + return err + } + idx += n + } + return nil +} + +func ReadPacket( reader io.Reader ) ( *Packet, os.Error) { + buf := make([]byte, 2) + err := readBytes( reader, buf ) + if err != nil { + return nil, err + } + idx := uint64(2) + datalen := uint64(buf[1]) + if Debug { + fmt.Printf( "Read: datalen = %d len(buf) = %d ", datalen, len( buf ) ) + for _, b := range buf { + fmt.Printf( "%02X ", b ) + } + fmt.Printf( "\n" ) + } + if datalen & 128 != 0 { + a := datalen - 128 + idx += a + buf = resizeBuffer( buf, 2 + a ) + err := readBytes( reader, buf[2:] ) + if err != nil { + return nil, err + } + datalen = DecodeInteger( buf[ 2:2+a ] ) + if Debug { + fmt.Printf( "Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len( buf ) ) + for _, b := range buf { + fmt.Printf( "%02X ", b ) + } + fmt.Printf( "\n" ) + } + } + + buf = resizeBuffer( buf, idx + datalen ) + err = readBytes( reader, buf[idx:] ) + if err != nil { + return nil, err + } + + if Debug { + fmt.Printf( "Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len( buf ), idx, datalen, idx + datalen ) + for _, b := range buf { + fmt.Printf( "%02X ", b ) + } + } + + p := DecodePacket( buf ) + return p, nil +} + +func DecodeString( data []byte ) (ret string) { + for _, c := range data { + ret += fmt.Sprintf( "%c", c ) + } + return +} + +func DecodeInteger( data []byte ) (ret uint64) { + for _, i := range data { + ret = ret * 256 + ret = ret + uint64(i) + } + return +} + +func EncodeInteger( val uint64 ) []byte { + var out bytes.Buffer + found := false + shift := uint(56) + mask := uint64(0xFF00000000000000) + for mask > 0 { + if !found && ( val & mask != 0 ) { + found = true + } + if found || ( shift == 0 ) { + out.Write( []byte { byte( ( val & mask ) >> shift ) } ) + } + shift -= 8 + mask = mask >> 8 + } + return out.Bytes() +} + +func DecodePacket( data []byte ) *Packet { + p, _ := decodePacket( data ) + return p +} + +func decodePacket( data []byte ) (*Packet, []byte) { + if Debug { + fmt.Printf( "decodePacket: enter %d\n", len( data ) ) + } + p := new( Packet ) + p.ClassType = data[0] & ClassBitmask + p.TagType = data[0] & TypeBitmask + p.Tag = data[0] & TagBitmask + + datalen := DecodeInteger( data[1:2] ) + datapos := uint64(2) + if datalen & 128 != 0 { + datalen -= 128 + datapos += datalen + datalen = DecodeInteger( data[2:2+datalen] ) + } + + p.Data = new( bytes.Buffer ) + p.Children = make( []*Packet, 0, 2 ) + p.Value = nil + + value_data := data[datapos:datapos+datalen] + + if p.TagType == TypeConstructed { + for len( value_data ) != 0 { + var child *Packet + child, value_data = decodePacket( value_data ) + p.AppendChild( child ) + } + } else if p.ClassType == ClassUniversal { + p.Data.Write( data[datapos:datapos+datalen] ) + switch p.Tag { + case TagEOC: + case TagBoolean: + val := DecodeInteger( value_data ) + p.Value = val != 0 + case TagInteger: + p.Value = DecodeInteger( value_data ) + case TagBitString: + case TagOctetString: + p.Value = DecodeString( value_data ) + case TagNULL: + case TagObjectIdentifier: + case TagObjectDescriptor: + case TagExternal: + case TagRealFloat: + case TagEnumerated: + p.Value = DecodeInteger( value_data ) + case TagEmbeddedPDV: + case TagUTF8String: + case TagRelativeOID: + case TagSequence: + case TagSet: + case TagNumericString: + case TagPrintableString: + p.Value = DecodeString( value_data ) + case TagT61String: + case TagVideotexString: + case TagIA5String: + case TagUTCTime: + case TagGeneralizedTime: + case TagGraphicString: + case TagVisibleString: + case TagGeneralString: + case TagUniversalString: + case TagCharacterString: + case TagBMPString: + } + } else { + p.Data.Write( data[datapos:datapos+datalen] ) + } + + return p, data[ datapos + datalen: ] +} + +func (p *Packet) DataLength() uint64 { + return uint64( p.Data.Len() ) +} + +func (p *Packet) Bytes() []byte { + var out bytes.Buffer + out.Write( []byte { p.ClassType | p.TagType | p.Tag } ) + packet_length := EncodeInteger( p.DataLength() ) + if len( packet_length ) > 1 { + out.Write( []byte { byte( len( packet_length ) | 128 ) } ) + out.Write( packet_length ) + } else { + out.Write( packet_length ) + } + out.Write( p.Data.Bytes() ) + return out.Bytes() +} + +func (p *Packet) AppendChild( child *Packet ) { + p.Data.Write( child.Bytes() ) + if len( p.Children ) == cap( p.Children ) { + newChildren := make( []*Packet, cap( p.Children ) * 2 ) + copy( newChildren, p.Children ) + p.Children = newChildren[0:len(p.Children)] + } + p.Children = p.Children[ 0:len(p.Children) + 1 ] + p.Children[ len( p.Children ) - 1 ] = child +} + +func Encode( ClassType, TagType, Tag uint8, 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.NewValue(Value) + + if ( ClassType == ClassUniversal ) { + switch Tag { + case TagOctetString: + sv, ok := v.Interface().(string) + if ok { + p.Data.Write( []byte(sv) ) + } + } + } + } + + return p +} + +func NewSequence( Description string) *Packet { + return Encode( ClassUniversal, TypePrimative, TagSequence, nil, Description ) +} + +func NewBoolean( ClassType, TagType, Tag uint8, Value bool, Description string ) *Packet { + intValue := 0 + if Value { + intValue = 1 + } + + p := Encode( ClassType, TagType, Tag, nil, Description ) + p.Value = Value + p.Data.Write( EncodeInteger( uint64(intValue) ) ) + return p +} + +func NewInteger( ClassType, TagType, Tag uint8, Value uint64, Description string ) *Packet { + p := Encode( ClassType, TagType, Tag, nil, Description ) + p.Value = Value + p.Data.Write( EncodeInteger( Value ) ) + return p +} + +func NewString( ClassType, TagType, Tag uint8, Value, Description string ) *Packet { + p := Encode( ClassType, TagType, Tag, nil, Description ) + p.Value = Value + p.Data.Write( []byte( Value ) ) + return p +} + -- cgit v1.2.3 From 3df1c6c2807ff5258506c928cc3cb6862b704b39 Mon Sep 17 00:00:00 2001 From: Michael Mitton Date: Fri, 18 Feb 2011 13:15:48 -0500 Subject: Fixed encoding length --- ber.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ber.go b/ber.go index 5e2fc0d..058fd48 100644 --- a/ber.go +++ b/ber.go @@ -351,7 +351,7 @@ func (p *Packet) Bytes() []byte { var out bytes.Buffer out.Write( []byte { p.ClassType | p.TagType | p.Tag } ) packet_length := EncodeInteger( p.DataLength() ) - if len( packet_length ) > 1 { + if p.DataLength() > 127 || len( packet_length ) > 1 { out.Write( []byte { byte( len( packet_length ) | 128 ) } ) out.Write( packet_length ) } else { -- cgit v1.2.3 From 3cfe95df320857f7ec3f9fb9bc93e6e0eb273530 Mon Sep 17 00:00:00 2001 From: Brian Ollenberger Date: Wed, 19 Feb 2014 16:43:26 -0800 Subject: Create LICENSE --- LICENSE | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7448756 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- cgit v1.2.3 From 0f360d2339e0580e1a506ba69f0972e8ed80a90f Mon Sep 17 00:00:00 2001 From: Robin Harper Date: Thu, 27 Feb 2014 16:32:03 -0500 Subject: Updated references to error --- ber.go | 566 ++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 282 insertions(+), 284 deletions(-) diff --git a/ber.go b/ber.go index 058fd48..31c43bd 100644 --- a/ber.go +++ b/ber.go @@ -3,19 +3,18 @@ package ber import ( "bytes" "fmt" - "io" - "os" + "io" "reflect" ) type Packet struct { - ClassType uint8 - TagType uint8 - Tag uint8 - Value interface{} - Data *bytes.Buffer - Children []*Packet - Description string + ClassType uint8 + TagType uint8 + Tag uint8 + Value interface{} + Data *bytes.Buffer + Children []*Packet + Description string } const ( @@ -51,211 +50,211 @@ const ( TagBitmask = 0x1f // xxx11111b ) -var TagMap = map[uint8] 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", +var TagMap = map[uint8]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", } const ( - ClassUniversal = 0 // 00xxxxxxb - ClassApplication = 64 // 01xxxxxxb - ClassContext = 128 // 10xxxxxxb - ClassPrivate = 192 // 11xxxxxxb - ClassBitmask = 192 // 11xxxxxxb + ClassUniversal = 0 // 00xxxxxxb + ClassApplication = 64 // 01xxxxxxb + ClassContext = 128 // 10xxxxxxb + ClassPrivate = 192 // 11xxxxxxb + ClassBitmask = 192 // 11xxxxxxb ) -var ClassMap = map[uint8] string { - ClassUniversal : "Universal", - ClassApplication : "Application", - ClassContext : "Context", - ClassPrivate : "Private", +var ClassMap = map[uint8]string{ + ClassUniversal: "Universal", + ClassApplication: "Application", + ClassContext: "Context", + ClassPrivate: "Private", } const ( - TypePrimative = 0 // xx0xxxxxb - TypeConstructed = 32 // xx1xxxxxb - TypeBitmask = 32 // xx1xxxxxb + TypePrimative = 0 // xx0xxxxxb + TypeConstructed = 32 // xx1xxxxxb + TypeBitmask = 32 // xx1xxxxxb ) -var TypeMap = map[uint8] string { - TypePrimative : "Primative", - TypeConstructed : "Constructed", +var TypeMap = map[uint8]string{ + TypePrimative: "Primative", + TypeConstructed: "Constructed", } var Debug bool = false -func PrintBytes( buf []byte, indent string ) { - data_lines := make( []string, ( len( buf ) / 30 ) + 1 ) - num_lines := make( []string, ( len( buf ) / 30 ) + 1 ) +func PrintBytes(buf []byte, indent string) { + data_lines := make([]string, (len(buf)/30)+1) + num_lines := make([]string, (len(buf)/30)+1) - for i, b := range buf { - data_lines[ i / 30 ] += fmt.Sprintf( "%02x ", b ) - num_lines[ i / 30 ] += fmt.Sprintf( "%02d ", ( i + 1 ) % 100 ) - } + for i, b := range buf { + data_lines[i/30] += fmt.Sprintf("%02x ", b) + num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100) + } - for i := 0; i < len( data_lines ); i++ { - fmt.Print( indent + data_lines[ i ] + "\n" ) - fmt.Print( indent + num_lines[ i ] + "\n\n" ) - } + for i := 0; i < len(data_lines); i++ { + fmt.Print(indent + data_lines[i] + "\n") + fmt.Print(indent + num_lines[i] + "\n\n") + } } -func PrintPacket( p *Packet ) { - printPacket( p, 0, false ) +func PrintPacket(p *Packet) { + printPacket(p, 0, false) } -func printPacket( p *Packet, indent int, printBytes bool ) { +func printPacket(p *Packet, indent int, printBytes bool) { indent_str := "" for len(indent_str) != indent { indent_str += " " } - class_str := ClassMap[ p.ClassType ] - tagtype_str := TypeMap[ p.TagType ] - tag_str := fmt.Sprintf( "0x%02X", p.Tag ) + class_str := ClassMap[p.ClassType] + tagtype_str := TypeMap[p.TagType] + tag_str := fmt.Sprintf("0x%02X", p.Tag) - if p.ClassType == ClassUniversal { - tag_str = TagMap[ p.Tag ] - } + if p.ClassType == ClassUniversal { + tag_str = TagMap[p.Tag] + } - value := fmt.Sprint( p.Value ) - description := "" - if p.Description != "" { - description = p.Description + ": " - } + value := fmt.Sprint(p.Value) + description := "" + if p.Description != "" { + description = p.Description + ": " + } - fmt.Printf( "%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value ) + fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value) - if printBytes { - PrintBytes( p.Bytes(), indent_str ) - } + if printBytes { + PrintBytes(p.Bytes(), indent_str) + } - for _, child := range p.Children { - printPacket( child, indent + 1, printBytes ) - } + for _, child := range p.Children { + printPacket(child, indent+1, printBytes) + } } -func resizeBuffer( in []byte, new_size uint64 ) (out []byte) { - out = make( []byte, new_size ) - copy( out, in ) - return +func resizeBuffer(in []byte, new_size uint64) (out []byte) { + out = make([]byte, new_size) + copy(out, in) + return } -func readBytes( reader io.Reader, buf []byte ) os.Error { - idx := 0 - buflen := len( buf ) - for idx < buflen { - n, err := reader.Read( buf[ idx: ] ) - if err != nil { - return err - } - idx += n - } - return nil +func readBytes(reader io.Reader, buf []byte) error { + idx := 0 + buflen := len(buf) + for idx < buflen { + n, err := reader.Read(buf[idx:]) + if err != nil { + return err + } + idx += n + } + return nil } -func ReadPacket( reader io.Reader ) ( *Packet, os.Error) { - buf := make([]byte, 2) - err := readBytes( reader, buf ) - if err != nil { - return nil, err - } - idx := uint64(2) - datalen := uint64(buf[1]) - if Debug { - fmt.Printf( "Read: datalen = %d len(buf) = %d ", datalen, len( buf ) ) - for _, b := range buf { - fmt.Printf( "%02X ", b ) - } - fmt.Printf( "\n" ) - } - if datalen & 128 != 0 { - a := datalen - 128 - idx += a - buf = resizeBuffer( buf, 2 + a ) - err := readBytes( reader, buf[2:] ) - if err != nil { - return nil, err - } - datalen = DecodeInteger( buf[ 2:2+a ] ) - if Debug { - fmt.Printf( "Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len( buf ) ) - for _, b := range buf { - fmt.Printf( "%02X ", b ) - } - fmt.Printf( "\n" ) - } - } - - buf = resizeBuffer( buf, idx + datalen ) - err = readBytes( reader, buf[idx:] ) - if err != nil { - return nil, err - } - - if Debug { - fmt.Printf( "Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len( buf ), idx, datalen, idx + datalen ) - for _, b := range buf { - fmt.Printf( "%02X ", b ) - } - } - - p := DecodePacket( buf ) - return p, nil +func ReadPacket(reader io.Reader) (*Packet, error) { + buf := make([]byte, 2) + err := readBytes(reader, buf) + if err != nil { + return nil, err + } + idx := uint64(2) + datalen := uint64(buf[1]) + if Debug { + fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf)) + for _, b := range buf { + fmt.Printf("%02X ", b) + } + fmt.Printf("\n") + } + if datalen&128 != 0 { + a := datalen - 128 + idx += a + buf = resizeBuffer(buf, 2+a) + err := readBytes(reader, buf[2:]) + if err != nil { + return nil, err + } + datalen = DecodeInteger(buf[2 : 2+a]) + if Debug { + fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf)) + for _, b := range buf { + fmt.Printf("%02X ", b) + } + fmt.Printf("\n") + } + } + + buf = resizeBuffer(buf, idx+datalen) + err = readBytes(reader, buf[idx:]) + if err != nil { + return nil, err + } + + if Debug { + fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen) + for _, b := range buf { + fmt.Printf("%02X ", b) + } + } + + p := DecodePacket(buf) + return p, nil } -func DecodeString( data []byte ) (ret string) { - for _, c := range data { - ret += fmt.Sprintf( "%c", c ) +func DecodeString(data []byte) (ret string) { + for _, c := range data { + ret += fmt.Sprintf("%c", c) } return } -func DecodeInteger( data []byte ) (ret uint64) { - for _, i := range data { +func DecodeInteger(data []byte) (ret uint64) { + for _, i := range data { ret = ret * 256 ret = ret + uint64(i) } return } -func EncodeInteger( val uint64 ) []byte { +func EncodeInteger(val uint64) []byte { var out bytes.Buffer found := false shift := uint(56) mask := uint64(0xFF00000000000000) for mask > 0 { - if !found && ( val & mask != 0 ) { + if !found && (val&mask != 0) { found = true } - if found || ( shift == 0 ) { - out.Write( []byte { byte( ( val & mask ) >> shift ) } ) + if found || (shift == 0) { + out.Write([]byte{byte((val & mask) >> shift)}) } shift -= 8 mask = mask >> 8 @@ -263,135 +262,135 @@ func EncodeInteger( val uint64 ) []byte { return out.Bytes() } -func DecodePacket( data []byte ) *Packet { - p, _ := decodePacket( data ) - return p +func DecodePacket(data []byte) *Packet { + p, _ := decodePacket(data) + return p } -func decodePacket( data []byte ) (*Packet, []byte) { - if Debug { - fmt.Printf( "decodePacket: enter %d\n", len( data ) ) - } - p := new( Packet ) - p.ClassType = data[0] & ClassBitmask - p.TagType = data[0] & TypeBitmask - p.Tag = data[0] & TagBitmask - - datalen := DecodeInteger( data[1:2] ) - datapos := uint64(2) - if datalen & 128 != 0 { - datalen -= 128 - datapos += datalen - datalen = DecodeInteger( data[2:2+datalen] ) - } - - p.Data = new( bytes.Buffer ) - p.Children = make( []*Packet, 0, 2 ) - p.Value = nil - - value_data := data[datapos:datapos+datalen] - - if p.TagType == TypeConstructed { - for len( value_data ) != 0 { - var child *Packet - child, value_data = decodePacket( value_data ) - p.AppendChild( child ) - } - } else if p.ClassType == ClassUniversal { - p.Data.Write( data[datapos:datapos+datalen] ) +func decodePacket(data []byte) (*Packet, []byte) { + if Debug { + fmt.Printf("decodePacket: enter %d\n", len(data)) + } + p := new(Packet) + p.ClassType = data[0] & ClassBitmask + p.TagType = data[0] & TypeBitmask + p.Tag = data[0] & TagBitmask + + datalen := DecodeInteger(data[1:2]) + datapos := uint64(2) + if datalen&128 != 0 { + datalen -= 128 + datapos += datalen + datalen = DecodeInteger(data[2 : 2+datalen]) + } + + p.Data = new(bytes.Buffer) + p.Children = make([]*Packet, 0, 2) + p.Value = nil + + value_data := data[datapos : datapos+datalen] + + if p.TagType == TypeConstructed { + for len(value_data) != 0 { + var child *Packet + child, value_data = decodePacket(value_data) + p.AppendChild(child) + } + } else if p.ClassType == ClassUniversal { + p.Data.Write(data[datapos : datapos+datalen]) switch p.Tag { - case TagEOC: - case TagBoolean: - val := DecodeInteger( value_data ) - p.Value = val != 0 - case TagInteger: - p.Value = DecodeInteger( value_data ) - case TagBitString: - case TagOctetString: - p.Value = DecodeString( value_data ) - case TagNULL: - case TagObjectIdentifier: - case TagObjectDescriptor: - case TagExternal: - case TagRealFloat: - case TagEnumerated: - p.Value = DecodeInteger( value_data ) - case TagEmbeddedPDV: - case TagUTF8String: - case TagRelativeOID: - case TagSequence: - case TagSet: - case TagNumericString: - case TagPrintableString: - p.Value = DecodeString( value_data ) - case TagT61String: - case TagVideotexString: - case TagIA5String: - case TagUTCTime: - case TagGeneralizedTime: - case TagGraphicString: - case TagVisibleString: - case TagGeneralString: - case TagUniversalString: - case TagCharacterString: - case TagBMPString: + case TagEOC: + case TagBoolean: + val := DecodeInteger(value_data) + p.Value = val != 0 + case TagInteger: + p.Value = DecodeInteger(value_data) + case TagBitString: + case TagOctetString: + p.Value = DecodeString(value_data) + case TagNULL: + case TagObjectIdentifier: + case TagObjectDescriptor: + case TagExternal: + case TagRealFloat: + case TagEnumerated: + p.Value = DecodeInteger(value_data) + case TagEmbeddedPDV: + case TagUTF8String: + case TagRelativeOID: + case TagSequence: + case TagSet: + case TagNumericString: + case TagPrintableString: + p.Value = DecodeString(value_data) + case TagT61String: + case TagVideotexString: + case TagIA5String: + case TagUTCTime: + case TagGeneralizedTime: + case TagGraphicString: + case TagVisibleString: + case TagGeneralString: + case TagUniversalString: + case TagCharacterString: + case TagBMPString: } - } else { - p.Data.Write( data[datapos:datapos+datalen] ) - } + } else { + p.Data.Write(data[datapos : datapos+datalen]) + } - return p, data[ datapos + datalen: ] + return p, data[datapos+datalen:] } func (p *Packet) DataLength() uint64 { - return uint64( p.Data.Len() ) + return uint64(p.Data.Len()) } func (p *Packet) Bytes() []byte { var out bytes.Buffer - out.Write( []byte { p.ClassType | p.TagType | p.Tag } ) - packet_length := EncodeInteger( p.DataLength() ) - if p.DataLength() > 127 || len( packet_length ) > 1 { - out.Write( []byte { byte( len( packet_length ) | 128 ) } ) - out.Write( packet_length ) + out.Write([]byte{p.ClassType | p.TagType | p.Tag}) + packet_length := EncodeInteger(p.DataLength()) + if p.DataLength() > 127 || len(packet_length) > 1 { + out.Write([]byte{byte(len(packet_length) | 128)}) + out.Write(packet_length) } else { - out.Write( packet_length ) + out.Write(packet_length) } - out.Write( p.Data.Bytes() ) + out.Write(p.Data.Bytes()) return out.Bytes() } -func (p *Packet) AppendChild( child *Packet ) { - p.Data.Write( child.Bytes() ) - if len( p.Children ) == cap( p.Children ) { - newChildren := make( []*Packet, cap( p.Children ) * 2 ) - copy( newChildren, p.Children ) - p.Children = newChildren[0:len(p.Children)] - } - p.Children = p.Children[ 0:len(p.Children) + 1 ] - p.Children[ len( p.Children ) - 1 ] = child +func (p *Packet) AppendChild(child *Packet) { + p.Data.Write(child.Bytes()) + if len(p.Children) == cap(p.Children) { + newChildren := make([]*Packet, cap(p.Children)*2) + copy(newChildren, p.Children) + p.Children = newChildren[0:len(p.Children)] + } + p.Children = p.Children[0 : len(p.Children)+1] + p.Children[len(p.Children)-1] = child } -func Encode( ClassType, TagType, Tag uint8, Value interface{}, Description string ) *Packet { - p := new( Packet ) +func Encode(ClassType, TagType, Tag uint8, 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 + p.Data = new(bytes.Buffer) + p.Children = make([]*Packet, 0, 2) + p.Value = Value + p.Description = Description if Value != nil { - v := reflect.NewValue(Value) + v := reflect.ValueOf(Value) - if ( ClassType == ClassUniversal ) { + if ClassType == ClassUniversal { switch Tag { - case TagOctetString: - sv, ok := v.Interface().(string) - if ok { - p.Data.Write( []byte(sv) ) - } + case TagOctetString: + sv, ok := v.Interface().(string) + if ok { + p.Data.Write([]byte(sv)) + } } } } @@ -399,33 +398,32 @@ func Encode( ClassType, TagType, Tag uint8, Value interface{}, Description strin return p } -func NewSequence( Description string) *Packet { - return Encode( ClassUniversal, TypePrimative, TagSequence, nil, Description ) +func NewSequence(Description string) *Packet { + return Encode(ClassUniversal, TypePrimative, TagSequence, nil, Description) } -func NewBoolean( ClassType, TagType, Tag uint8, Value bool, Description string ) *Packet { - intValue := 0 - if Value { - intValue = 1 - } +func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet { + intValue := 0 + if Value { + intValue = 1 + } - p := Encode( ClassType, TagType, Tag, nil, Description ) - p.Value = Value - p.Data.Write( EncodeInteger( uint64(intValue) ) ) - return p + p := Encode(ClassType, TagType, Tag, nil, Description) + p.Value = Value + p.Data.Write(EncodeInteger(uint64(intValue))) + return p } -func NewInteger( ClassType, TagType, Tag uint8, Value uint64, Description string ) *Packet { - p := Encode( ClassType, TagType, Tag, nil, Description ) - p.Value = Value - p.Data.Write( EncodeInteger( Value ) ) - return p +func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet { + p := Encode(ClassType, TagType, Tag, nil, Description) + p.Value = Value + p.Data.Write(EncodeInteger(Value)) + return p } -func NewString( ClassType, TagType, Tag uint8, Value, Description string ) *Packet { - p := Encode( ClassType, TagType, Tag, nil, Description ) - p.Value = Value - p.Data.Write( []byte( Value ) ) - return p +func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet { + p := Encode(ClassType, TagType, Tag, nil, Description) + p.Value = Value + p.Data.Write([]byte(Value)) + return p } - -- cgit v1.2.3 From 375661f7291d03e1fca2c386b0412f31c2060fe9 Mon Sep 17 00:00:00 2001 From: Robin Harper Date: Thu, 13 Mar 2014 12:46:49 -0400 Subject: Add support for transporting the raw byte value --- ber.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ber.go b/ber.go index 31c43bd..f670f8f 100644 --- a/ber.go +++ b/ber.go @@ -12,6 +12,7 @@ type Packet struct { TagType uint8 Tag uint8 Value interface{} + ByteValue []byte Data *bytes.Buffer Children []*Packet Description string @@ -298,6 +299,8 @@ func decodePacket(data []byte) (*Packet, []byte) { } } else if p.ClassType == ClassUniversal { p.Data.Write(data[datapos : datapos+datalen]) + p.ByteValue = value_data + switch p.Tag { case TagEOC: case TagBoolean: -- cgit v1.2.3 From 678acb985fa28726ab4bed6ea7eccbeada6b0ff0 Mon Sep 17 00:00:00 2001 From: Robin Harper Date: Mon, 14 Apr 2014 14:56:15 -0400 Subject: Style format update --- ber.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/ber.go b/ber.go index f670f8f..cd11c8f 100644 --- a/ber.go +++ b/ber.go @@ -132,12 +132,15 @@ func PrintPacket(p *Packet) { func printPacket(p *Packet, indent int, printBytes bool) { indent_str := "" + for len(indent_str) != indent { indent_str += " " } class_str := ClassMap[p.ClassType] + tagtype_str := TypeMap[p.TagType] + tag_str := fmt.Sprintf("0x%02X", p.Tag) if p.ClassType == ClassUniversal { @@ -146,6 +149,7 @@ func printPacket(p *Packet, indent int, printBytes bool) { value := fmt.Sprint(p.Value) description := "" + if p.Description != "" { description = p.Description + ": " } @@ -163,13 +167,16 @@ func printPacket(p *Packet, indent int, printBytes bool) { func resizeBuffer(in []byte, new_size uint64) (out []byte) { out = make([]byte, new_size) + copy(out, in) + return } func readBytes(reader io.Reader, buf []byte) error { idx := 0 buflen := len(buf) + for idx < buflen { n, err := reader.Read(buf[idx:]) if err != nil { @@ -177,56 +184,74 @@ func readBytes(reader io.Reader, buf []byte) error { } idx += n } + return nil } func ReadPacket(reader io.Reader) (*Packet, error) { buf := make([]byte, 2) + err := readBytes(reader, buf) + if err != nil { return nil, err } + idx := uint64(2) datalen := uint64(buf[1]) + if Debug { fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf)) + for _, b := range buf { fmt.Printf("%02X ", b) } + fmt.Printf("\n") } + if datalen&128 != 0 { a := datalen - 128 + idx += a buf = resizeBuffer(buf, 2+a) + err := readBytes(reader, buf[2:]) + if err != nil { return nil, err } + datalen = DecodeInteger(buf[2 : 2+a]) + if Debug { fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf)) + for _, b := range buf { fmt.Printf("%02X ", b) } + fmt.Printf("\n") } } buf = resizeBuffer(buf, idx+datalen) err = readBytes(reader, buf[idx:]) + if err != nil { return nil, err } if Debug { fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen) + for _, b := range buf { fmt.Printf("%02X ", b) } } p := DecodePacket(buf) + return p, nil } @@ -234,6 +259,7 @@ func DecodeString(data []byte) (ret string) { for _, c := range data { ret += fmt.Sprintf("%c", c) } + return } @@ -242,29 +268,38 @@ func DecodeInteger(data []byte) (ret uint64) { ret = ret * 256 ret = ret + uint64(i) } + return } func EncodeInteger(val uint64) []byte { var out bytes.Buffer + found := false + shift := uint(56) + mask := uint64(0xFF00000000000000) + for mask > 0 { if !found && (val&mask != 0) { found = true } + if found || (shift == 0) { out.Write([]byte{byte((val & mask) >> shift)}) } + shift -= 8 mask = mask >> 8 } + return out.Bytes() } func DecodePacket(data []byte) *Packet { p, _ := decodePacket(data) + return p } @@ -272,13 +307,16 @@ func decodePacket(data []byte) (*Packet, []byte) { if Debug { fmt.Printf("decodePacket: enter %d\n", len(data)) } + p := new(Packet) + p.ClassType = data[0] & ClassBitmask p.TagType = data[0] & TypeBitmask p.Tag = data[0] & TagBitmask datalen := DecodeInteger(data[1:2]) datapos := uint64(2) + if datalen&128 != 0 { datalen -= 128 datapos += datalen @@ -286,7 +324,9 @@ func decodePacket(data []byte) (*Packet, []byte) { } p.Data = new(bytes.Buffer) + p.Children = make([]*Packet, 0, 2) + p.Value = nil value_data := data[datapos : datapos+datalen] @@ -294,6 +334,7 @@ func decodePacket(data []byte) (*Packet, []byte) { if p.TagType == TypeConstructed { for len(value_data) != 0 { var child *Packet + child, value_data = decodePacket(value_data) p.AppendChild(child) } @@ -305,6 +346,7 @@ func decodePacket(data []byte) (*Packet, []byte) { case TagEOC: case TagBoolean: val := DecodeInteger(value_data) + p.Value = val != 0 case TagInteger: p.Value = DecodeInteger(value_data) @@ -351,36 +393,46 @@ func (p *Packet) DataLength() uint64 { func (p *Packet) Bytes() []byte { var out bytes.Buffer + out.Write([]byte{p.ClassType | p.TagType | p.Tag}) packet_length := EncodeInteger(p.DataLength()) + if p.DataLength() > 127 || len(packet_length) > 1 { out.Write([]byte{byte(len(packet_length) | 128)}) out.Write(packet_length) } else { out.Write(packet_length) } + out.Write(p.Data.Bytes()) + return out.Bytes() } func (p *Packet) AppendChild(child *Packet) { p.Data.Write(child.Bytes()) + if len(p.Children) == cap(p.Children) { newChildren := make([]*Packet, cap(p.Children)*2) + copy(newChildren, p.Children) p.Children = newChildren[0:len(p.Children)] } + p.Children = p.Children[0 : len(p.Children)+1] p.Children[len(p.Children)-1] = child } func Encode(ClassType, TagType, Tag uint8, 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 @@ -391,6 +443,7 @@ func Encode(ClassType, TagType, Tag uint8, Value interface{}, Description string switch Tag { case TagOctetString: sv, ok := v.Interface().(string) + if ok { p.Data.Write([]byte(sv)) } @@ -407,26 +460,33 @@ func NewSequence(Description string) *Packet { func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet { intValue := 0 + if Value { intValue = 1 } p := Encode(ClassType, TagType, Tag, nil, Description) + p.Value = Value p.Data.Write(EncodeInteger(uint64(intValue))) + return p } func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet { p := Encode(ClassType, TagType, Tag, nil, Description) + p.Value = Value p.Data.Write(EncodeInteger(Value)) + return p } func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet { p := Encode(ClassType, TagType, Tag, nil, Description) + p.Value = Value p.Data.Write([]byte(Value)) + return p } -- cgit v1.2.3 From ec51d5ed21377b4023ca7b1e70ae4cb296ee6047 Mon Sep 17 00:00:00 2001 From: John Weldon Date: Tue, 15 Apr 2014 18:04:59 -0700 Subject: fix typo --- ber.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ber.go b/ber.go index cd11c8f..3e99a27 100644 --- a/ber.go +++ b/ber.go @@ -99,13 +99,13 @@ var ClassMap = map[uint8]string{ } const ( - TypePrimative = 0 // xx0xxxxxb + TypePrimitive = 0 // xx0xxxxxb TypeConstructed = 32 // xx1xxxxxb TypeBitmask = 32 // xx1xxxxxb ) var TypeMap = map[uint8]string{ - TypePrimative: "Primative", + TypePrimitive: "Primative", TypeConstructed: "Constructed", } @@ -455,7 +455,7 @@ func Encode(ClassType, TagType, Tag uint8, Value interface{}, Description string } func NewSequence(Description string) *Packet { - return Encode(ClassUniversal, TypePrimative, TagSequence, nil, Description) + return Encode(ClassUniversal, TypePrimitive, TagSequence, nil, Description) } func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet { -- cgit v1.2.3 From 43e530dce9a3833c7fdcbf527b757581e5e37657 Mon Sep 17 00:00:00 2001 From: Michael Grosshans Date: Tue, 3 Jan 2017 16:34:35 +0100 Subject: Fixed String Decoding --- ber.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ber.go b/ber.go index 3e99a27..5f95e0a 100644 --- a/ber.go +++ b/ber.go @@ -255,12 +255,8 @@ func ReadPacket(reader io.Reader) (*Packet, error) { return p, nil } -func DecodeString(data []byte) (ret string) { - for _, c := range data { - ret += fmt.Sprintf("%c", c) - } - - return +func DecodeString(data []byte) (string) { + return string(data) } func DecodeInteger(data []byte) (ret uint64) { -- cgit v1.2.3 From e8fcb80412352832e63f8a5859687729d358461b Mon Sep 17 00:00:00 2001 From: Michael Grosshans Date: Wed, 4 Jan 2017 15:23:38 +0100 Subject: Fixed problem with message 128 --- ber.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ber.go b/ber.go index 5f95e0a..95755fe 100644 --- a/ber.go +++ b/ber.go @@ -290,7 +290,14 @@ func EncodeInteger(val uint64) []byte { mask = mask >> 8 } - return out.Bytes() + byteSlice := out.Bytes() + + // if first bit in first byte is 1 it is necessary to append a leading 00 byte to make signum clear + // otherwise it happens that a request with messageId => 02 01 80 get response with messageId => 02 04 FF FF FF 80 + if len(byteSlice) > 0 && byteSlice[0]&byte(128) != 0 { + return append([]byte{0x00}, byteSlice...) + } + return byteSlice } func DecodePacket(data []byte) *Packet { -- cgit v1.2.3 From db0060239d6bf2085534d5cdb4a0790df88f1000 Mon Sep 17 00:00:00 2001 From: Mark Rushakoff Date: Fri, 23 Feb 2018 08:44:13 -0800 Subject: Move ber package to internal In order to not have an external dependency in the ldapserver repo. --- LICENSE | 27 --- Makefile | 11 - README | 14 -- ber.go | 495 --------------------------------------------- internal/asn1-ber/LICENSE | 27 +++ internal/asn1-ber/Makefile | 11 + internal/asn1-ber/README | 14 ++ internal/asn1-ber/ber.go | 495 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 547 insertions(+), 547 deletions(-) delete mode 100644 LICENSE delete mode 100644 Makefile delete mode 100644 README delete mode 100644 ber.go create mode 100644 internal/asn1-ber/LICENSE create mode 100644 internal/asn1-ber/Makefile create mode 100644 internal/asn1-ber/README create mode 100644 internal/asn1-ber/ber.go diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 7448756..0000000 --- a/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile deleted file mode 100644 index acda29a..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include $(GOROOT)/src/Make.inc - -TARG=github.com/mmitton/asn1-ber -GOFILES=\ - ber.go\ - -include $(GOROOT)/src/Make.pkg diff --git a/README b/README deleted file mode 100644 index bb785a0..0000000 --- a/README +++ /dev/null @@ -1,14 +0,0 @@ -ASN1 BER Encoding / Decoding Library for the GO programming language. - -Required Librarys: - None - -Working: - Very basic encoding / decoding needed for LDAP protocol - -Tests Implemented: - None - -TODO: - Fix all encoding / decoding to conform to ASN1 BER spec - Implement Tests / Benchmarks diff --git a/ber.go b/ber.go deleted file mode 100644 index 95755fe..0000000 --- a/ber.go +++ /dev/null @@ -1,495 +0,0 @@ -package ber - -import ( - "bytes" - "fmt" - "io" - "reflect" -) - -type Packet struct { - ClassType uint8 - TagType uint8 - Tag uint8 - Value interface{} - ByteValue []byte - Data *bytes.Buffer - Children []*Packet - Description string -} - -const ( - TagEOC = 0x00 - TagBoolean = 0x01 - TagInteger = 0x02 - TagBitString = 0x03 - TagOctetString = 0x04 - TagNULL = 0x05 - TagObjectIdentifier = 0x06 - TagObjectDescriptor = 0x07 - TagExternal = 0x08 - TagRealFloat = 0x09 - TagEnumerated = 0x0a - TagEmbeddedPDV = 0x0b - TagUTF8String = 0x0c - TagRelativeOID = 0x0d - TagSequence = 0x10 - TagSet = 0x11 - TagNumericString = 0x12 - TagPrintableString = 0x13 - TagT61String = 0x14 - TagVideotexString = 0x15 - TagIA5String = 0x16 - TagUTCTime = 0x17 - TagGeneralizedTime = 0x18 - TagGraphicString = 0x19 - TagVisibleString = 0x1a - TagGeneralString = 0x1b - TagUniversalString = 0x1c - TagCharacterString = 0x1d - TagBMPString = 0x1e - TagBitmask = 0x1f // xxx11111b -) - -var TagMap = map[uint8]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", -} - -const ( - ClassUniversal = 0 // 00xxxxxxb - ClassApplication = 64 // 01xxxxxxb - ClassContext = 128 // 10xxxxxxb - ClassPrivate = 192 // 11xxxxxxb - ClassBitmask = 192 // 11xxxxxxb -) - -var ClassMap = map[uint8]string{ - ClassUniversal: "Universal", - ClassApplication: "Application", - ClassContext: "Context", - ClassPrivate: "Private", -} - -const ( - TypePrimitive = 0 // xx0xxxxxb - TypeConstructed = 32 // xx1xxxxxb - TypeBitmask = 32 // xx1xxxxxb -) - -var TypeMap = map[uint8]string{ - TypePrimitive: "Primative", - TypeConstructed: "Constructed", -} - -var Debug bool = false - -func PrintBytes(buf []byte, indent string) { - data_lines := make([]string, (len(buf)/30)+1) - num_lines := make([]string, (len(buf)/30)+1) - - for i, b := range buf { - data_lines[i/30] += fmt.Sprintf("%02x ", b) - num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100) - } - - for i := 0; i < len(data_lines); i++ { - fmt.Print(indent + data_lines[i] + "\n") - fmt.Print(indent + num_lines[i] + "\n\n") - } -} - -func PrintPacket(p *Packet) { - printPacket(p, 0, false) -} - -func printPacket(p *Packet, indent int, printBytes bool) { - indent_str := "" - - for len(indent_str) != indent { - indent_str += " " - } - - class_str := ClassMap[p.ClassType] - - tagtype_str := TypeMap[p.TagType] - - tag_str := fmt.Sprintf("0x%02X", p.Tag) - - if p.ClassType == ClassUniversal { - tag_str = TagMap[p.Tag] - } - - value := fmt.Sprint(p.Value) - description := "" - - if p.Description != "" { - description = p.Description + ": " - } - - fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value) - - if printBytes { - PrintBytes(p.Bytes(), indent_str) - } - - for _, child := range p.Children { - printPacket(child, indent+1, printBytes) - } -} - -func resizeBuffer(in []byte, new_size uint64) (out []byte) { - out = make([]byte, new_size) - - copy(out, in) - - return -} - -func readBytes(reader io.Reader, buf []byte) error { - idx := 0 - buflen := len(buf) - - for idx < buflen { - n, err := reader.Read(buf[idx:]) - if err != nil { - return err - } - idx += n - } - - return nil -} - -func ReadPacket(reader io.Reader) (*Packet, error) { - buf := make([]byte, 2) - - err := readBytes(reader, buf) - - if err != nil { - return nil, err - } - - idx := uint64(2) - datalen := uint64(buf[1]) - - if Debug { - fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf)) - - for _, b := range buf { - fmt.Printf("%02X ", b) - } - - fmt.Printf("\n") - } - - if datalen&128 != 0 { - a := datalen - 128 - - idx += a - buf = resizeBuffer(buf, 2+a) - - err := readBytes(reader, buf[2:]) - - if err != nil { - return nil, err - } - - datalen = DecodeInteger(buf[2 : 2+a]) - - if Debug { - fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf)) - - for _, b := range buf { - fmt.Printf("%02X ", b) - } - - fmt.Printf("\n") - } - } - - buf = resizeBuffer(buf, idx+datalen) - err = readBytes(reader, buf[idx:]) - - if err != nil { - return nil, err - } - - if Debug { - fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen) - - for _, b := range buf { - fmt.Printf("%02X ", b) - } - } - - p := DecodePacket(buf) - - return p, nil -} - -func DecodeString(data []byte) (string) { - return string(data) -} - -func DecodeInteger(data []byte) (ret uint64) { - for _, i := range data { - ret = ret * 256 - ret = ret + uint64(i) - } - - return -} - -func EncodeInteger(val uint64) []byte { - var out bytes.Buffer - - found := false - - shift := uint(56) - - mask := uint64(0xFF00000000000000) - - for mask > 0 { - if !found && (val&mask != 0) { - found = true - } - - if found || (shift == 0) { - out.Write([]byte{byte((val & mask) >> shift)}) - } - - shift -= 8 - mask = mask >> 8 - } - - byteSlice := out.Bytes() - - // if first bit in first byte is 1 it is necessary to append a leading 00 byte to make signum clear - // otherwise it happens that a request with messageId => 02 01 80 get response with messageId => 02 04 FF FF FF 80 - if len(byteSlice) > 0 && byteSlice[0]&byte(128) != 0 { - return append([]byte{0x00}, byteSlice...) - } - return byteSlice -} - -func DecodePacket(data []byte) *Packet { - p, _ := decodePacket(data) - - return p -} - -func decodePacket(data []byte) (*Packet, []byte) { - if Debug { - fmt.Printf("decodePacket: enter %d\n", len(data)) - } - - p := new(Packet) - - p.ClassType = data[0] & ClassBitmask - p.TagType = data[0] & TypeBitmask - p.Tag = data[0] & TagBitmask - - datalen := DecodeInteger(data[1:2]) - datapos := uint64(2) - - if datalen&128 != 0 { - datalen -= 128 - datapos += datalen - datalen = DecodeInteger(data[2 : 2+datalen]) - } - - p.Data = new(bytes.Buffer) - - p.Children = make([]*Packet, 0, 2) - - p.Value = nil - - value_data := data[datapos : datapos+datalen] - - if p.TagType == TypeConstructed { - for len(value_data) != 0 { - var child *Packet - - child, value_data = decodePacket(value_data) - p.AppendChild(child) - } - } else if p.ClassType == ClassUniversal { - p.Data.Write(data[datapos : datapos+datalen]) - p.ByteValue = value_data - - switch p.Tag { - case TagEOC: - case TagBoolean: - val := DecodeInteger(value_data) - - p.Value = val != 0 - case TagInteger: - p.Value = DecodeInteger(value_data) - case TagBitString: - case TagOctetString: - p.Value = DecodeString(value_data) - case TagNULL: - case TagObjectIdentifier: - case TagObjectDescriptor: - case TagExternal: - case TagRealFloat: - case TagEnumerated: - p.Value = DecodeInteger(value_data) - case TagEmbeddedPDV: - case TagUTF8String: - case TagRelativeOID: - case TagSequence: - case TagSet: - case TagNumericString: - case TagPrintableString: - p.Value = DecodeString(value_data) - case TagT61String: - case TagVideotexString: - case TagIA5String: - case TagUTCTime: - case TagGeneralizedTime: - case TagGraphicString: - case TagVisibleString: - case TagGeneralString: - case TagUniversalString: - case TagCharacterString: - case TagBMPString: - } - } else { - p.Data.Write(data[datapos : datapos+datalen]) - } - - return p, data[datapos+datalen:] -} - -func (p *Packet) DataLength() uint64 { - return uint64(p.Data.Len()) -} - -func (p *Packet) Bytes() []byte { - var out bytes.Buffer - - out.Write([]byte{p.ClassType | p.TagType | p.Tag}) - packet_length := EncodeInteger(p.DataLength()) - - if p.DataLength() > 127 || len(packet_length) > 1 { - out.Write([]byte{byte(len(packet_length) | 128)}) - out.Write(packet_length) - } else { - out.Write(packet_length) - } - - out.Write(p.Data.Bytes()) - - return out.Bytes() -} - -func (p *Packet) AppendChild(child *Packet) { - p.Data.Write(child.Bytes()) - - if len(p.Children) == cap(p.Children) { - newChildren := make([]*Packet, cap(p.Children)*2) - - copy(newChildren, p.Children) - p.Children = newChildren[0:len(p.Children)] - } - - p.Children = p.Children[0 : len(p.Children)+1] - p.Children[len(p.Children)-1] = child -} - -func Encode(ClassType, TagType, Tag uint8, 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)) - } - } - } - } - - return p -} - -func NewSequence(Description string) *Packet { - return Encode(ClassUniversal, TypePrimitive, TagSequence, nil, Description) -} - -func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet { - intValue := 0 - - if Value { - intValue = 1 - } - - p := Encode(ClassType, TagType, Tag, nil, Description) - - p.Value = Value - p.Data.Write(EncodeInteger(uint64(intValue))) - - return p -} - -func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet { - p := Encode(ClassType, TagType, Tag, nil, Description) - - p.Value = Value - p.Data.Write(EncodeInteger(Value)) - - return p -} - -func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet { - p := Encode(ClassType, TagType, Tag, nil, Description) - - p.Value = Value - p.Data.Write([]byte(Value)) - - return p -} diff --git a/internal/asn1-ber/LICENSE b/internal/asn1-ber/LICENSE new file mode 100644 index 0000000..7448756 --- /dev/null +++ b/internal/asn1-ber/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/internal/asn1-ber/Makefile b/internal/asn1-ber/Makefile new file mode 100644 index 0000000..acda29a --- /dev/null +++ b/internal/asn1-ber/Makefile @@ -0,0 +1,11 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +include $(GOROOT)/src/Make.inc + +TARG=github.com/mmitton/asn1-ber +GOFILES=\ + ber.go\ + +include $(GOROOT)/src/Make.pkg diff --git a/internal/asn1-ber/README b/internal/asn1-ber/README new file mode 100644 index 0000000..bb785a0 --- /dev/null +++ b/internal/asn1-ber/README @@ -0,0 +1,14 @@ +ASN1 BER Encoding / Decoding Library for the GO programming language. + +Required Librarys: + None + +Working: + Very basic encoding / decoding needed for LDAP protocol + +Tests Implemented: + None + +TODO: + Fix all encoding / decoding to conform to ASN1 BER spec + Implement Tests / Benchmarks diff --git a/internal/asn1-ber/ber.go b/internal/asn1-ber/ber.go new file mode 100644 index 0000000..95755fe --- /dev/null +++ b/internal/asn1-ber/ber.go @@ -0,0 +1,495 @@ +package ber + +import ( + "bytes" + "fmt" + "io" + "reflect" +) + +type Packet struct { + ClassType uint8 + TagType uint8 + Tag uint8 + Value interface{} + ByteValue []byte + Data *bytes.Buffer + Children []*Packet + Description string +} + +const ( + TagEOC = 0x00 + TagBoolean = 0x01 + TagInteger = 0x02 + TagBitString = 0x03 + TagOctetString = 0x04 + TagNULL = 0x05 + TagObjectIdentifier = 0x06 + TagObjectDescriptor = 0x07 + TagExternal = 0x08 + TagRealFloat = 0x09 + TagEnumerated = 0x0a + TagEmbeddedPDV = 0x0b + TagUTF8String = 0x0c + TagRelativeOID = 0x0d + TagSequence = 0x10 + TagSet = 0x11 + TagNumericString = 0x12 + TagPrintableString = 0x13 + TagT61String = 0x14 + TagVideotexString = 0x15 + TagIA5String = 0x16 + TagUTCTime = 0x17 + TagGeneralizedTime = 0x18 + TagGraphicString = 0x19 + TagVisibleString = 0x1a + TagGeneralString = 0x1b + TagUniversalString = 0x1c + TagCharacterString = 0x1d + TagBMPString = 0x1e + TagBitmask = 0x1f // xxx11111b +) + +var TagMap = map[uint8]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", +} + +const ( + ClassUniversal = 0 // 00xxxxxxb + ClassApplication = 64 // 01xxxxxxb + ClassContext = 128 // 10xxxxxxb + ClassPrivate = 192 // 11xxxxxxb + ClassBitmask = 192 // 11xxxxxxb +) + +var ClassMap = map[uint8]string{ + ClassUniversal: "Universal", + ClassApplication: "Application", + ClassContext: "Context", + ClassPrivate: "Private", +} + +const ( + TypePrimitive = 0 // xx0xxxxxb + TypeConstructed = 32 // xx1xxxxxb + TypeBitmask = 32 // xx1xxxxxb +) + +var TypeMap = map[uint8]string{ + TypePrimitive: "Primative", + TypeConstructed: "Constructed", +} + +var Debug bool = false + +func PrintBytes(buf []byte, indent string) { + data_lines := make([]string, (len(buf)/30)+1) + num_lines := make([]string, (len(buf)/30)+1) + + for i, b := range buf { + data_lines[i/30] += fmt.Sprintf("%02x ", b) + num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100) + } + + for i := 0; i < len(data_lines); i++ { + fmt.Print(indent + data_lines[i] + "\n") + fmt.Print(indent + num_lines[i] + "\n\n") + } +} + +func PrintPacket(p *Packet) { + printPacket(p, 0, false) +} + +func printPacket(p *Packet, indent int, printBytes bool) { + indent_str := "" + + for len(indent_str) != indent { + indent_str += " " + } + + class_str := ClassMap[p.ClassType] + + tagtype_str := TypeMap[p.TagType] + + tag_str := fmt.Sprintf("0x%02X", p.Tag) + + if p.ClassType == ClassUniversal { + tag_str = TagMap[p.Tag] + } + + value := fmt.Sprint(p.Value) + description := "" + + if p.Description != "" { + description = p.Description + ": " + } + + fmt.Printf("%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value) + + if printBytes { + PrintBytes(p.Bytes(), indent_str) + } + + for _, child := range p.Children { + printPacket(child, indent+1, printBytes) + } +} + +func resizeBuffer(in []byte, new_size uint64) (out []byte) { + out = make([]byte, new_size) + + copy(out, in) + + return +} + +func readBytes(reader io.Reader, buf []byte) error { + idx := 0 + buflen := len(buf) + + for idx < buflen { + n, err := reader.Read(buf[idx:]) + if err != nil { + return err + } + idx += n + } + + return nil +} + +func ReadPacket(reader io.Reader) (*Packet, error) { + buf := make([]byte, 2) + + err := readBytes(reader, buf) + + if err != nil { + return nil, err + } + + idx := uint64(2) + datalen := uint64(buf[1]) + + if Debug { + fmt.Printf("Read: datalen = %d len(buf) = %d ", datalen, len(buf)) + + for _, b := range buf { + fmt.Printf("%02X ", b) + } + + fmt.Printf("\n") + } + + if datalen&128 != 0 { + a := datalen - 128 + + idx += a + buf = resizeBuffer(buf, 2+a) + + err := readBytes(reader, buf[2:]) + + if err != nil { + return nil, err + } + + datalen = DecodeInteger(buf[2 : 2+a]) + + if Debug { + fmt.Printf("Read: a = %d idx = %d datalen = %d len(buf) = %d", a, idx, datalen, len(buf)) + + for _, b := range buf { + fmt.Printf("%02X ", b) + } + + fmt.Printf("\n") + } + } + + buf = resizeBuffer(buf, idx+datalen) + err = readBytes(reader, buf[idx:]) + + if err != nil { + return nil, err + } + + if Debug { + fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n", len(buf), idx, datalen, idx+datalen) + + for _, b := range buf { + fmt.Printf("%02X ", b) + } + } + + p := DecodePacket(buf) + + return p, nil +} + +func DecodeString(data []byte) (string) { + return string(data) +} + +func DecodeInteger(data []byte) (ret uint64) { + for _, i := range data { + ret = ret * 256 + ret = ret + uint64(i) + } + + return +} + +func EncodeInteger(val uint64) []byte { + var out bytes.Buffer + + found := false + + shift := uint(56) + + mask := uint64(0xFF00000000000000) + + for mask > 0 { + if !found && (val&mask != 0) { + found = true + } + + if found || (shift == 0) { + out.Write([]byte{byte((val & mask) >> shift)}) + } + + shift -= 8 + mask = mask >> 8 + } + + byteSlice := out.Bytes() + + // if first bit in first byte is 1 it is necessary to append a leading 00 byte to make signum clear + // otherwise it happens that a request with messageId => 02 01 80 get response with messageId => 02 04 FF FF FF 80 + if len(byteSlice) > 0 && byteSlice[0]&byte(128) != 0 { + return append([]byte{0x00}, byteSlice...) + } + return byteSlice +} + +func DecodePacket(data []byte) *Packet { + p, _ := decodePacket(data) + + return p +} + +func decodePacket(data []byte) (*Packet, []byte) { + if Debug { + fmt.Printf("decodePacket: enter %d\n", len(data)) + } + + p := new(Packet) + + p.ClassType = data[0] & ClassBitmask + p.TagType = data[0] & TypeBitmask + p.Tag = data[0] & TagBitmask + + datalen := DecodeInteger(data[1:2]) + datapos := uint64(2) + + if datalen&128 != 0 { + datalen -= 128 + datapos += datalen + datalen = DecodeInteger(data[2 : 2+datalen]) + } + + p.Data = new(bytes.Buffer) + + p.Children = make([]*Packet, 0, 2) + + p.Value = nil + + value_data := data[datapos : datapos+datalen] + + if p.TagType == TypeConstructed { + for len(value_data) != 0 { + var child *Packet + + child, value_data = decodePacket(value_data) + p.AppendChild(child) + } + } else if p.ClassType == ClassUniversal { + p.Data.Write(data[datapos : datapos+datalen]) + p.ByteValue = value_data + + switch p.Tag { + case TagEOC: + case TagBoolean: + val := DecodeInteger(value_data) + + p.Value = val != 0 + case TagInteger: + p.Value = DecodeInteger(value_data) + case TagBitString: + case TagOctetString: + p.Value = DecodeString(value_data) + case TagNULL: + case TagObjectIdentifier: + case TagObjectDescriptor: + case TagExternal: + case TagRealFloat: + case TagEnumerated: + p.Value = DecodeInteger(value_data) + case TagEmbeddedPDV: + case TagUTF8String: + case TagRelativeOID: + case TagSequence: + case TagSet: + case TagNumericString: + case TagPrintableString: + p.Value = DecodeString(value_data) + case TagT61String: + case TagVideotexString: + case TagIA5String: + case TagUTCTime: + case TagGeneralizedTime: + case TagGraphicString: + case TagVisibleString: + case TagGeneralString: + case TagUniversalString: + case TagCharacterString: + case TagBMPString: + } + } else { + p.Data.Write(data[datapos : datapos+datalen]) + } + + return p, data[datapos+datalen:] +} + +func (p *Packet) DataLength() uint64 { + return uint64(p.Data.Len()) +} + +func (p *Packet) Bytes() []byte { + var out bytes.Buffer + + out.Write([]byte{p.ClassType | p.TagType | p.Tag}) + packet_length := EncodeInteger(p.DataLength()) + + if p.DataLength() > 127 || len(packet_length) > 1 { + out.Write([]byte{byte(len(packet_length) | 128)}) + out.Write(packet_length) + } else { + out.Write(packet_length) + } + + out.Write(p.Data.Bytes()) + + return out.Bytes() +} + +func (p *Packet) AppendChild(child *Packet) { + p.Data.Write(child.Bytes()) + + if len(p.Children) == cap(p.Children) { + newChildren := make([]*Packet, cap(p.Children)*2) + + copy(newChildren, p.Children) + p.Children = newChildren[0:len(p.Children)] + } + + p.Children = p.Children[0 : len(p.Children)+1] + p.Children[len(p.Children)-1] = child +} + +func Encode(ClassType, TagType, Tag uint8, 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)) + } + } + } + } + + return p +} + +func NewSequence(Description string) *Packet { + return Encode(ClassUniversal, TypePrimitive, TagSequence, nil, Description) +} + +func NewBoolean(ClassType, TagType, Tag uint8, Value bool, Description string) *Packet { + intValue := 0 + + if Value { + intValue = 1 + } + + p := Encode(ClassType, TagType, Tag, nil, Description) + + p.Value = Value + p.Data.Write(EncodeInteger(uint64(intValue))) + + return p +} + +func NewInteger(ClassType, TagType, Tag uint8, Value uint64, Description string) *Packet { + p := Encode(ClassType, TagType, Tag, nil, Description) + + p.Value = Value + p.Data.Write(EncodeInteger(Value)) + + return p +} + +func NewString(ClassType, TagType, Tag uint8, Value, Description string) *Packet { + p := Encode(ClassType, TagType, Tag, nil, Description) + + p.Value = Value + p.Data.Write([]byte(Value)) + + return p +} -- cgit v1.2.3