...

Source file src/github.com/go-asn1-ber/asn1-ber/ber.go

Documentation: github.com/go-asn1-ber/asn1-ber

     1  package ber
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"math"
     9  	"os"
    10  	"reflect"
    11  	"time"
    12  	"unicode/utf8"
    13  )
    14  
    15  // MaxPacketLengthBytes specifies the maximum allowed packet size when calling ReadPacket or DecodePacket. Set to 0 for
    16  // no limit.
    17  var MaxPacketLengthBytes int64 = math.MaxInt32
    18  
    19  type Packet struct {
    20  	Identifier
    21  	Value       interface{}
    22  	ByteValue   []byte
    23  	Data        *bytes.Buffer
    24  	Children    []*Packet
    25  	Description string
    26  }
    27  
    28  type Identifier struct {
    29  	ClassType Class
    30  	TagType   Type
    31  	Tag       Tag
    32  }
    33  
    34  type Tag uint64
    35  
    36  const (
    37  	TagEOC              Tag = 0x00
    38  	TagBoolean          Tag = 0x01
    39  	TagInteger          Tag = 0x02
    40  	TagBitString        Tag = 0x03
    41  	TagOctetString      Tag = 0x04
    42  	TagNULL             Tag = 0x05
    43  	TagObjectIdentifier Tag = 0x06
    44  	TagObjectDescriptor Tag = 0x07
    45  	TagExternal         Tag = 0x08
    46  	TagRealFloat        Tag = 0x09
    47  	TagEnumerated       Tag = 0x0a
    48  	TagEmbeddedPDV      Tag = 0x0b
    49  	TagUTF8String       Tag = 0x0c
    50  	TagRelativeOID      Tag = 0x0d
    51  	TagSequence         Tag = 0x10
    52  	TagSet              Tag = 0x11
    53  	TagNumericString    Tag = 0x12
    54  	TagPrintableString  Tag = 0x13
    55  	TagT61String        Tag = 0x14
    56  	TagVideotexString   Tag = 0x15
    57  	TagIA5String        Tag = 0x16
    58  	TagUTCTime          Tag = 0x17
    59  	TagGeneralizedTime  Tag = 0x18
    60  	TagGraphicString    Tag = 0x19
    61  	TagVisibleString    Tag = 0x1a
    62  	TagGeneralString    Tag = 0x1b
    63  	TagUniversalString  Tag = 0x1c
    64  	TagCharacterString  Tag = 0x1d
    65  	TagBMPString        Tag = 0x1e
    66  	TagBitmask          Tag = 0x1f // xxx11111b
    67  
    68  	// HighTag indicates the start of a high-tag byte sequence
    69  	HighTag Tag = 0x1f // xxx11111b
    70  	// HighTagContinueBitmask indicates the high-tag byte sequence should continue
    71  	HighTagContinueBitmask Tag = 0x80 // 10000000b
    72  	// HighTagValueBitmask obtains the tag value from a high-tag byte sequence byte
    73  	HighTagValueBitmask Tag = 0x7f // 01111111b
    74  )
    75  
    76  const (
    77  	// LengthLongFormBitmask is the mask to apply to the length byte to see if a long-form byte sequence is used
    78  	LengthLongFormBitmask = 0x80
    79  	// LengthValueBitmask is the mask to apply to the length byte to get the number of bytes in the long-form byte sequence
    80  	LengthValueBitmask = 0x7f
    81  
    82  	// LengthIndefinite is returned from readLength to indicate an indefinite length
    83  	LengthIndefinite = -1
    84  )
    85  
    86  var tagMap = map[Tag]string{
    87  	TagEOC:              "EOC (End-of-Content)",
    88  	TagBoolean:          "Boolean",
    89  	TagInteger:          "Integer",
    90  	TagBitString:        "Bit String",
    91  	TagOctetString:      "Octet String",
    92  	TagNULL:             "NULL",
    93  	TagObjectIdentifier: "Object Identifier",
    94  	TagObjectDescriptor: "Object Descriptor",
    95  	TagExternal:         "External",
    96  	TagRealFloat:        "Real (float)",
    97  	TagEnumerated:       "Enumerated",
    98  	TagEmbeddedPDV:      "Embedded PDV",
    99  	TagUTF8String:       "UTF8 String",
   100  	TagRelativeOID:      "Relative-OID",
   101  	TagSequence:         "Sequence and Sequence of",
   102  	TagSet:              "Set and Set OF",
   103  	TagNumericString:    "Numeric String",
   104  	TagPrintableString:  "Printable String",
   105  	TagT61String:        "T61 String",
   106  	TagVideotexString:   "Videotex String",
   107  	TagIA5String:        "IA5 String",
   108  	TagUTCTime:          "UTC Time",
   109  	TagGeneralizedTime:  "Generalized Time",
   110  	TagGraphicString:    "Graphic String",
   111  	TagVisibleString:    "Visible String",
   112  	TagGeneralString:    "General String",
   113  	TagUniversalString:  "Universal String",
   114  	TagCharacterString:  "Character String",
   115  	TagBMPString:        "BMP String",
   116  }
   117  
   118  type Class uint8
   119  
   120  const (
   121  	ClassUniversal   Class = 0   // 00xxxxxxb
   122  	ClassApplication Class = 64  // 01xxxxxxb
   123  	ClassContext     Class = 128 // 10xxxxxxb
   124  	ClassPrivate     Class = 192 // 11xxxxxxb
   125  	ClassBitmask     Class = 192 // 11xxxxxxb
   126  )
   127  
   128  var ClassMap = map[Class]string{
   129  	ClassUniversal:   "Universal",
   130  	ClassApplication: "Application",
   131  	ClassContext:     "Context",
   132  	ClassPrivate:     "Private",
   133  }
   134  
   135  type Type uint8
   136  
   137  const (
   138  	TypePrimitive   Type = 0  // xx0xxxxxb
   139  	TypeConstructed Type = 32 // xx1xxxxxb
   140  	TypeBitmask     Type = 32 // xx1xxxxxb
   141  )
   142  
   143  var TypeMap = map[Type]string{
   144  	TypePrimitive:   "Primitive",
   145  	TypeConstructed: "Constructed",
   146  }
   147  
   148  var Debug = false
   149  
   150  func PrintBytes(out io.Writer, buf []byte, indent string) {
   151  	dataLines := make([]string, (len(buf)/30)+1)
   152  	numLines := make([]string, (len(buf)/30)+1)
   153  
   154  	for i, b := range buf {
   155  		dataLines[i/30] += fmt.Sprintf("%02x ", b)
   156  		numLines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
   157  	}
   158  
   159  	for i := 0; i < len(dataLines); i++ {
   160  		_, _ = out.Write([]byte(indent + dataLines[i] + "\n"))
   161  		_, _ = out.Write([]byte(indent + numLines[i] + "\n\n"))
   162  	}
   163  }
   164  
   165  func WritePacket(out io.Writer, p *Packet) {
   166  	printPacket(out, p, 0, false)
   167  }
   168  
   169  func PrintPacket(p *Packet) {
   170  	printPacket(os.Stdout, p, 0, false)
   171  }
   172  
   173  // Return a string describing packet content. This is not recursive,
   174  // If the packet is a sequence, use `printPacket()`, or browse
   175  // sequence yourself.
   176  func DescribePacket(p *Packet) string {
   177  
   178  	classStr := ClassMap[p.ClassType]
   179  
   180  	tagTypeStr := TypeMap[p.TagType]
   181  
   182  	tagStr := fmt.Sprintf("0x%02X", p.Tag)
   183  
   184  	if p.ClassType == ClassUniversal {
   185  		tagStr = tagMap[p.Tag]
   186  	}
   187  
   188  	value := fmt.Sprint(p.Value)
   189  	description := ""
   190  
   191  	if p.Description != "" {
   192  		description = p.Description + ": "
   193  	}
   194  
   195  	return fmt.Sprintf("%s(%s, %s, %s) Len=%d %q", description, classStr, tagTypeStr, tagStr, p.Data.Len(), value)
   196  }
   197  
   198  func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) {
   199  	indentStr := ""
   200  
   201  	for len(indentStr) != indent {
   202  		indentStr += " "
   203  	}
   204  
   205  	_, _ = fmt.Fprintf(out, "%s%s\n", indentStr, DescribePacket(p))
   206  
   207  	if printBytes {
   208  		PrintBytes(out, p.Bytes(), indentStr)
   209  	}
   210  
   211  	for _, child := range p.Children {
   212  		printPacket(out, child, indent+1, printBytes)
   213  	}
   214  }
   215  
   216  // ReadPacket reads a single Packet from the reader.
   217  func ReadPacket(reader io.Reader) (*Packet, error) {
   218  	p, _, err := readPacket(reader)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return p, nil
   223  }
   224  
   225  func DecodeString(data []byte) string {
   226  	return string(data)
   227  }
   228  
   229  func ParseInt64(bytes []byte) (ret int64, err error) {
   230  	if len(bytes) > 8 {
   231  		// We'll overflow an int64 in this case.
   232  		err = fmt.Errorf("integer too large")
   233  		return
   234  	}
   235  	for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
   236  		ret <<= 8
   237  		ret |= int64(bytes[bytesRead])
   238  	}
   239  
   240  	// Shift up and down in order to sign extend the result.
   241  	ret <<= 64 - uint8(len(bytes))*8
   242  	ret >>= 64 - uint8(len(bytes))*8
   243  	return
   244  }
   245  
   246  func encodeInteger(i int64) []byte {
   247  	n := int64Length(i)
   248  	out := make([]byte, n)
   249  
   250  	var j int
   251  	for ; n > 0; n-- {
   252  		out[j] = byte(i >> uint((n-1)*8))
   253  		j++
   254  	}
   255  
   256  	return out
   257  }
   258  
   259  func int64Length(i int64) (numBytes int) {
   260  	numBytes = 1
   261  
   262  	for i > 127 {
   263  		numBytes++
   264  		i >>= 8
   265  	}
   266  
   267  	for i < -128 {
   268  		numBytes++
   269  		i >>= 8
   270  	}
   271  
   272  	return
   273  }
   274  
   275  // DecodePacket decodes the given bytes into a single Packet
   276  // If a decode error is encountered, nil is returned.
   277  func DecodePacket(data []byte) *Packet {
   278  	p, _, _ := readPacket(bytes.NewBuffer(data))
   279  
   280  	return p
   281  }
   282  
   283  // DecodePacketErr decodes the given bytes into a single Packet
   284  // If a decode error is encountered, nil is returned.
   285  func DecodePacketErr(data []byte) (*Packet, error) {
   286  	p, _, err := readPacket(bytes.NewBuffer(data))
   287  	if err != nil {
   288  		return nil, err
   289  	}
   290  	return p, nil
   291  }
   292  
   293  // readPacket reads a single Packet from the reader, returning the number of bytes read.
   294  func readPacket(reader io.Reader) (*Packet, int, error) {
   295  	identifier, length, read, err := readHeader(reader)
   296  	if err != nil {
   297  		return nil, read, err
   298  	}
   299  
   300  	p := &Packet{
   301  		Identifier: identifier,
   302  	}
   303  
   304  	p.Data = new(bytes.Buffer)
   305  	p.Children = make([]*Packet, 0, 2)
   306  	p.Value = nil
   307  
   308  	if p.TagType == TypeConstructed {
   309  		// TODO: if universal, ensure tag type is allowed to be constructed
   310  
   311  		// Track how much content we've read
   312  		contentRead := 0
   313  		for {
   314  			if length != LengthIndefinite {
   315  				// End if we've read what we've been told to
   316  				if contentRead == length {
   317  					break
   318  				}
   319  				// Detect if a packet boundary didn't fall on the expected length
   320  				if contentRead > length {
   321  					return nil, read, fmt.Errorf("expected to read %d bytes, read %d", length, contentRead)
   322  				}
   323  			}
   324  
   325  			// Read the next packet
   326  			child, r, err := readPacket(reader)
   327  			if err != nil {
   328  				return nil, read, unexpectedEOF(err)
   329  			}
   330  			contentRead += r
   331  			read += r
   332  
   333  			// Test is this is the EOC marker for our packet
   334  			if isEOCPacket(child) {
   335  				if length == LengthIndefinite {
   336  					break
   337  				}
   338  				return nil, read, errors.New("eoc child not allowed with definite length")
   339  			}
   340  
   341  			// Append and continue
   342  			p.AppendChild(child)
   343  		}
   344  		return p, read, nil
   345  	}
   346  
   347  	if length == LengthIndefinite {
   348  		return nil, read, errors.New("indefinite length used with primitive type")
   349  	}
   350  
   351  	// Read definite-length content
   352  	if MaxPacketLengthBytes > 0 && int64(length) > MaxPacketLengthBytes {
   353  		return nil, read, fmt.Errorf("length %d greater than maximum %d", length, MaxPacketLengthBytes)
   354  	}
   355  	content := make([]byte, length)
   356  	if length > 0 {
   357  		_, err := io.ReadFull(reader, content)
   358  		if err != nil {
   359  			return nil, read, unexpectedEOF(err)
   360  		}
   361  		read += length
   362  	}
   363  
   364  	if p.ClassType == ClassUniversal {
   365  		p.Data.Write(content)
   366  		p.ByteValue = content
   367  
   368  		switch p.Tag {
   369  		case TagEOC:
   370  		case TagBoolean:
   371  			val, _ := ParseInt64(content)
   372  
   373  			p.Value = val != 0
   374  		case TagInteger:
   375  			p.Value, _ = ParseInt64(content)
   376  		case TagBitString:
   377  		case TagOctetString:
   378  			// the actual string encoding is not known here
   379  			// (e.g. for LDAP content is already an UTF8-encoded
   380  			// string). Return the data without further processing
   381  			p.Value = DecodeString(content)
   382  		case TagNULL:
   383  		case TagObjectIdentifier:
   384  		case TagObjectDescriptor:
   385  		case TagExternal:
   386  		case TagRealFloat:
   387  			p.Value, err = ParseReal(content)
   388  		case TagEnumerated:
   389  			p.Value, _ = ParseInt64(content)
   390  		case TagEmbeddedPDV:
   391  		case TagUTF8String:
   392  			val := DecodeString(content)
   393  			if !utf8.Valid([]byte(val)) {
   394  				err = errors.New("invalid UTF-8 string")
   395  			} else {
   396  				p.Value = val
   397  			}
   398  		case TagRelativeOID:
   399  		case TagSequence:
   400  		case TagSet:
   401  		case TagNumericString:
   402  		case TagPrintableString:
   403  			val := DecodeString(content)
   404  			if err = isPrintableString(val); err == nil {
   405  				p.Value = val
   406  			}
   407  		case TagT61String:
   408  		case TagVideotexString:
   409  		case TagIA5String:
   410  			val := DecodeString(content)
   411  			for i, c := range val {
   412  				if c >= 0x7F {
   413  					err = fmt.Errorf("invalid character for IA5String at pos %d: %c", i, c)
   414  					break
   415  				}
   416  			}
   417  			if err == nil {
   418  				p.Value = val
   419  			}
   420  		case TagUTCTime:
   421  		case TagGeneralizedTime:
   422  			p.Value, err = ParseGeneralizedTime(content)
   423  		case TagGraphicString:
   424  		case TagVisibleString:
   425  		case TagGeneralString:
   426  		case TagUniversalString:
   427  		case TagCharacterString:
   428  		case TagBMPString:
   429  		}
   430  	} else {
   431  		p.Data.Write(content)
   432  	}
   433  
   434  	return p, read, err
   435  }
   436  
   437  func isPrintableString(val string) error {
   438  	for i, c := range val {
   439  		switch {
   440  		case c >= 'a' && c <= 'z':
   441  		case c >= 'A' && c <= 'Z':
   442  		case c >= '0' && c <= '9':
   443  		default:
   444  			switch c {
   445  			case '\'', '(', ')', '+', ',', '-', '.', '=', '/', ':', '?', ' ':
   446  			default:
   447  				return fmt.Errorf("invalid character in position %d", i)
   448  			}
   449  		}
   450  	}
   451  	return nil
   452  }
   453  
   454  func (p *Packet) Bytes() []byte {
   455  	var out bytes.Buffer
   456  
   457  	out.Write(encodeIdentifier(p.Identifier))
   458  	out.Write(encodeLength(p.Data.Len()))
   459  	out.Write(p.Data.Bytes())
   460  
   461  	return out.Bytes()
   462  }
   463  
   464  func (p *Packet) AppendChild(child *Packet) {
   465  	p.Data.Write(child.Bytes())
   466  	p.Children = append(p.Children, child)
   467  }
   468  
   469  func Encode(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet {
   470  	p := new(Packet)
   471  
   472  	p.ClassType = classType
   473  	p.TagType = tagType
   474  	p.Tag = tag
   475  	p.Data = new(bytes.Buffer)
   476  
   477  	p.Children = make([]*Packet, 0, 2)
   478  
   479  	p.Value = value
   480  	p.Description = description
   481  
   482  	if value != nil {
   483  		v := reflect.ValueOf(value)
   484  
   485  		if classType == ClassUniversal {
   486  			switch tag {
   487  			case TagOctetString:
   488  				sv, ok := v.Interface().(string)
   489  
   490  				if ok {
   491  					p.Data.Write([]byte(sv))
   492  				}
   493  			case TagEnumerated:
   494  				bv, ok := v.Interface().([]byte)
   495  				if ok {
   496  					p.Data.Write(bv)
   497  				}
   498  			case TagEmbeddedPDV:
   499  				bv, ok := v.Interface().([]byte)
   500  				if ok {
   501  					p.Data.Write(bv)
   502  				}
   503  			}
   504  		} else if classType == ClassContext {
   505  			switch tag {
   506  			case TagEnumerated:
   507  				bv, ok := v.Interface().([]byte)
   508  				if ok {
   509  					p.Data.Write(bv)
   510  				}
   511  			case TagEmbeddedPDV:
   512  				bv, ok := v.Interface().([]byte)
   513  				if ok {
   514  					p.Data.Write(bv)
   515  				}
   516  			}
   517  		}
   518  	}
   519  	return p
   520  }
   521  
   522  func NewSequence(description string) *Packet {
   523  	return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, description)
   524  }
   525  
   526  func NewBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet {
   527  	intValue := int64(0)
   528  
   529  	if value {
   530  		intValue = 1
   531  	}
   532  
   533  	p := Encode(classType, tagType, tag, nil, description)
   534  
   535  	p.Value = value
   536  	p.Data.Write(encodeInteger(intValue))
   537  
   538  	return p
   539  }
   540  
   541  // NewLDAPBoolean returns a RFC 4511-compliant Boolean packet.
   542  func NewLDAPBoolean(classType Class, tagType Type, tag Tag, value bool, description string) *Packet {
   543  	intValue := int64(0)
   544  
   545  	if value {
   546  		intValue = 255
   547  	}
   548  
   549  	p := Encode(classType, tagType, tag, nil, description)
   550  
   551  	p.Value = value
   552  	p.Data.Write(encodeInteger(intValue))
   553  
   554  	return p
   555  }
   556  
   557  func NewInteger(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet {
   558  	p := Encode(classType, tagType, tag, nil, description)
   559  
   560  	p.Value = value
   561  	switch v := value.(type) {
   562  	case int:
   563  		p.Data.Write(encodeInteger(int64(v)))
   564  	case uint:
   565  		p.Data.Write(encodeInteger(int64(v)))
   566  	case int64:
   567  		p.Data.Write(encodeInteger(v))
   568  	case uint64:
   569  		// TODO : check range or add encodeUInt...
   570  		p.Data.Write(encodeInteger(int64(v)))
   571  	case int32:
   572  		p.Data.Write(encodeInteger(int64(v)))
   573  	case uint32:
   574  		p.Data.Write(encodeInteger(int64(v)))
   575  	case int16:
   576  		p.Data.Write(encodeInteger(int64(v)))
   577  	case uint16:
   578  		p.Data.Write(encodeInteger(int64(v)))
   579  	case int8:
   580  		p.Data.Write(encodeInteger(int64(v)))
   581  	case uint8:
   582  		p.Data.Write(encodeInteger(int64(v)))
   583  	default:
   584  		// TODO : add support for big.Int ?
   585  		panic(fmt.Sprintf("Invalid type %T, expected {u|}int{64|32|16|8}", v))
   586  	}
   587  
   588  	return p
   589  }
   590  
   591  func NewString(classType Class, tagType Type, tag Tag, value, description string) *Packet {
   592  	p := Encode(classType, tagType, tag, nil, description)
   593  
   594  	p.Value = value
   595  	p.Data.Write([]byte(value))
   596  
   597  	return p
   598  }
   599  
   600  func NewGeneralizedTime(classType Class, tagType Type, tag Tag, value time.Time, description string) *Packet {
   601  	p := Encode(classType, tagType, tag, nil, description)
   602  	var s string
   603  	if value.Nanosecond() != 0 {
   604  		s = value.Format(`20060102150405.000000000Z`)
   605  	} else {
   606  		s = value.Format(`20060102150405Z`)
   607  	}
   608  	p.Value = s
   609  	p.Data.Write([]byte(s))
   610  	return p
   611  }
   612  
   613  func NewReal(classType Class, tagType Type, tag Tag, value interface{}, description string) *Packet {
   614  	p := Encode(classType, tagType, tag, nil, description)
   615  
   616  	switch v := value.(type) {
   617  	case float64:
   618  		p.Data.Write(encodeFloat(v))
   619  	case float32:
   620  		p.Data.Write(encodeFloat(float64(v)))
   621  	default:
   622  		panic(fmt.Sprintf("Invalid type %T, expected float{64|32}", v))
   623  	}
   624  	return p
   625  }
   626  

View as plain text