github.com/emmansun/gmsm@v0.29.1/pkcs7/ber.go (about) 1 package pkcs7 2 3 import ( 4 "bytes" 5 "errors" 6 ) 7 8 var encodeIndent = 0 9 10 type asn1Object interface { 11 EncodeTo(writer *bytes.Buffer) error 12 } 13 14 type asn1Structured struct { 15 tagBytes []byte 16 content []asn1Object 17 } 18 19 func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { 20 //fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes) 21 encodeIndent++ 22 inner := new(bytes.Buffer) 23 for _, obj := range s.content { 24 err := obj.EncodeTo(inner) 25 if err != nil { 26 return err 27 } 28 } 29 encodeIndent-- 30 out.Write(s.tagBytes) 31 encodeLength(out, inner.Len()) 32 out.Write(inner.Bytes()) 33 return nil 34 } 35 36 type asn1Primitive struct { 37 tagBytes []byte 38 length int 39 content []byte 40 } 41 42 func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error { 43 _, err := out.Write(p.tagBytes) 44 if err != nil { 45 return err 46 } 47 if err = encodeLength(out, p.length); err != nil { 48 return err 49 } 50 //fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length) 51 //fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content)) 52 out.Write(p.content) 53 54 return nil 55 } 56 57 func ber2der(ber []byte) ([]byte, error) { 58 if len(ber) == 0 { 59 return nil, errors.New("ber2der: input ber is empty") 60 } 61 //fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber)) 62 out := new(bytes.Buffer) 63 64 obj, _, err := readObject(ber, 0) 65 if err != nil { 66 return nil, err 67 } 68 obj.EncodeTo(out) 69 70 // if offset < len(ber) { 71 // return nil, fmt.Errorf("ber2der: Content longer than expected. Got %d, expected %d", offset, len(ber)) 72 //} 73 74 return out.Bytes(), nil 75 } 76 77 // encodes lengths that are longer than 127 into string of bytes 78 func marshalLongLength(out *bytes.Buffer, i int) (err error) { 79 n := lengthLength(i) 80 81 for ; n > 0; n-- { 82 err = out.WriteByte(byte(i >> uint((n-1)*8))) 83 if err != nil { 84 return 85 } 86 } 87 88 return nil 89 } 90 91 // computes the byte length of an encoded length value 92 func lengthLength(i int) (numBytes int) { 93 numBytes = 1 94 for i > 255 { 95 numBytes++ 96 i >>= 8 97 } 98 return 99 } 100 101 // encodes the length in DER format 102 // If the length fits in 7 bits, the value is encoded directly. 103 // 104 // Otherwise, the number of bytes to encode the length is first determined. 105 // This number is likely to be 4 or less for a 32bit length. This number is 106 // added to 0x80. The length is encoded in big endian encoding follow after 107 // 108 // Examples: 109 // length | byte 1 | bytes n 110 // 0 | 0x00 | - 111 // 120 | 0x78 | - 112 // 200 | 0x81 | 0xC8 113 // 500 | 0x82 | 0x01 0xF4 114 // 115 func encodeLength(out *bytes.Buffer, length int) (err error) { 116 if length >= 128 { 117 l := lengthLength(length) 118 err = out.WriteByte(0x80 | byte(l)) 119 if err != nil { 120 return 121 } 122 err = marshalLongLength(out, length) 123 if err != nil { 124 return 125 } 126 } else { 127 err = out.WriteByte(byte(length)) 128 if err != nil { 129 return 130 } 131 } 132 return 133 } 134 135 func readObject(ber []byte, offset int) (asn1Object, int, error) { 136 berLen := len(ber) 137 if offset >= berLen { 138 return nil, 0, errors.New("ber2der: offset is after end of ber data") 139 } 140 tagStart := offset 141 b := ber[offset] 142 offset++ 143 if offset >= berLen { 144 return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") 145 } 146 tag := b & 0x1F // last 5 bits 147 if tag == 0x1F { 148 tag = 0 149 for ber[offset] >= 0x80 { 150 tag = tag<<7 + ber[offset] - 0x80 151 offset++ 152 if offset > berLen { 153 return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") 154 } 155 } 156 // jvehent 20170227: this doesn't appear to be used anywhere... 157 //tag = tag*128 + ber[offset] - 0x80 158 offset++ 159 if offset > berLen { 160 return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") 161 } 162 } 163 tagEnd := offset 164 165 kind := b & 0x20 166 if kind == 0 { 167 debugprint("--> Primitive\n") 168 } else { 169 debugprint("--> Constructed\n") 170 } 171 // read length 172 var length int 173 l := ber[offset] 174 offset++ 175 if offset > berLen { 176 return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") 177 } 178 indefinite := false 179 if l > 0x80 { 180 numberOfBytes := (int)(l & 0x7F) 181 if numberOfBytes > 4 { // int is only guaranteed to be 32bit 182 return nil, 0, errors.New("ber2der: BER tag length too long") 183 } 184 if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F { 185 return nil, 0, errors.New("ber2der: BER tag length is negative") 186 } 187 if (int)(ber[offset]) == 0x0 { 188 return nil, 0, errors.New("ber2der: BER tag length has leading zero") 189 } 190 debugprint("--> (compute length) indicator byte: %x\n", l) 191 debugprint("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes]) 192 for i := 0; i < numberOfBytes; i++ { 193 length = length<<8 + (int)(ber[offset]) 194 offset++ 195 if offset > berLen { 196 return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") 197 } 198 } 199 } else if l == 0x80 { 200 indefinite = true 201 } else { 202 length = (int)(l) 203 } 204 if length < 0 { 205 return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length") 206 } 207 //fmt.Printf("--> length : %d\n", length) 208 contentEnd := offset + length 209 if contentEnd > len(ber) { 210 return nil, 0, errors.New("ber2der: BER tag length is more than available data") 211 } 212 debugprint("--> content start : %d\n", offset) 213 debugprint("--> content end : %d\n", contentEnd) 214 debugprint("--> content : % X\n", ber[offset:contentEnd]) 215 var obj asn1Object 216 if indefinite && kind == 0 { 217 return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding") 218 } 219 if kind == 0 { 220 obj = asn1Primitive{ 221 tagBytes: ber[tagStart:tagEnd], 222 length: length, 223 content: ber[offset:contentEnd], 224 } 225 } else { 226 var subObjects []asn1Object 227 for (offset < contentEnd) || indefinite { 228 var subObj asn1Object 229 var err error 230 subObj, offset, err = readObject(ber, offset) 231 if err != nil { 232 return nil, 0, err 233 } 234 subObjects = append(subObjects, subObj) 235 236 if indefinite { 237 terminated, err := isIndefiniteTermination(ber, offset) 238 if err != nil { 239 return nil, 0, err 240 } 241 242 if terminated { 243 break 244 } 245 } 246 } 247 obj = asn1Structured{ 248 tagBytes: ber[tagStart:tagEnd], 249 content: subObjects, 250 } 251 } 252 253 // Apply indefinite form length with 0x0000 terminator. 254 if indefinite { 255 contentEnd = offset + 2 256 } 257 258 return obj, contentEnd, nil 259 } 260 261 func isIndefiniteTermination(ber []byte, offset int) (bool, error) { 262 if len(ber)-offset < 2 { 263 return false, errors.New("ber2der: Invalid BER format") 264 } 265 266 return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil 267 } 268 269 func debugprint(format string, a ...any) { 270 //fmt.Printf(format, a) 271 }