...

Source file src/vendor/golang.org/x/crypto/cryptobyte/builder.go

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

View as plain text