github.com/Hyperledger-TWGC/tjfoc-gm@v1.4.0/x509/ber.go (about) 1 package x509 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 //fmt.Printf("\n====> Starting readObject at offset: %d\n\n", offset) 137 tagStart := offset 138 b := ber[offset] 139 offset++ 140 tag := b & 0x1F // last 5 bits 141 if tag == 0x1F { 142 tag = 0 143 for ber[offset] >= 0x80 { 144 tag = tag*128 + ber[offset] - 0x80 145 offset++ 146 } 147 tag = tag*128 + ber[offset] - 0x80 148 offset++ 149 } 150 tagEnd := offset 151 152 kind := b & 0x20 153 /* 154 if kind == 0 { 155 fmt.Print("--> Primitive\n") 156 } else { 157 fmt.Print("--> Constructed\n") 158 } 159 */ 160 // read length 161 var length int 162 l := ber[offset] 163 offset++ 164 indefinite := false 165 if l > 0x80 { 166 numberOfBytes := (int)(l & 0x7F) 167 if numberOfBytes > 4 { // int is only guaranteed to be 32bit 168 return nil, 0, errors.New("ber2der: BER tag length too long") 169 } 170 if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F { 171 return nil, 0, errors.New("ber2der: BER tag length is negative") 172 } 173 if 0x0 == (int)(ber[offset]) { 174 return nil, 0, errors.New("ber2der: BER tag length has leading zero") 175 } 176 //fmt.Printf("--> (compute length) indicator byte: %x\n", l) 177 //fmt.Printf("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes]) 178 for i := 0; i < numberOfBytes; i++ { 179 length = length*256 + (int)(ber[offset]) 180 offset++ 181 } 182 } else if l == 0x80 { 183 indefinite = true 184 } else { 185 length = (int)(l) 186 } 187 188 //fmt.Printf("--> length : %d\n", length) 189 contentEnd := offset + length 190 if contentEnd > len(ber) { 191 return nil, 0, errors.New("ber2der: BER tag length is more than available data") 192 } 193 //fmt.Printf("--> content start : %d\n", offset) 194 //fmt.Printf("--> content end : %d\n", contentEnd) 195 //fmt.Printf("--> content : % X\n", ber[offset:contentEnd]) 196 var obj asn1Object 197 if indefinite && kind == 0 { 198 return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding") 199 } 200 if kind == 0 { 201 obj = asn1Primitive{ 202 tagBytes: ber[tagStart:tagEnd], 203 length: length, 204 content: ber[offset:contentEnd], 205 } 206 } else { 207 var subObjects []asn1Object 208 for (offset < contentEnd) || indefinite { 209 var subObj asn1Object 210 var err error 211 subObj, offset, err = readObject(ber, offset) 212 if err != nil { 213 return nil, 0, err 214 } 215 subObjects = append(subObjects, subObj) 216 217 if indefinite { 218 terminated, err := isIndefiniteTermination(ber, offset) 219 if err != nil { 220 return nil, 0, err 221 } 222 223 if terminated { 224 break 225 } 226 } 227 } 228 obj = asn1Structured{ 229 tagBytes: ber[tagStart:tagEnd], 230 content: subObjects, 231 } 232 } 233 234 // Apply indefinite form length with 0x0000 terminator. 235 if indefinite { 236 contentEnd = offset + 2 237 } 238 239 return obj, contentEnd, nil 240 } 241 242 func isIndefiniteTermination(ber []byte, offset int) (bool, error) { 243 if len(ber)-offset < 2 { 244 return false, errors.New("ber2der: Invalid BER format") 245 } 246 247 return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil 248 }