|
|
@@ -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
|
|
|
+}
|
|
|
+
|