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.

103 lines
2.1 KiB

  1. package ber
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "math"
  7. )
  8. func readIdentifier(reader io.Reader) (Identifier, int, error) {
  9. identifier := Identifier{}
  10. read := 0
  11. // identifier byte
  12. b, err := readByte(reader)
  13. if err != nil {
  14. if Debug {
  15. fmt.Printf("error reading identifier byte: %v\n", err)
  16. }
  17. return Identifier{}, read, err
  18. }
  19. read++
  20. identifier.ClassType = Class(b) & ClassBitmask
  21. identifier.TagType = Type(b) & TypeBitmask
  22. if tag := Tag(b) & TagBitmask; tag != HighTag {
  23. // short-form tag
  24. identifier.Tag = tag
  25. return identifier, read, nil
  26. }
  27. // high-tag-number tag
  28. tagBytes := 0
  29. for {
  30. b, err := readByte(reader)
  31. if err != nil {
  32. if Debug {
  33. fmt.Printf("error reading high-tag-number tag byte %d: %v\n", tagBytes, err)
  34. }
  35. return Identifier{}, read, err
  36. }
  37. tagBytes++
  38. read++
  39. // Lowest 7 bits get appended to the tag value (x.690, 8.1.2.4.2.b)
  40. identifier.Tag <<= 7
  41. identifier.Tag |= Tag(b) & HighTagValueBitmask
  42. // First byte may not be all zeros (x.690, 8.1.2.4.2.c)
  43. if tagBytes == 1 && identifier.Tag == 0 {
  44. return Identifier{}, read, errors.New("invalid first high-tag-number tag byte")
  45. }
  46. // Overflow of int64
  47. // TODO: support big int tags?
  48. if tagBytes > 9 {
  49. return Identifier{}, read, errors.New("high-tag-number tag overflow")
  50. }
  51. // Top bit of 0 means this is the last byte in the high-tag-number tag (x.690, 8.1.2.4.2.a)
  52. if Tag(b)&HighTagContinueBitmask == 0 {
  53. break
  54. }
  55. }
  56. return identifier, read, nil
  57. }
  58. func encodeIdentifier(identifier Identifier) []byte {
  59. b := []byte{0x0}
  60. b[0] |= byte(identifier.ClassType)
  61. b[0] |= byte(identifier.TagType)
  62. if identifier.Tag < HighTag {
  63. // Short-form
  64. b[0] |= byte(identifier.Tag)
  65. } else {
  66. // high-tag-number
  67. b[0] |= byte(HighTag)
  68. tag := identifier.Tag
  69. highBit := uint(63)
  70. for {
  71. if tag&(1<<highBit) != 0 {
  72. break
  73. }
  74. highBit--
  75. }
  76. tagBytes := int(math.Ceil(float64(highBit) / 7.0))
  77. for i := tagBytes - 1; i >= 0; i-- {
  78. offset := uint(i) * 7
  79. mask := Tag(0x7f) << offset
  80. tagByte := (tag & mask) >> offset
  81. if i != 0 {
  82. tagByte |= 0x80
  83. }
  84. b = append(b, byte(tagByte))
  85. }
  86. }
  87. return b
  88. }