Michael Mitton 15 سال پیش
کامیت
45715bd422
3فایلهای تغییر یافته به همراه456 افزوده شده و 0 حذف شده
  1. 11 0
      Makefile
  2. 14 0
      README
  3. 431 0
      ber.go

+ 11 - 0
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

+ 14 - 0
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

+ 431 - 0
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
+}
+