builder.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. // AddUint64 appends a big-endian, 64-bit value to the byte string.
  86. func (b *Builder) AddUint64(v uint64) {
  87. 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))
  88. }
  89. // AddBytes appends a sequence of bytes to the byte string.
  90. func (b *Builder) AddBytes(v []byte) {
  91. b.add(v...)
  92. }
  93. // BuilderContinuation is a continuation-passing interface for building
  94. // length-prefixed byte sequences. Builder methods for length-prefixed
  95. // sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
  96. // supplied to them. The child builder passed to the continuation can be used
  97. // to build the content of the length-prefixed sequence. For example:
  98. //
  99. // parent := cryptobyte.NewBuilder()
  100. // parent.AddUint8LengthPrefixed(func (child *Builder) {
  101. // child.AddUint8(42)
  102. // child.AddUint8LengthPrefixed(func (grandchild *Builder) {
  103. // grandchild.AddUint8(5)
  104. // })
  105. // })
  106. //
  107. // It is an error to write more bytes to the child than allowed by the reserved
  108. // length prefix. After the continuation returns, the child must be considered
  109. // invalid, i.e. users must not store any copies or references of the child
  110. // that outlive the continuation.
  111. //
  112. // If the continuation panics with a value of type BuildError then the inner
  113. // error will be returned as the error from Bytes. If the child panics
  114. // otherwise then Bytes will repanic with the same value.
  115. type BuilderContinuation func(child *Builder)
  116. // BuildError wraps an error. If a BuilderContinuation panics with this value,
  117. // the panic will be recovered and the inner error will be returned from
  118. // Builder.Bytes.
  119. type BuildError struct {
  120. Err error
  121. }
  122. // AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
  123. func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
  124. b.addLengthPrefixed(1, false, f)
  125. }
  126. // AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
  127. func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
  128. b.addLengthPrefixed(2, false, f)
  129. }
  130. // AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
  131. func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
  132. b.addLengthPrefixed(3, false, f)
  133. }
  134. // AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.
  135. func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
  136. b.addLengthPrefixed(4, false, f)
  137. }
  138. func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
  139. if !*b.inContinuation {
  140. *b.inContinuation = true
  141. defer func() {
  142. *b.inContinuation = false
  143. r := recover()
  144. if r == nil {
  145. return
  146. }
  147. if buildError, ok := r.(BuildError); ok {
  148. b.err = buildError.Err
  149. } else {
  150. panic(r)
  151. }
  152. }()
  153. }
  154. f(arg)
  155. }
  156. func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
  157. // Subsequent writes can be ignored if the builder has encountered an error.
  158. if b.err != nil {
  159. return
  160. }
  161. offset := len(b.result)
  162. b.add(make([]byte, lenLen)...)
  163. if b.inContinuation == nil {
  164. b.inContinuation = new(bool)
  165. }
  166. b.child = &Builder{
  167. result: b.result,
  168. fixedSize: b.fixedSize,
  169. offset: offset,
  170. pendingLenLen: lenLen,
  171. pendingIsASN1: isASN1,
  172. inContinuation: b.inContinuation,
  173. }
  174. b.callContinuation(f, b.child)
  175. b.flushChild()
  176. if b.child != nil {
  177. panic("cryptobyte: internal error")
  178. }
  179. }
  180. func (b *Builder) flushChild() {
  181. if b.child == nil {
  182. return
  183. }
  184. b.child.flushChild()
  185. child := b.child
  186. b.child = nil
  187. if child.err != nil {
  188. b.err = child.err
  189. return
  190. }
  191. length := len(child.result) - child.pendingLenLen - child.offset
  192. if length < 0 {
  193. panic("cryptobyte: internal error") // result unexpectedly shrunk
  194. }
  195. if child.pendingIsASN1 {
  196. // For ASN.1, we reserved a single byte for the length. If that turned out
  197. // to be incorrect, we have to move the contents along in order to make
  198. // space.
  199. if child.pendingLenLen != 1 {
  200. panic("cryptobyte: internal error")
  201. }
  202. var lenLen, lenByte uint8
  203. if int64(length) > 0xfffffffe {
  204. b.err = errors.New("pending ASN.1 child too long")
  205. return
  206. } else if length > 0xffffff {
  207. lenLen = 5
  208. lenByte = 0x80 | 4
  209. } else if length > 0xffff {
  210. lenLen = 4
  211. lenByte = 0x80 | 3
  212. } else if length > 0xff {
  213. lenLen = 3
  214. lenByte = 0x80 | 2
  215. } else if length > 0x7f {
  216. lenLen = 2
  217. lenByte = 0x80 | 1
  218. } else {
  219. lenLen = 1
  220. lenByte = uint8(length)
  221. length = 0
  222. }
  223. // Insert the initial length byte, make space for successive length bytes,
  224. // and adjust the offset.
  225. child.result[child.offset] = lenByte
  226. extraBytes := int(lenLen - 1)
  227. if extraBytes != 0 {
  228. child.add(make([]byte, extraBytes)...)
  229. childStart := child.offset + child.pendingLenLen
  230. copy(child.result[childStart+extraBytes:], child.result[childStart:])
  231. }
  232. child.offset++
  233. child.pendingLenLen = extraBytes
  234. }
  235. l := length
  236. for i := child.pendingLenLen - 1; i >= 0; i-- {
  237. child.result[child.offset+i] = uint8(l)
  238. l >>= 8
  239. }
  240. if l != 0 {
  241. b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
  242. return
  243. }
  244. if b.fixedSize && &b.result[0] != &child.result[0] {
  245. panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer")
  246. }
  247. b.result = child.result
  248. }
  249. func (b *Builder) add(bytes ...byte) {
  250. if b.err != nil {
  251. return
  252. }
  253. if b.child != nil {
  254. panic("cryptobyte: attempted write while child is pending")
  255. }
  256. if len(b.result)+len(bytes) < len(bytes) {
  257. b.err = errors.New("cryptobyte: length overflow")
  258. }
  259. if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
  260. b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
  261. return
  262. }
  263. b.result = append(b.result, bytes...)
  264. }
  265. // Unwrite rolls back non-negative n bytes written directly to the Builder.
  266. // An attempt by a child builder passed to a continuation to unwrite bytes
  267. // from its parent will panic.
  268. func (b *Builder) Unwrite(n int) {
  269. if b.err != nil {
  270. return
  271. }
  272. if b.child != nil {
  273. panic("cryptobyte: attempted unwrite while child is pending")
  274. }
  275. length := len(b.result) - b.pendingLenLen - b.offset
  276. if length < 0 {
  277. panic("cryptobyte: internal error")
  278. }
  279. if n < 0 {
  280. panic("cryptobyte: attempted to unwrite negative number of bytes")
  281. }
  282. if n > length {
  283. panic("cryptobyte: attempted to unwrite more than was written")
  284. }
  285. b.result = b.result[:len(b.result)-n]
  286. }
  287. // A MarshalingValue marshals itself into a Builder.
  288. type MarshalingValue interface {
  289. // Marshal is called by Builder.AddValue. It receives a pointer to a builder
  290. // to marshal itself into. It may return an error that occurred during
  291. // marshaling, such as unset or invalid values.
  292. Marshal(b *Builder) error
  293. }
  294. // AddValue calls Marshal on v, passing a pointer to the builder to append to.
  295. // If Marshal returns an error, it is set on the Builder so that subsequent
  296. // appends don't have an effect.
  297. func (b *Builder) AddValue(v MarshalingValue) {
  298. err := v.Marshal(b)
  299. if err != nil {
  300. b.err = err
  301. }
  302. }