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 func newOIDFromDER(der []byte) (OID, bool) {
28 if len(der) == 0 || der[len(der)-1]&0x80 != 0 {
29 return OID{}, false
30 }
31
32 start := 0
33 for i, v := range der {
34
35
36
37 if i == start && v == 0x80 {
38 return OID{}, false
39 }
40 if v&0x80 == 0 {
41 start = i + 1
42 }
43 }
44
45 return OID{der}, true
46 }
47
48
49 func OIDFromInts(oid []uint64) (OID, error) {
50 if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
51 return OID{}, errInvalidOID
52 }
53
54 length := base128IntLength(oid[0]*40 + oid[1])
55 for _, v := range oid[2:] {
56 length += base128IntLength(v)
57 }
58
59 der := make([]byte, 0, length)
60 der = appendBase128Int(der, oid[0]*40+oid[1])
61 for _, v := range oid[2:] {
62 der = appendBase128Int(der, v)
63 }
64 return OID{der}, nil
65 }
66
67 func base128IntLength(n uint64) int {
68 if n == 0 {
69 return 1
70 }
71 return (bits.Len64(n) + 6) / 7
72 }
73
74 func appendBase128Int(dst []byte, n uint64) []byte {
75 for i := base128IntLength(n) - 1; i >= 0; i-- {
76 o := byte(n >> uint(i*7))
77 o &= 0x7f
78 if i != 0 {
79 o |= 0x80
80 }
81 dst = append(dst, o)
82 }
83 return dst
84 }
85
86
87 func (oid OID) Equal(other OID) bool {
88
89
90 return bytes.Equal(oid.der, other.der)
91 }
92
93 func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, failed bool) {
94 offset = initOffset
95 var ret64 int64
96 for shifted := 0; offset < len(bytes); shifted++ {
97
98
99 if shifted == 5 {
100 failed = true
101 return
102 }
103 ret64 <<= 7
104 b := bytes[offset]
105
106
107 if shifted == 0 && b == 0x80 {
108 failed = true
109 return
110 }
111 ret64 |= int64(b & 0x7f)
112 offset++
113 if b&0x80 == 0 {
114 ret = int(ret64)
115
116 if ret64 > math.MaxInt32 {
117 failed = true
118 }
119 return
120 }
121 }
122 failed = true
123 return
124 }
125
126
127
128
129 func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool {
130 if len(other) < 2 {
131 return false
132 }
133 v, offset, failed := parseBase128Int(oid.der, 0)
134 if failed {
135
136
137 return false
138 }
139 if v < 80 {
140 a, b := v/40, v%40
141 if other[0] != a || other[1] != b {
142 return false
143 }
144 } else {
145 a, b := 2, v-80
146 if other[0] != a || other[1] != b {
147 return false
148 }
149 }
150
151 i := 2
152 for ; offset < len(oid.der); i++ {
153 v, offset, failed = parseBase128Int(oid.der, offset)
154 if failed {
155
156
157 return false
158 }
159 if v != other[i] {
160 return false
161 }
162 }
163
164 return i == len(other)
165 }
166
167
168 func (oid OID) String() string {
169 var b strings.Builder
170 b.Grow(32)
171 const (
172 valSize = 64
173 bitsPerByte = 7
174 maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1
175 )
176 var (
177 start = 0
178 val = uint64(0)
179 numBuf = make([]byte, 0, 21)
180 bigVal *big.Int
181 overflow bool
182 )
183 for i, v := range oid.der {
184 curVal := v & 0x7F
185 valEnd := v&0x80 == 0
186 if valEnd {
187 if start != 0 {
188 b.WriteByte('.')
189 }
190 }
191 if !overflow && val > maxValSafeShift {
192 if bigVal == nil {
193 bigVal = new(big.Int)
194 }
195 bigVal = bigVal.SetUint64(val)
196 overflow = true
197 }
198 if overflow {
199 bigVal = bigVal.Lsh(bigVal, bitsPerByte).Or(bigVal, big.NewInt(int64(curVal)))
200 if valEnd {
201 if start == 0 {
202 b.WriteString("2.")
203 bigVal = bigVal.Sub(bigVal, big.NewInt(80))
204 }
205 numBuf = bigVal.Append(numBuf, 10)
206 b.Write(numBuf)
207 numBuf = numBuf[:0]
208 val = 0
209 start = i + 1
210 overflow = false
211 }
212 continue
213 }
214 val <<= bitsPerByte
215 val |= uint64(curVal)
216 if valEnd {
217 if start == 0 {
218 if val < 80 {
219 b.Write(strconv.AppendUint(numBuf, val/40, 10))
220 b.WriteByte('.')
221 b.Write(strconv.AppendUint(numBuf, val%40, 10))
222 } else {
223 b.WriteString("2.")
224 b.Write(strconv.AppendUint(numBuf, val-80, 10))
225 }
226 } else {
227 b.Write(strconv.AppendUint(numBuf, val, 10))
228 }
229 val = 0
230 start = i + 1
231 }
232 }
233 return b.String()
234 }
235
236 func (oid OID) toASN1OID() (asn1.ObjectIdentifier, bool) {
237 out := make([]int, 0, len(oid.der)+1)
238
239 const (
240 valSize = 31
241 bitsPerByte = 7
242 maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1
243 )
244
245 val := 0
246
247 for _, v := range oid.der {
248 if val > maxValSafeShift {
249 return nil, false
250 }
251
252 val <<= bitsPerByte
253 val |= int(v & 0x7F)
254
255 if v&0x80 == 0 {
256 if len(out) == 0 {
257 if val < 80 {
258 out = append(out, val/40)
259 out = append(out, val%40)
260 } else {
261 out = append(out, 2)
262 out = append(out, val-80)
263 }
264 val = 0
265 continue
266 }
267 out = append(out, val)
268 val = 0
269 }
270 }
271
272 return out, true
273 }
274
View as plain text