Codebase list golang-gopkg-asn1-ber.v1 / upstream/1
Imported Upstream version 1 aviau 8 years ago
5 changed file(s) with 743 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 language: go
1 go:
2 - 1.2
3 - 1.3
4 - tip
5 install:
6 - go list -f '{{range .Imports}}{{.}} {{end}}' ./... | xargs go get -v
7 - go list -f '{{range .TestImports}}{{.}} {{end}}' ./... | xargs go get -v
8 - go get code.google.com/p/go.tools/cmd/cover
9 - go build -v ./...
10 script:
11 - go test -v -cover ./...
0 Copyright (c) 2012 The Go Authors. All rights reserved.
1
2 Redistribution and use in source and binary forms, with or without
3 modification, are permitted provided that the following conditions are
4 met:
5
6 * Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above
9 copyright notice, this list of conditions and the following disclaimer
10 in the documentation and/or other materials provided with the
11 distribution.
12 * Neither the name of Google Inc. nor the names of its
13 contributors may be used to endorse or promote products derived from
14 this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 [![GoDoc](https://godoc.org/gopkg.in/asn1-ber.v1?status.svg)](https://godoc.org/gopkg.in/asn1-ber.v1) [![Build Status](https://travis-ci.org/go-asn1-ber/asn1-ber.svg)](https://travis-ci.org/go-asn1-ber/asn1-ber)
1
2
3 ASN1 BER Encoding / Decoding Library for the GO programming language.
4 ---------------------------------------------------------------------
5
6 Required libraries:
7 None
8
9 Working:
10 Very basic encoding / decoding needed for LDAP protocol
11
12 Tests Implemented:
13 A few
14
15 TODO:
16 Fix all encoding / decoding to conform to ASN1 BER spec
17 Implement Tests / Benchmarks
0 package ber
1
2 import (
3 "bytes"
4 "fmt"
5 "io"
6 "os"
7 "reflect"
8 )
9
10 type Packet struct {
11 ClassType Class
12 TagType Type
13 Tag Tag
14 Value interface{}
15 ByteValue []byte
16 Data *bytes.Buffer
17 Children []*Packet
18 Description string
19 }
20
21 type Tag uint8
22
23 const (
24 TagEOC Tag = 0x00
25 TagBoolean Tag = 0x01
26 TagInteger Tag = 0x02
27 TagBitString Tag = 0x03
28 TagOctetString Tag = 0x04
29 TagNULL Tag = 0x05
30 TagObjectIdentifier Tag = 0x06
31 TagObjectDescriptor Tag = 0x07
32 TagExternal Tag = 0x08
33 TagRealFloat Tag = 0x09
34 TagEnumerated Tag = 0x0a
35 TagEmbeddedPDV Tag = 0x0b
36 TagUTF8String Tag = 0x0c
37 TagRelativeOID Tag = 0x0d
38 TagSequence Tag = 0x10
39 TagSet Tag = 0x11
40 TagNumericString Tag = 0x12
41 TagPrintableString Tag = 0x13
42 TagT61String Tag = 0x14
43 TagVideotexString Tag = 0x15
44 TagIA5String Tag = 0x16
45 TagUTCTime Tag = 0x17
46 TagGeneralizedTime Tag = 0x18
47 TagGraphicString Tag = 0x19
48 TagVisibleString Tag = 0x1a
49 TagGeneralString Tag = 0x1b
50 TagUniversalString Tag = 0x1c
51 TagCharacterString Tag = 0x1d
52 TagBMPString Tag = 0x1e
53 TagBitmask Tag = 0x1f // xxx11111b
54 )
55
56 var tagMap = map[Tag]string{
57 TagEOC: "EOC (End-of-Content)",
58 TagBoolean: "Boolean",
59 TagInteger: "Integer",
60 TagBitString: "Bit String",
61 TagOctetString: "Octet String",
62 TagNULL: "NULL",
63 TagObjectIdentifier: "Object Identifier",
64 TagObjectDescriptor: "Object Descriptor",
65 TagExternal: "External",
66 TagRealFloat: "Real (float)",
67 TagEnumerated: "Enumerated",
68 TagEmbeddedPDV: "Embedded PDV",
69 TagUTF8String: "UTF8 String",
70 TagRelativeOID: "Relative-OID",
71 TagSequence: "Sequence and Sequence of",
72 TagSet: "Set and Set OF",
73 TagNumericString: "Numeric String",
74 TagPrintableString: "Printable String",
75 TagT61String: "T61 String",
76 TagVideotexString: "Videotex String",
77 TagIA5String: "IA5 String",
78 TagUTCTime: "UTC Time",
79 TagGeneralizedTime: "Generalized Time",
80 TagGraphicString: "Graphic String",
81 TagVisibleString: "Visible String",
82 TagGeneralString: "General String",
83 TagUniversalString: "Universal String",
84 TagCharacterString: "Character String",
85 TagBMPString: "BMP String",
86 }
87
88 type Class uint8
89
90 const (
91 ClassUniversal Class = 0 // 00xxxxxxb
92 ClassApplication Class = 64 // 01xxxxxxb
93 ClassContext Class = 128 // 10xxxxxxb
94 ClassPrivate Class = 192 // 11xxxxxxb
95 ClassBitmask Class = 192 // 11xxxxxxb
96 )
97
98 var ClassMap = map[Class]string{
99 ClassUniversal: "Universal",
100 ClassApplication: "Application",
101 ClassContext: "Context",
102 ClassPrivate: "Private",
103 }
104
105 type Type uint8
106
107 const (
108 TypePrimitive Type = 0 // xx0xxxxxb
109 TypeConstructed Type = 32 // xx1xxxxxb
110 TypeBitmask Type = 32 // xx1xxxxxb
111 )
112
113 var TypeMap = map[Type]string{
114 TypePrimitive: "Primitive",
115 TypeConstructed: "Constructed",
116 }
117
118 var Debug bool = false
119
120 func PrintBytes(out io.Writer, buf []byte, indent string) {
121 data_lines := make([]string, (len(buf)/30)+1)
122 num_lines := make([]string, (len(buf)/30)+1)
123
124 for i, b := range buf {
125 data_lines[i/30] += fmt.Sprintf("%02x ", b)
126 num_lines[i/30] += fmt.Sprintf("%02d ", (i+1)%100)
127 }
128
129 for i := 0; i < len(data_lines); i++ {
130 out.Write([]byte(indent + data_lines[i] + "\n"))
131 out.Write([]byte(indent + num_lines[i] + "\n\n"))
132 }
133 }
134
135 func PrintPacket(p *Packet) {
136 printPacket(os.Stdout, p, 0, false)
137 }
138
139 func printPacket(out io.Writer, p *Packet, indent int, printBytes bool) {
140 indent_str := ""
141
142 for len(indent_str) != indent {
143 indent_str += " "
144 }
145
146 class_str := ClassMap[p.ClassType]
147
148 tagtype_str := TypeMap[p.TagType]
149
150 tag_str := fmt.Sprintf("0x%02X", p.Tag)
151
152 if p.ClassType == ClassUniversal {
153 tag_str = tagMap[p.Tag]
154 }
155
156 value := fmt.Sprint(p.Value)
157 description := ""
158
159 if p.Description != "" {
160 description = p.Description + ": "
161 }
162
163 fmt.Fprintf(out, "%s%s(%s, %s, %s) Len=%d %q\n", indent_str, description, class_str, tagtype_str, tag_str, p.Data.Len(), value)
164
165 if printBytes {
166 PrintBytes(out, p.Bytes(), indent_str)
167 }
168
169 for _, child := range p.Children {
170 printPacket(out, child, indent+1, printBytes)
171 }
172 }
173
174 func resizeBuffer(in []byte, new_size int) (out []byte) {
175 out = make([]byte, new_size)
176
177 copy(out, in)
178
179 return
180 }
181
182 func ReadPacket(reader io.Reader) (*Packet, error) {
183 var header [2]byte
184 buf := header[:]
185 _, err := io.ReadFull(reader, buf)
186
187 if err != nil {
188 return nil, err
189 }
190
191 idx := 2
192 var datalen int
193 l := buf[1]
194
195 if l&0x80 == 0 {
196 // The length is encoded in the bottom 7 bits.
197 datalen = int(l & 0x7f)
198 if Debug {
199 fmt.Printf("Read: datalen = %d len(buf) = %d\n ", l, len(buf))
200
201 for _, b := range buf {
202 fmt.Printf("%02X ", b)
203 }
204
205 fmt.Printf("\n")
206 }
207 } else {
208 // Bottom 7 bits give the number of length bytes to follow.
209 numBytes := int(l & 0x7f)
210 if numBytes == 0 {
211 return nil, fmt.Errorf("invalid length found")
212 }
213 idx += numBytes
214 buf = resizeBuffer(buf, 2+numBytes)
215 _, err := io.ReadFull(reader, buf[2:])
216
217 if err != nil {
218 return nil, err
219 }
220 datalen = 0
221 for i := 0; i < numBytes; i++ {
222 b := buf[2+i]
223 datalen <<= 8
224 datalen |= int(b)
225 }
226
227 if Debug {
228 fmt.Printf("Read: datalen = %d numbytes=%d len(buf) = %d\n ", datalen, numBytes, len(buf))
229
230 for _, b := range buf {
231 fmt.Printf("%02X ", b)
232 }
233
234 fmt.Printf("\n")
235 }
236 }
237
238 buf = resizeBuffer(buf, idx+datalen)
239 _, err = io.ReadFull(reader, buf[idx:])
240
241 if err != nil {
242 return nil, err
243 }
244
245 if Debug {
246 fmt.Printf("Read: len( buf ) = %d idx=%d datalen=%d idx+datalen=%d\n ", len(buf), idx, datalen, idx+datalen)
247
248 for _, b := range buf {
249 fmt.Printf("%02X ", b)
250 }
251 }
252
253 p, _ := decodePacket(buf)
254
255 return p, nil
256 }
257
258 func DecodeString(data []byte) string {
259 return string(data)
260 }
261
262 func parseInt64(bytes []byte) (ret int64, err error) {
263 if len(bytes) > 8 {
264 // We'll overflow an int64 in this case.
265 err = fmt.Errorf("integer too large")
266 return
267 }
268 for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
269 ret <<= 8
270 ret |= int64(bytes[bytesRead])
271 }
272
273 // Shift up and down in order to sign extend the result.
274 ret <<= 64 - uint8(len(bytes))*8
275 ret >>= 64 - uint8(len(bytes))*8
276 return
277 }
278
279 func encodeInteger(i int64) []byte {
280 n := int64Length(i)
281 out := make([]byte, n)
282
283 var j int
284 for ; n > 0; n-- {
285 out[j] = (byte(i >> uint((n-1)*8)))
286 j++
287 }
288
289 return out
290 }
291
292 func int64Length(i int64) (numBytes int) {
293 numBytes = 1
294
295 for i > 127 {
296 numBytes++
297 i >>= 8
298 }
299
300 for i < -128 {
301 numBytes++
302 i >>= 8
303 }
304
305 return
306 }
307
308 func DecodePacket(data []byte) *Packet {
309 p, _ := decodePacket(data)
310
311 return p
312 }
313
314 func decodePacket(data []byte) (*Packet, []byte) {
315 if Debug {
316 fmt.Printf("decodePacket: enter %d\n", len(data))
317 }
318
319 p := new(Packet)
320
321 p.ClassType = Class(data[0]) & ClassBitmask
322 p.TagType = Type(data[0]) & TypeBitmask
323 p.Tag = Tag(data[0]) & TagBitmask
324
325 var datalen int
326 l := data[1]
327 datapos := 2
328 if l&0x80 == 0 {
329 // The length is encoded in the bottom 7 bits.
330 datalen = int(l & 0x7f)
331 } else {
332 // Bottom 7 bits give the number of length bytes to follow.
333 numBytes := int(l & 0x7f)
334 if numBytes == 0 {
335 return nil, nil
336 }
337 datapos += numBytes
338 datalen = 0
339 for i := 0; i < numBytes; i++ {
340 b := data[2+i]
341 datalen <<= 8
342 datalen |= int(b)
343 }
344 }
345
346 p.Data = new(bytes.Buffer)
347
348 p.Children = make([]*Packet, 0, 2)
349
350 p.Value = nil
351
352 value_data := data[datapos : datapos+datalen]
353
354 if p.TagType == TypeConstructed {
355 for len(value_data) != 0 {
356 var child *Packet
357
358 child, value_data = decodePacket(value_data)
359 p.AppendChild(child)
360 }
361 } else if p.ClassType == ClassUniversal {
362 p.Data.Write(data[datapos : datapos+datalen])
363 p.ByteValue = value_data
364
365 switch p.Tag {
366 case TagEOC:
367 case TagBoolean:
368 val, _ := parseInt64(value_data)
369
370 p.Value = val != 0
371 case TagInteger:
372 p.Value, _ = parseInt64(value_data)
373 case TagBitString:
374 case TagOctetString:
375 // the actual string encoding is not known here
376 // (e.g. for LDAP value_data is already an UTF8-encoded
377 // string). Return the data without further processing
378 p.Value = DecodeString(value_data)
379 case TagNULL:
380 case TagObjectIdentifier:
381 case TagObjectDescriptor:
382 case TagExternal:
383 case TagRealFloat:
384 case TagEnumerated:
385 p.Value, _ = parseInt64(value_data)
386 case TagEmbeddedPDV:
387 case TagUTF8String:
388 case TagRelativeOID:
389 case TagSequence:
390 case TagSet:
391 case TagNumericString:
392 case TagPrintableString:
393 p.Value = DecodeString(value_data)
394 case TagT61String:
395 case TagVideotexString:
396 case TagIA5String:
397 case TagUTCTime:
398 case TagGeneralizedTime:
399 case TagGraphicString:
400 case TagVisibleString:
401 case TagGeneralString:
402 case TagUniversalString:
403 case TagCharacterString:
404 case TagBMPString:
405 }
406 } else {
407 p.Data.Write(data[datapos : datapos+datalen])
408 }
409
410 return p, data[datapos+datalen:]
411 }
412
413 func (p *Packet) Bytes() []byte {
414 var out bytes.Buffer
415
416 out.Write([]byte{byte(p.ClassType) | byte(p.TagType) | byte(p.Tag)})
417 packet_length := encodeInteger(int64(p.Data.Len()))
418
419 if p.Data.Len() > 127 || len(packet_length) > 1 {
420 out.Write([]byte{byte(len(packet_length) | 128)})
421 out.Write(packet_length)
422 } else {
423 out.Write(packet_length)
424 }
425
426 out.Write(p.Data.Bytes())
427
428 return out.Bytes()
429 }
430
431 func (p *Packet) AppendChild(child *Packet) {
432 p.Data.Write(child.Bytes())
433 p.Children = append(p.Children, child)
434 }
435
436 func Encode(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet {
437 p := new(Packet)
438
439 p.ClassType = ClassType
440 p.TagType = TagType
441 p.Tag = Tag
442 p.Data = new(bytes.Buffer)
443
444 p.Children = make([]*Packet, 0, 2)
445
446 p.Value = Value
447 p.Description = Description
448
449 if Value != nil {
450 v := reflect.ValueOf(Value)
451
452 if ClassType == ClassUniversal {
453 switch Tag {
454 case TagOctetString:
455 sv, ok := v.Interface().(string)
456
457 if ok {
458 p.Data.Write([]byte(sv))
459 }
460 }
461 }
462 }
463
464 return p
465 }
466
467 func NewSequence(Description string) *Packet {
468 return Encode(ClassUniversal, TypeConstructed, TagSequence, nil, Description)
469 }
470
471 func NewBoolean(ClassType Class, TagType Type, Tag Tag, Value bool, Description string) *Packet {
472 intValue := int64(0)
473
474 if Value {
475 intValue = 1
476 }
477
478 p := Encode(ClassType, TagType, Tag, nil, Description)
479
480 p.Value = Value
481 p.Data.Write(encodeInteger(intValue))
482
483 return p
484 }
485
486 func NewInteger(ClassType Class, TagType Type, Tag Tag, Value interface{}, Description string) *Packet {
487 p := Encode(ClassType, TagType, Tag, nil, Description)
488
489 p.Value = Value
490 switch v := Value.(type) {
491 case int:
492 p.Data.Write(encodeInteger(int64(v)))
493 case uint:
494 p.Data.Write(encodeInteger(int64(v)))
495 case int64:
496 p.Data.Write(encodeInteger(v))
497 case uint64:
498 // TODO : check range or add encodeUInt...
499 p.Data.Write(encodeInteger(int64(v)))
500 case int32:
501 p.Data.Write(encodeInteger(int64(v)))
502 case uint32:
503 p.Data.Write(encodeInteger(int64(v)))
504 case int16:
505 p.Data.Write(encodeInteger(int64(v)))
506 case uint16:
507 p.Data.Write(encodeInteger(int64(v)))
508 case int8:
509 p.Data.Write(encodeInteger(int64(v)))
510 case uint8:
511 p.Data.Write(encodeInteger(int64(v)))
512 default:
513 // TODO : add support for big.Int ?
514 panic(fmt.Sprintf("Invalid type %T, expected {u|}int{64|32|16|8}", v))
515 }
516
517 return p
518 }
519
520 func NewString(ClassType Class, TagType Type, Tag Tag, Value, Description string) *Packet {
521 p := Encode(ClassType, TagType, Tag, nil, Description)
522
523 p.Value = Value
524 p.Data.Write([]byte(Value))
525
526 return p
527 }
0 package ber
1
2 import (
3 "bytes"
4
5 "io"
6 "testing"
7 )
8
9 func TestEncodeDecodeInteger(t *testing.T) {
10 for _, v := range []int64{0, 10, 128, 1024, -1, -100, -128, -1024} {
11 enc := encodeInteger(v)
12 dec, err := parseInt64(enc)
13 if err != nil {
14 t.Fatalf("Error decoding %d : %s", v, err)
15 }
16 if v != dec {
17 t.Error("TestEncodeDecodeInteger failed for %d (got %d)", v, dec)
18 }
19
20 }
21 }
22
23 func TestBoolean(t *testing.T) {
24 var value bool = true
25
26 packet := NewBoolean(ClassUniversal, TypePrimitive, TagBoolean, value, "first Packet, True")
27
28 newBoolean, ok := packet.Value.(bool)
29 if !ok || newBoolean != value {
30 t.Error("error during creating packet")
31 }
32
33 encodedPacket := packet.Bytes()
34
35 newPacket := DecodePacket(encodedPacket)
36
37 newBoolean, ok = newPacket.Value.(bool)
38 if !ok || newBoolean != value {
39 t.Error("error during decoding packet")
40 }
41
42 }
43
44 func TestInteger(t *testing.T) {
45 var value int64 = 10
46
47 packet := NewInteger(ClassUniversal, TypePrimitive, TagInteger, value, "Integer, 10")
48
49 {
50 newInteger, ok := packet.Value.(int64)
51 if !ok || newInteger != value {
52 t.Error("error creating packet")
53 }
54 }
55
56 encodedPacket := packet.Bytes()
57
58 newPacket := DecodePacket(encodedPacket)
59
60 {
61 newInteger, ok := newPacket.Value.(int64)
62 if !ok || int64(newInteger) != value {
63 t.Error("error decoding packet")
64 }
65 }
66 }
67
68 func TestString(t *testing.T) {
69 var value string = "Hic sunt dracones"
70
71 packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, value, "String")
72
73 newValue, ok := packet.Value.(string)
74 if !ok || newValue != value {
75 t.Error("error during creating packet")
76 }
77
78 encodedPacket := packet.Bytes()
79
80 newPacket := DecodePacket(encodedPacket)
81
82 newValue, ok = newPacket.Value.(string)
83 if !ok || newValue != value {
84 t.Error("error during decoding packet")
85 }
86
87 }
88
89 func TestSequenceAndAppendChild(t *testing.T) {
90
91 p1 := NewString(ClassUniversal, TypePrimitive, TagOctetString, "HIC SVNT LEONES", "String")
92 p2 := NewString(ClassUniversal, TypePrimitive, TagOctetString, "HIC SVNT DRACONES", "String")
93 p3 := NewString(ClassUniversal, TypePrimitive, TagOctetString, "Terra Incognita", "String")
94
95 sequence := NewSequence("a sequence")
96 sequence.AppendChild(p1)
97 sequence.AppendChild(p2)
98 sequence.AppendChild(p3)
99
100 if len(sequence.Children) != 3 {
101 t.Error("wrong length for children array should be three =>", len(sequence.Children))
102 }
103
104 encodedSequence := sequence.Bytes()
105
106 decodedSequence := DecodePacket(encodedSequence)
107 if len(decodedSequence.Children) != 3 {
108 t.Error("wrong length for children array should be three =>", len(decodedSequence.Children))
109 }
110
111 }
112
113 func TestReadPacket(t *testing.T) {
114 packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, "Ad impossibilia nemo tenetur", "string")
115 var buffer io.ReadWriter
116 buffer = new(bytes.Buffer)
117
118 buffer.Write(packet.Bytes())
119
120 newPacket, err := ReadPacket(buffer)
121 if err != nil {
122 t.Error("error during ReadPacket", err)
123 }
124 newPacket.ByteValue = nil
125 if !bytes.Equal(newPacket.ByteValue, packet.ByteValue) {
126 t.Error("packets should be the same")
127 }
128 }
129
130 func TestBinaryInteger(t *testing.T) {
131 // data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.7
132 var data = []struct {
133 v int64
134 e []byte
135 }{
136 {v: 0, e: []byte{0x02, 0x01, 0x00}},
137 {v: 127, e: []byte{0x02, 0x01, 0x7F}},
138 {v: 128, e: []byte{0x02, 0x02, 0x00, 0x80}},
139 {v: 256, e: []byte{0x02, 0x02, 0x01, 0x00}},
140 {v: -128, e: []byte{0x02, 0x01, 0x80}},
141 {v: -129, e: []byte{0x02, 0x02, 0xFF, 0x7F}},
142 }
143
144 for _, d := range data {
145 if b := NewInteger(ClassUniversal, TypePrimitive, TagInteger, int64(d.v), "").Bytes(); !bytes.Equal(d.e, b) {
146 t.Errorf("Wrong binary generated for %d : got % X, expected % X", d.v, b, d.e)
147 }
148 }
149 }
150
151 func TestBinaryOctetString(t *testing.T) {
152 // data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.10
153
154 if !bytes.Equal([]byte{0x04, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, NewString(ClassUniversal, TypePrimitive, TagOctetString, "\x01\x23\x45\x67\x89\xab\xcd\xef", "").Bytes()) {
155 t.Error("wrong binary generated")
156 }
157 }