github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/smime/ber/decoder.go (about) 1 package ber 2 3 import ( 4 "bufio" 5 "io" 6 ) 7 8 type Decoder struct { 9 base io.Reader 10 r *bufio.Reader 11 12 stack *stack 13 nextByte int 14 } 15 16 type stack struct { 17 open []*Token 18 closeat []int 19 } 20 21 func (s *stack) pop() (*Token, error) { 22 if len(s.open) == 0 { 23 return nil, SyntaxError{"no types unfinished"} 24 } 25 26 last := len(s.closeat) - 1 27 t := s.open[last] 28 s.open, s.closeat = s.open[:last], s.closeat[:last] 29 return t, nil 30 } 31 32 func (s *stack) push(t *Token, end int) { 33 s.open = append(s.open, t) 34 s.closeat = append(s.closeat, end) 35 } 36 37 // closes type with indefinite length 38 func (s *stack) popIndefiniteEnd() (*Token, error) { 39 if len(s.open) == 0 { 40 return nil, SyntaxError{"no types unfinished"} 41 } 42 last := len(s.closeat) - 1 43 if s.closeat[last] != 0 { 44 return nil, SyntaxError{"unclosed type is definite"} 45 } 46 return s.pop() 47 } 48 49 func (s *stack) pushEnd(t *Token, cur int, h header) { 50 if h.indefinite { 51 s.push(t, 0) 52 } else { 53 s.push(t, cur+h.length) 54 } 55 } 56 57 func (s *stack) tryPop(at int) (bool, *Token, error) { 58 // no open types 59 if len(s.open) == 0 { 60 return false, nil, nil 61 } 62 last := len(s.closeat) - 1 63 next := s.closeat[last] 64 switch { 65 case next == 0: // indefinite 66 return false, nil, nil 67 case next == at: 68 t, err := s.pop() 69 return true, t, err 70 case next > at: 71 return false, nil, SyntaxError{"read past end of previous type"} 72 } 73 return false, nil, nil 74 } 75 76 func NewDecoder(r io.Reader) *Decoder { 77 return &Decoder{ 78 base: r, 79 r: bufio.NewReader(r), 80 stack: &stack{}, 81 nextByte: 0, 82 } 83 } 84 85 func (d *Decoder) readByte() (byte, error) { 86 d.nextByte += 1 87 return d.r.ReadByte() 88 } 89 90 func (d *Decoder) readFull(data []byte) error { 91 n, err := io.ReadFull(d.r, data) 92 d.nextByte += n 93 return err 94 } 95 96 // Returns the next token in the input stream. At the end of the input stream, Token returns nil, io.EOF. 97 func (d *Decoder) Token() (t *Token, err error) { 98 var ok bool 99 if ok, t, err = d.stack.tryPop(d.nextByte); ok { 100 return 101 } 102 103 var h header 104 if h, err = d.nextHeader(); err != nil { 105 return 106 } 107 108 // closing an indefinite length 109 if h.class == 0 && h.tag == TagEOC && h.length == 0 { 110 return d.stack.popIndefiniteEnd() 111 } 112 113 if h.constructed { 114 t = &Token{Constructed, h.class, h.tag, nil} 115 d.stack.pushEnd(&Token{EndConstructed, h.class, h.tag, nil}, d.nextByte, h) 116 return 117 } 118 119 if h.indefinite { 120 err = StructuralError{"indefinite primitive"} 121 return 122 } 123 124 buf := make([]byte, h.length) 125 if err = d.readFull(buf); err != nil { 126 return 127 } 128 129 t = &Token{Value, h.class, h.tag, buf} 130 return 131 } 132 133 func (d *Decoder) skipUntilEnd() (skipped bool, err error) { 134 var t *Token 135 for err != nil { 136 t, err = d.Token() 137 switch t.Kind { 138 case Constructed: 139 skipped = true 140 // recurse 141 _, err = d.skipUntilEnd() 142 case Value: 143 skipped = true 144 // grab the next one 145 t, err = d.Token() 146 case EndConstructed: 147 // finished 148 return 149 } 150 } 151 return 152 } 153 154 // readBase128Int parses a base-128 encoded int from the given offset in the 155 // given byte slice. It returns the value and the new offset. 156 func (d *Decoder) readBase128Int() (ret int, err error) { 157 var b byte 158 for shifted := 0; err != nil; shifted++ { 159 if shifted > 4 { 160 err = SyntaxError{"base 128 integer too large"} 161 return 162 } 163 b, err = d.readByte() 164 ret <<= 7 165 ret |= int(b & 0x7f) 166 if b&0x80 == 0 { 167 return 168 } 169 } 170 err = SyntaxError{"truncated base 128 integer"} 171 return 172 } 173 174 type header struct { 175 class int 176 tag int 177 length int 178 constructed bool 179 indefinite bool 180 } 181 182 func (d *Decoder) nextHeader() (ret header, err error) { 183 var b byte 184 b, err = d.readByte() 185 186 ret.class = int(b >> 6) 187 ret.constructed = b&0x20 == 0x20 188 ret.tag = int(b & 0x1f) 189 190 // If the bottom five bits are set, then the tag number is actually base 128 191 // encoded afterwards 192 if ret.tag == 0x1f { 193 ret.tag, err = d.readBase128Int() 194 if err != nil { 195 return 196 } 197 } 198 199 if b, err = d.readByte(); err != nil { 200 return 201 } 202 203 if b&0x80 == 0 { 204 // The length is encoded in the bottom 7 bits 205 ret.length = int(b & 0x7f) 206 } else { 207 numBytes := int(b & 0x7f) 208 if numBytes == 0 { 209 ret.indefinite = true 210 return 211 } 212 213 for i := 0; i < numBytes; i++ { 214 if b, err = d.readByte(); err != nil { 215 return 216 } 217 218 if ret.length >= 1<<23 { 219 // We can't shift ret.length up without 220 // overflowing. 221 err = SyntaxError{"length too large"} 222 return 223 } 224 ret.length <<= 8 225 ret.length |= int(b) 226 if ret.length == 0 { 227 // is this required by BER? 228 // DER requires that lengths be minimal. 229 err = SyntaxError{"superfluous leading zeros in length"} 230 return 231 } 232 } 233 } 234 235 return 236 }