github.com/devops-filetransfer/sshego@v7.0.4+incompatible/_vendor/golang.org/x/crypto/cryptobyte/builder.go (about)

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