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
16
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
67
68
69 HighTag Tag = 0x1f
70
71 HighTagContinueBitmask Tag = 0x80
72
73 HighTagValueBitmask Tag = 0x7f
74 )
75
76 const (
77
78 LengthLongFormBitmask = 0x80
79
80 LengthValueBitmask = 0x7f
81
82
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
122 ClassApplication Class = 64
123 ClassContext Class = 128
124 ClassPrivate Class = 192
125 ClassBitmask Class = 192
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
139 TypeConstructed Type = 32
140 TypeBitmask Type = 32
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
174
175
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
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
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
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
276
277 func DecodePacket(data []byte) *Packet {
278 p, _, _ := readPacket(bytes.NewBuffer(data))
279
280 return p
281 }
282
283
284
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
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
310
311
312 contentRead := 0
313 for {
314 if length != LengthIndefinite {
315
316 if contentRead == length {
317 break
318 }
319
320 if contentRead > length {
321 return nil, read, fmt.Errorf("expected to read %d bytes, read %d", length, contentRead)
322 }
323 }
324
325
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
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
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
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
379
380
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
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
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
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