1
2
3
4
5 package x509
6
7 import (
8 "bytes"
9 "encoding/asn1"
10 "errors"
11 "math"
12 "math/big"
13 "math/bits"
14 "strconv"
15 "strings"
16 )
17
18 var (
19 errInvalidOID = errors.New("invalid oid")
20 )
21
22
23 type OID struct {
24 der []byte
25 }
26
27
28 func ParseOID(oid string) (OID, error) {
29 var o OID
30 return o, o.unmarshalOIDText(oid)
31 }
32
33 func newOIDFromDER(der []byte) (OID, bool) {
34 if len(der) == 0 || der[len(der)-1]&0x80 != 0 {
35 return OID{}, false
36 }
37
38 start := 0
39 for i, v := range der {
40
41
42
43 if i == start && v == 0x80 {
44 return OID{}, false
45 }
46 if v&0x80 == 0 {
47 start = i + 1
48 }
49 }
50
51 return OID{der}, true
52 }
53
54
55 func OIDFromInts(oid []uint64) (OID, error) {
56 if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
57 return OID{}, errInvalidOID
58 }
59
60 length := base128IntLength(oid[0]*40 + oid[1])
61 for _, v := range oid[2:] {
62 length += base128IntLength(v)
63 }
64
65 der := make([]byte, 0, length)
66 der = appendBase128Int(der, oid[0]*40+oid[1])
67 for _, v := range oid[2:] {
68 der = appendBase128Int(der, v)
69 }
70 return OID{der}, nil
71 }
72
73 func base128IntLength(n uint64) int {
74 if n == 0 {
75 return 1
76 }
77 return (bits.Len64(n) + 6) / 7
78 }
79
80 func appendBase128Int(dst []byte, n uint64) []byte {
81 for i := base128IntLength(n) - 1; i >= 0; i-- {
82 o := byte(n >> uint(i*7))
83 o &= 0x7f
84 if i != 0 {
85 o |= 0x80
86 }
87 dst = append(dst, o)
88 }
89 return dst
90 }
91
92 func base128BigIntLength(n *big.Int) int {
93 if n.Cmp(big.NewInt(0)) == 0 {
94 return 1
95 }
96 return (n.BitLen() + 6) / 7
97 }
98
99 func appendBase128BigInt(dst []byte, n *big.Int) []byte {
100 if n.Cmp(big.NewInt(0)) == 0 {
101 return append(dst, 0)
102 }
103
104 for i := base128BigIntLength(n) - 1; i >= 0; i-- {
105 o := byte(big.NewInt(0).Rsh(n, uint(i)*7).Bits()[0])
106 o &= 0x7f
107 if i != 0 {
108 o |= 0x80
109 }
110 dst = append(dst, o)
111 }
112 return dst
113 }
114
115
116 func (o OID) AppendText(b []byte) ([]byte, error) {
117 return append(b, o.String()...), nil
118 }
119
120
121 func (o OID) MarshalText() ([]byte, error) {
122 return o.AppendText(nil)
123 }
124
125
126 func (o *OID) UnmarshalText(text []byte) error {
127 return o.unmarshalOIDText(string(text))
128 }
129
130 func (o *OID) unmarshalOIDText(oid string) error {
131
132
133
134 for _, c := range oid {
135 isDigit := c >= '0' && c <= '9'
136 if !isDigit && c != '.' {
137 return errInvalidOID
138 }
139 }
140
141 var (
142 firstNum string
143 secondNum string
144 )
145
146 var nextComponentExists bool
147 firstNum, oid, nextComponentExists = strings.Cut(oid, ".")
148 if !nextComponentExists {
149 return errInvalidOID
150 }
151 secondNum, oid, nextComponentExists = strings.Cut(oid, ".")
152
153 var (
154 first = big.NewInt(0)
155 second = big.NewInt(0)
156 )
157
158 if _, ok := first.SetString(firstNum, 10); !ok {
159 return errInvalidOID
160 }
161 if _, ok := second.SetString(secondNum, 10); !ok {
162 return errInvalidOID
163 }
164
165 if first.Cmp(big.NewInt(2)) > 0 || (first.Cmp(big.NewInt(2)) < 0 && second.Cmp(big.NewInt(40)) >= 0) {
166 return errInvalidOID
167 }
168
169 firstComponent := first.Mul(first, big.NewInt(40))
170 firstComponent.Add(firstComponent, second)
171
172 der := appendBase128BigInt(make([]byte, 0, 32), firstComponent)
173
174 for nextComponentExists {
175 var strNum string
176 strNum, oid, nextComponentExists = strings.Cut(oid, ".")
177 b, ok := big.NewInt(0).SetString(strNum, 10)
178 if !ok {
179 return errInvalidOID
180 }
181 der = appendBase128BigInt(der, b)
182 }
183
184 o.der = der
185 return nil
186 }
187
188
189 func (o OID) AppendBinary(b []byte) ([]byte, error) {
190 return append(b, o.der...), nil
191 }
192
193
194 func (o OID) MarshalBinary() ([]byte, error) {
195 return o.AppendBinary(nil)
196 }
197
198
199 func (o *OID) UnmarshalBinary(b []byte) error {
200 oid, ok := newOIDFromDER(bytes.Clone(b))
201 if !ok {
202 return errInvalidOID
203 }
204 *o = oid
205 return nil
206 }
207
208
209 func (oid OID) Equal(other OID) bool {
210
211
212 return bytes.Equal(oid.der, other.der)
213 }
214
215 func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, failed bool) {
216 offset = initOffset
217 var ret64 int64
218 for shifted := 0; offset < len(bytes); shifted++ {
219
220
221 if shifted == 5 {
222 failed = true
223 return
224 }
225 ret64 <<= 7
226 b := bytes[offset]
227
228
229 if shifted == 0 && b == 0x80 {
230 failed = true
231 return
232 }
233 ret64 |= int64(b & 0x7f)
234 offset++
235 if b&0x80 == 0 {
236 ret = int(ret64)
237
238 if ret64 > math.MaxInt32 {
239 failed = true
240 }
241 return
242 }
243 }
244 failed = true
245 return
246 }
247
248
249
250
251 func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool {
252 if len(other) < 2 {
253 return false
254 }
255 v, offset, failed := parseBase128Int(oid.der, 0)
256 if failed {
257
258
259 return false
260 }
261 if v < 80 {
262 a, b := v/40, v%40
263 if other[0] != a || other[1] != b {
264 return false
265 }
266 } else {
267 a, b := 2, v-80
268 if other[0] != a || other[1] != b {
269 return false
270 }
271 }
272
273 i := 2
274 for ; offset < len(oid.der); i++ {
275 v, offset, failed = parseBase128Int(oid.der, offset)
276 if failed {
277
278
279 return false
280 }
281 if i >= len(other) || v != other[i] {
282 return false
283 }
284 }
285
286 return i == len(other)
287 }
288
289
290 func (oid OID) String() string {
291 var b strings.Builder
292 b.Grow(32)
293 const (
294 valSize = 64
295 bitsPerByte = 7
296 maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1
297 )
298 var (
299 start = 0
300 val = uint64(0)
301 numBuf = make([]byte, 0, 21)
302 bigVal *big.Int
303 overflow bool
304 )
305 for i, v := range oid.der {
306 curVal := v & 0x7F
307 valEnd := v&0x80 == 0
308 if valEnd {
309 if start != 0 {
310 b.WriteByte('.')
311 }
312 }
313 if !overflow && val > maxValSafeShift {
314 if bigVal == nil {
315 bigVal = new(big.Int)
316 }
317 bigVal = bigVal.SetUint64(val)
318 overflow = true
319 }
320 if overflow {
321 bigVal = bigVal.Lsh(bigVal, bitsPerByte).Or(bigVal, big.NewInt(int64(curVal)))
322 if valEnd {
323 if start == 0 {
324 b.WriteString("2.")
325 bigVal = bigVal.Sub(bigVal, big.NewInt(80))
326 }
327 numBuf = bigVal.Append(numBuf, 10)
328 b.Write(numBuf)
329 numBuf = numBuf[:0]
330 val = 0
331 start = i + 1
332 overflow = false
333 }
334 continue
335 }
336 val <<= bitsPerByte
337 val |= uint64(curVal)
338 if valEnd {
339 if start == 0 {
340 if val < 80 {
341 b.Write(strconv.AppendUint(numBuf, val/40, 10))
342 b.WriteByte('.')
343 b.Write(strconv.AppendUint(numBuf, val%40, 10))
344 } else {
345 b.WriteString("2.")
346 b.Write(strconv.AppendUint(numBuf, val-80, 10))
347 }
348 } else {
349 b.Write(strconv.AppendUint(numBuf, val, 10))
350 }
351 val = 0
352 start = i + 1
353 }
354 }
355 return b.String()
356 }
357
358 func (oid OID) toASN1OID() (asn1.ObjectIdentifier, bool) {
359 out := make([]int, 0, len(oid.der)+1)
360
361 const (
362 valSize = 31
363 bitsPerByte = 7
364 maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1
365 )
366
367 val := 0
368
369 for _, v := range oid.der {
370 if val > maxValSafeShift {
371 return nil, false
372 }
373
374 val <<= bitsPerByte
375 val |= int(v & 0x7F)
376
377 if v&0x80 == 0 {
378 if len(out) == 0 {
379 if val < 80 {
380 out = append(out, val/40)
381 out = append(out, val%40)
382 } else {
383 out = append(out, 2)
384 out = append(out, val-80)
385 }
386 val = 0
387 continue
388 }
389 out = append(out, val)
390 val = 0
391 }
392 }
393
394 return out, true
395 }
396
View as plain text