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.
 
 
 

256 line
7.0 KiB

  1. // Copyright 2017 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package cryptobyte
  5. import (
  6. "errors"
  7. "fmt"
  8. )
  9. // A Builder builds byte strings from fixed-length and length-prefixed values.
  10. // The zero value is a usable Builder that allocates space as needed.
  11. type Builder struct {
  12. err error
  13. result []byte
  14. fixedSize bool
  15. child *Builder
  16. offset int
  17. pendingLenLen int
  18. pendingIsASN1 bool
  19. }
  20. // NewBuilder creates a Builder that appends its output to the given buffer.
  21. // Like append(), the slice will be reallocated if its capacity is exceeded.
  22. // Use Bytes to get the final buffer.
  23. func NewBuilder(buffer []byte) *Builder {
  24. return &Builder{
  25. result: buffer,
  26. }
  27. }
  28. // NewFixedBuilder creates a Builder that appends its output into the given
  29. // buffer. This builder does not reallocate the output buffer. Writes that
  30. // would exceed the buffer's capacity are treated as an error.
  31. func NewFixedBuilder(buffer []byte) *Builder {
  32. return &Builder{
  33. result: buffer,
  34. fixedSize: true,
  35. }
  36. }
  37. // Bytes returns the bytes written by the builder or an error if one has
  38. // occurred during during building.
  39. func (b *Builder) Bytes() ([]byte, error) {
  40. if b.err != nil {
  41. return nil, b.err
  42. }
  43. return b.result[b.offset:], nil
  44. }
  45. // BytesOrPanic returns the bytes written by the builder or panics if an error
  46. // has occurred during building.
  47. func (b *Builder) BytesOrPanic() []byte {
  48. if b.err != nil {
  49. panic(b.err)
  50. }
  51. return b.result[b.offset:]
  52. }
  53. // AddUint8 appends an 8-bit value to the byte string.
  54. func (b *Builder) AddUint8(v uint8) {
  55. b.add(byte(v))
  56. }
  57. // AddUint16 appends a big-endian, 16-bit value to the byte string.
  58. func (b *Builder) AddUint16(v uint16) {
  59. b.add(byte(v>>8), byte(v))
  60. }
  61. // AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
  62. // byte of the 32-bit input value is silently truncated.
  63. func (b *Builder) AddUint24(v uint32) {
  64. b.add(byte(v>>16), byte(v>>8), byte(v))
  65. }
  66. // AddUint32 appends a big-endian, 32-bit value to the byte string.
  67. func (b *Builder) AddUint32(v uint32) {
  68. b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  69. }
  70. // AddBytes appends a sequence of bytes to the byte string.
  71. func (b *Builder) AddBytes(v []byte) {
  72. b.add(v...)
  73. }
  74. // BuilderContinuation is continuation-passing interface for building
  75. // length-prefixed byte sequences. Builder methods for length-prefixed
  76. // sequences (AddUint8LengthPrefixed etc.) will invoke the BuilderContinuation
  77. // supplied to them. The child builder passed to the continuation can be used
  78. // to build the content of the length-prefixed sequence. Example:
  79. //
  80. // parent := cryptobyte.NewBuilder()
  81. // parent.AddUint8LengthPrefixed(func (child *Builder) {
  82. // child.AddUint8(42)
  83. // child.AddUint8LengthPrefixed(func (grandchild *Builder) {
  84. // grandchild.AddUint8(5)
  85. // })
  86. // })
  87. //
  88. // It is an error to write more bytes to the child than allowed by the reserved
  89. // length prefix. After the continuation returns, the child must be considered
  90. // invalid, i.e. users must not store any copies or references of the child
  91. // that outlive the continuation.
  92. type BuilderContinuation func(child *Builder)
  93. // AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
  94. func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
  95. b.addLengthPrefixed(1, false, f)
  96. }
  97. // AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
  98. func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
  99. b.addLengthPrefixed(2, false, f)
  100. }
  101. // AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
  102. func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
  103. b.addLengthPrefixed(3, false, f)
  104. }
  105. func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
  106. // Subsequent writes can be ignored if the builder has encountered an error.
  107. if b.err != nil {
  108. return
  109. }
  110. offset := len(b.result)
  111. b.add(make([]byte, lenLen)...)
  112. b.child = &Builder{
  113. result: b.result,
  114. fixedSize: b.fixedSize,
  115. offset: offset,
  116. pendingLenLen: lenLen,
  117. pendingIsASN1: isASN1,
  118. }
  119. f(b.child)
  120. b.flushChild()
  121. if b.child != nil {
  122. panic("cryptobyte: internal error")
  123. }
  124. }
  125. func (b *Builder) flushChild() {
  126. if b.child == nil {
  127. return
  128. }
  129. b.child.flushChild()
  130. child := b.child
  131. b.child = nil
  132. if child.err != nil {
  133. b.err = child.err
  134. return
  135. }
  136. length := len(child.result) - child.pendingLenLen - child.offset
  137. if length < 0 {
  138. panic("cryptobyte: internal error") // result unexpectedly shrunk
  139. }
  140. if child.pendingIsASN1 {
  141. // For ASN.1, we reserved a single byte for the length. If that turned out
  142. // to be incorrect, we have to move the contents along in order to make
  143. // space.
  144. if child.pendingLenLen != 1 {
  145. panic("cryptobyte: internal error")
  146. }
  147. var lenLen, lenByte uint8
  148. if int64(length) > 0xfffffffe {
  149. b.err = errors.New("pending ASN.1 child too long")
  150. return
  151. } else if length > 0xffffff {
  152. lenLen = 5
  153. lenByte = 0x80 | 4
  154. } else if length > 0xffff {
  155. lenLen = 4
  156. lenByte = 0x80 | 3
  157. } else if length > 0xff {
  158. lenLen = 3
  159. lenByte = 0x80 | 2
  160. } else if length > 0x7f {
  161. lenLen = 2
  162. lenByte = 0x80 | 1
  163. } else {
  164. lenLen = 1
  165. lenByte = uint8(length)
  166. length = 0
  167. }
  168. // Insert the initial length byte, make space for successive length bytes,
  169. // and adjust the offset.
  170. child.result[child.offset] = lenByte
  171. extraBytes := int(lenLen - 1)
  172. if extraBytes != 0 {
  173. child.add(make([]byte, extraBytes)...)
  174. childStart := child.offset + child.pendingLenLen
  175. copy(child.result[childStart+extraBytes:], child.result[childStart:])
  176. }
  177. child.offset++
  178. child.pendingLenLen = extraBytes
  179. }
  180. l := length
  181. for i := child.pendingLenLen - 1; i >= 0; i-- {
  182. child.result[child.offset+i] = uint8(l)
  183. l >>= 8
  184. }
  185. if l != 0 {
  186. b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
  187. return
  188. }
  189. if !b.fixedSize {
  190. b.result = child.result // In case child reallocated result.
  191. }
  192. }
  193. func (b *Builder) add(bytes ...byte) {
  194. if b.err != nil {
  195. return
  196. }
  197. if b.child != nil {
  198. panic("attempted write while child is pending")
  199. }
  200. if len(b.result)+len(bytes) < len(bytes) {
  201. b.err = errors.New("cryptobyte: length overflow")
  202. }
  203. if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
  204. b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
  205. return
  206. }
  207. b.result = append(b.result, bytes...)
  208. }
  209. // A MarshalingValue marshals itself into a Builder.
  210. type MarshalingValue interface {
  211. // Marshal is called by Builder.AddValue. It receives a pointer to a builder
  212. // to marshal itself into. It may return an error that occurred during
  213. // marshaling, such as unset or invalid values.
  214. Marshal(b *Builder) error
  215. }
  216. // AddValue calls Marshal on v, passing a pointer to the builder to append to.
  217. // If Marshal returns an error, it is set on the Builder so that subsequent
  218. // appends don't have an effect.
  219. func (b *Builder) AddValue(v MarshalingValue) {
  220. err := v.Marshal(b)
  221. if err != nil {
  222. b.err = err
  223. }
  224. }