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 }