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.

ber.go 14KB

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