builder.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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. // Builders either allocate space as needed, or are ‘fixed’, which means that
  11. // they write into a given buffer and produce an error if it's exhausted.
  12. //
  13. // The zero value is a usable Builder that allocates space as needed.
  14. //
  15. // Simple values are marshaled and appended to a Builder using methods on the
  16. // Builder. Length-prefixed values are marshaled by providing a
  17. // BuilderContinuation, which is a function that writes the inner contents of
  18. // the value to a given Builder. See the documentation for BuilderContinuation
  19. // for details.
  20. type Builder struct {
  21. err error
  22. result []byte
  23. fixedSize bool
  24. child *Builder
  25. offset int
  26. pendingLenLen int
  27. pendingIsASN1 bool
  28. inContinuation *bool
  29. }
  30. // NewBuilder creates a Builder that appends its output to the given buffer.
  31. // Like append(), the slice will be reallocated if its capacity is exceeded.
  32. // Use Bytes to get the final buffer.
  33. func NewBuilder(buffer []byte) *Builder {
  34. return &Builder{
  35. result: buffer,
  36. }
  37. }
  38. // NewFixedBuilder creates a Builder that appends its output into the given
  39. // buffer. This builder does not reallocate the output buffer. Writes that
  40. // would exceed the buffer's capacity are treated as an error.
  41. func NewFixedBuilder(buffer []byte) *Builder {
  42. return &Builder{
  43. result: buffer,
  44. fixedSize: true,
  45. }
  46. }
  47. // SetError sets the value to be returned as the error from Bytes. Writes
  48. // performed after calling SetError are ignored.
  49. func (b *Builder) SetError(err error) {
  50. b.err = err
  51. }
  52. // Bytes returns the bytes written by the builder or an error if one has
  53. // occurred during building.
  54. func (b *Builder) Bytes() ([]byte, error) {
  55. if b.err != nil {
  56. return nil, b.err
  57. }
  58. return b.result[b.offset:], nil
  59. }
  60. // BytesOrPanic returns the bytes written by the builder or panics if an error
  61. // has occurred during building.
  62. func (b *Builder) BytesOrPanic() []byte {
  63. if b.err != nil {
  64. panic(b.err)
  65. }
  66. return b.result[b.offset:]
  67. }
  68. // AddUint8 appends an 8-bit value to the byte string.
  69. func (b *Builder) AddUint8(v uint8) {
  70. b.add(byte(v))
  71. }
  72. // AddUint16 appends a big-endian, 16-bit value to the byte string.
  73. func (b *Builder) AddUint16(v uint16) {
  74. b.add(byte(v>>8), byte(v))
  75. }
  76. // AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
  77. // byte of the 32-bit input value is silently truncated.
  78. func (b *Builder) AddUint24(v uint32) {
  79. b.add(byte(v>>16), byte(v>>8), byte(v))
  80. }
  81. // AddUint32 appends a big-endian, 32-bit value to the byte string.
  82. func (b *Builder) AddUint32(v uint32) {
  83. b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  84. }
  85. // AddUint48 appends a big-endian, 48-bit value to the byte string.
  86. func (b *Builder) AddUint48(v uint64) {
  87. b.add(byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  88. }
  89. // AddUint64 appends a big-endian, 64-bit value to the byte string.
  90. func (b *Builder) AddUint64(v uint64) {
  91. b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  92. }
  93. // AddBytes appends a sequence of bytes to the byte string.
  94. func (b *Builder) AddBytes(v []byte) {
  95. b.add(v...)
  96. }
  97. // BuilderContinuation is a continuation-passing interface for building
  98. // length-prefixed byte sequences. Builder methods for length-prefixed
  99. // sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
  100. // supplied to them. The child builder passed to the continuation can be used
  101. // to build the content of the length-prefixed sequence. For example:
  102. //
  103. // parent := cryptobyte.NewBuilder()
  104. // parent.AddUint8LengthPrefixed(func (child *Builder) {
  105. // child.AddUint8(42)
  106. // child.AddUint8LengthPrefixed(func (grandchild *Builder) {
  107. // grandchild.AddUint8(5)
  108. // })
  109. // })
  110. //
  111. // It is an error to write more bytes to the child than allowed by the reserved
  112. // length prefix. After the continuation returns, the child must be considered
  113. // invalid, i.e. users must not store any copies or references of the child
  114. // that outlive the continuation.
  115. //
  116. // If the continuation panics with a value of type BuildError then the inner
  117. // error will be returned as the error from Bytes. If the child panics
  118. // otherwise then Bytes will repanic with the same value.
  119. type BuilderContinuation func(child *Builder)
  120. // BuildError wraps an error. If a BuilderContinuation panics with this value,
  121. // the panic will be recovered and the inner error will be returned from
  122. // Builder.Bytes.
  123. type BuildError struct {
  124. Err error
  125. }
  126. // AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
  127. func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
  128. b.addLengthPrefixed(1, false, f)
  129. }
  130. // AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
  131. func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
  132. b.addLengthPrefixed(2, false, f)
  133. }
  134. // AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
  135. func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
  136. b.addLengthPrefixed(3, false, f)
  137. }
  138. // AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.
  139. func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
  140. b.addLengthPrefixed(4, false, f)
  141. }
  142. func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
  143. if !*b.inContinuation {
  144. *b.inContinuation = true
  145. defer func() {
  146. *b.inContinuation = false
  147. r := recover()
  148. if r == nil {
  149. return
  150. }
  151. if buildError, ok := r.(BuildError); ok {
  152. b.err = buildError.Err
  153. } else {
  154. panic(r)
  155. }
  156. }()
  157. }
  158. f(arg)
  159. }
  160. func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
  161. // Subsequent writes can be ignored if the builder has encountered an error.
  162. if b.err != nil {
  163. return
  164. }
  165. offset := len(b.result)
  166. b.add(make([]byte, lenLen)...)
  167. if b.inContinuation == nil {
  168. b.inContinuation = new(bool)
  169. }
  170. b.child = &Builder{
  171. result: b.result,
  172. fixedSize: b.fixedSize,
  173. offset: offset,
  174. pendingLenLen: lenLen,
  175. pendingIsASN1: isASN1,
  176. inContinuation: b.inContinuation,
  177. }
  178. b.callContinuation(f, b.child)
  179. b.flushChild()
  180. if b.child != nil {
  181. panic("cryptobyte: internal error")
  182. }
  183. }
  184. func (b *Builder) flushChild() {
  185. if b.child == nil {
  186. return
  187. }
  188. b.child.flushChild()
  189. child := b.child
  190. b.child = nil
  191. if child.err != nil {
  192. b.err = child.err
  193. return
  194. }
  195. length := len(child.result) - child.pendingLenLen - child.offset
  196. if length < 0 {
  197. panic("cryptobyte: internal error") // result unexpectedly shrunk
  198. }
  199. if child.pendingIsASN1 {
  200. // For ASN.1, we reserved a single byte for the length. If that turned out
  201. // to be incorrect, we have to move the contents along in order to make
  202. // space.
  203. if child.pendingLenLen != 1 {
  204. panic("cryptobyte: internal error")
  205. }
  206. var lenLen, lenByte uint8
  207. if int64(length) > 0xfffffffe {
  208. b.err = errors.New("pending ASN.1 child too long")
  209. return
  210. } else if length > 0xffffff {
  211. lenLen = 5
  212. lenByte = 0x80 | 4
  213. } else if length > 0xffff {
  214. lenLen = 4
  215. lenByte = 0x80 | 3
  216. } else if length > 0xff {
  217. lenLen = 3
  218. lenByte = 0x80 | 2
  219. } else if length > 0x7f {
  220. lenLen = 2
  221. lenByte = 0x80 | 1
  222. } else {
  223. lenLen = 1
  224. lenByte = uint8(length)
  225. length = 0
  226. }
  227. // Insert the initial length byte, make space for successive length bytes,
  228. // and adjust the offset.
  229. child.result[child.offset] = lenByte
  230. extraBytes := int(lenLen - 1)
  231. if extraBytes != 0 {
  232. child.add(make([]byte, extraBytes)...)
  233. childStart := child.offset + child.pendingLenLen
  234. copy(child.result[childStart+extraBytes:], child.result[childStart:])
  235. }
  236. child.offset++
  237. child.pendingLenLen = extraBytes
  238. }
  239. l := length
  240. for i := child.pendingLenLen - 1; i >= 0; i-- {
  241. child.result[child.offset+i] = uint8(l)
  242. l >>= 8
  243. }
  244. if l != 0 {
  245. b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
  246. return
  247. }
  248. if b.fixedSize && &b.result[0] != &child.result[0] {
  249. panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer")
  250. }
  251. b.result = child.result
  252. }
  253. func (b *Builder) add(bytes ...byte) {
  254. if b.err != nil {
  255. return
  256. }
  257. if b.child != nil {
  258. panic("cryptobyte: attempted write while child is pending")
  259. }
  260. if len(b.result)+len(bytes) < len(bytes) {
  261. b.err = errors.New("cryptobyte: length overflow")
  262. }
  263. if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
  264. b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
  265. return
  266. }
  267. b.result = append(b.result, bytes...)
  268. }
  269. // Unwrite rolls back non-negative n bytes written directly to the Builder.
  270. // An attempt by a child builder passed to a continuation to unwrite bytes
  271. // from its parent will panic.
  272. func (b *Builder) Unwrite(n int) {
  273. if b.err != nil {
  274. return
  275. }
  276. if b.child != nil {
  277. panic("cryptobyte: attempted unwrite while child is pending")
  278. }
  279. length := len(b.result) - b.pendingLenLen - b.offset
  280. if length < 0 {
  281. panic("cryptobyte: internal error")
  282. }
  283. if n < 0 {
  284. panic("cryptobyte: attempted to unwrite negative number of bytes")
  285. }
  286. if n > length {
  287. panic("cryptobyte: attempted to unwrite more than was written")
  288. }
  289. b.result = b.result[:len(b.result)-n]
  290. }
  291. // A MarshalingValue marshals itself into a Builder.
  292. type MarshalingValue interface {
  293. // Marshal is called by Builder.AddValue. It receives a pointer to a builder
  294. // to marshal itself into. It may return an error that occurred during
  295. // marshaling, such as unset or invalid values.
  296. Marshal(b *Builder) error
  297. }
  298. // AddValue calls Marshal on v, passing a pointer to the builder to append to.
  299. // If Marshal returns an error, it is set on the Builder so that subsequent
  300. // appends don't have an effect.
  301. func (b *Builder) AddValue(v MarshalingValue) {
  302. err := v.Marshal(b)
  303. if err != nil {
  304. b.err = err
  305. }
  306. }