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.

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