mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
492 lines
9.9 KiB
492 lines
9.9 KiB
package ber |
|
|
|
import ( |
|
"bytes" |
|
"fmt" |
|
"io" |
|
"reflect" |
|
) |
|
|
|
type Packet struct { |
|
ClassType uint8 |
|
TagType uint8 |
|
Tag uint8 |
|
Value interface{} |
|
ByteValue []byte |
|
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 ( |
|
TypePrimitive = 0 // xx0xxxxxb |
|
TypeConstructed = 32 // xx1xxxxxb |
|
TypeBitmask = 32 // xx1xxxxxb |
|
) |
|
|
|
var TypeMap = map[uint8]string{ |
|
TypePrimitive: "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) 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, 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 string(data) |
|
} |
|
|
|
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]) |
|
p.ByteValue = value_data |
|
|
|
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 p.DataLength() > 127 || 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.ValueOf(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, TypePrimitive, 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 |
|
}
|
|
|