1
2
3
4
5 package x509
6
7 import (
8 "encoding"
9 "encoding/asn1"
10 "math"
11 "testing"
12 )
13
14 var oidTests = []struct {
15 raw []byte
16 valid bool
17 str string
18 ints []uint64
19 }{
20 {[]byte{}, false, "", nil},
21 {[]byte{0x80, 0x01}, false, "", nil},
22 {[]byte{0x01, 0x80, 0x01}, false, "", nil},
23
24 {[]byte{1, 2, 3}, true, "0.1.2.3", []uint64{0, 1, 2, 3}},
25 {[]byte{41, 2, 3}, true, "1.1.2.3", []uint64{1, 1, 2, 3}},
26 {[]byte{86, 2, 3}, true, "2.6.2.3", []uint64{2, 6, 2, 3}},
27
28 {[]byte{41, 255, 255, 255, 127}, true, "1.1.268435455", []uint64{1, 1, 268435455}},
29 {[]byte{41, 0x87, 255, 255, 255, 127}, true, "1.1.2147483647", []uint64{1, 1, 2147483647}},
30 {[]byte{41, 255, 255, 255, 255, 127}, true, "1.1.34359738367", []uint64{1, 1, 34359738367}},
31 {[]byte{42, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "1.2.9223372036854775807", []uint64{1, 2, 9223372036854775807}},
32 {[]byte{43, 0x81, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "1.3.18446744073709551615", []uint64{1, 3, 18446744073709551615}},
33 {[]byte{44, 0x83, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "1.4.36893488147419103231", nil},
34 {[]byte{85, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.5.1180591620717411303423", nil},
35 {[]byte{85, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.5.19342813113834066795298815", nil},
36
37 {[]byte{255, 255, 255, 127}, true, "2.268435375", []uint64{2, 268435375}},
38 {[]byte{0x87, 255, 255, 255, 127}, true, "2.2147483567", []uint64{2, 2147483567}},
39 {[]byte{255, 127}, true, "2.16303", []uint64{2, 16303}},
40 {[]byte{255, 255, 255, 255, 127}, true, "2.34359738287", []uint64{2, 34359738287}},
41 {[]byte{255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.9223372036854775727", []uint64{2, 9223372036854775727}},
42 {[]byte{0x81, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.18446744073709551535", []uint64{2, 18446744073709551535}},
43 {[]byte{0x83, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.36893488147419103151", nil},
44 {[]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.1180591620717411303343", nil},
45 {[]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.19342813113834066795298735", nil},
46
47 {[]byte{41, 0x80 | 66, 0x80 | 44, 0x80 | 11, 33}, true, "1.1.139134369", []uint64{1, 1, 139134369}},
48 {[]byte{0x80 | 66, 0x80 | 44, 0x80 | 11, 33}, true, "2.139134289", []uint64{2, 139134289}},
49 }
50
51 func TestOID(t *testing.T) {
52 for _, v := range oidTests {
53 oid, ok := newOIDFromDER(v.raw)
54 if ok != v.valid {
55 t.Errorf("newOIDFromDER(%v) = (%v, %v); want = (OID, %v)", v.raw, oid, ok, v.valid)
56 continue
57 }
58
59 if !ok {
60 continue
61 }
62
63 if str := oid.String(); str != v.str {
64 t.Errorf("(%#v).String() = %v, want; %v", oid, str, v.str)
65 }
66
67 var asn1OID asn1.ObjectIdentifier
68 for _, v := range v.ints {
69 if v > math.MaxInt32 {
70 asn1OID = nil
71 break
72 }
73 asn1OID = append(asn1OID, int(v))
74 }
75
76 o, ok := oid.toASN1OID()
77 if shouldOk := asn1OID != nil; shouldOk != ok {
78 t.Errorf("(%#v).toASN1OID() = (%v, %v); want = (%v, %v)", oid, o, ok, asn1OID, shouldOk)
79 continue
80 }
81
82 if asn1OID != nil && !o.Equal(asn1OID) {
83 t.Errorf("(%#v).toASN1OID() = (%v, true); want = (%v, true)", oid, o, asn1OID)
84 }
85
86 if v.ints != nil {
87 oid2, err := OIDFromInts(v.ints)
88 if err != nil {
89 t.Errorf("OIDFromInts(%v) = (%v, %v); want = (%v, nil)", v.ints, oid2, err, oid)
90 }
91 if !oid2.Equal(oid) {
92 t.Errorf("OIDFromInts(%v) = (%v, nil); want = (%v, nil)", v.ints, oid2, oid)
93 }
94 }
95 }
96 }
97
98 func TestInvalidOID(t *testing.T) {
99 cases := []struct {
100 str string
101 ints []uint64
102 }{
103 {str: "", ints: []uint64{}},
104 {str: "1", ints: []uint64{1}},
105 {str: "3", ints: []uint64{3}},
106 {str: "3.100.200", ints: []uint64{3, 100, 200}},
107 {str: "1.81", ints: []uint64{1, 81}},
108 {str: "1.81.200", ints: []uint64{1, 81, 200}},
109 }
110
111 for _, tt := range cases {
112 oid, err := OIDFromInts(tt.ints)
113 if err == nil {
114 t.Errorf("OIDFromInts(%v) = (%v, %v); want = (OID{}, %v)", tt.ints, oid, err, errInvalidOID)
115 }
116
117 oid2, err := ParseOID(tt.str)
118 if err == nil {
119 t.Errorf("ParseOID(%v) = (%v, %v); want = (OID{}, %v)", tt.str, oid2, err, errInvalidOID)
120 }
121
122 var oid3 OID
123 err = oid3.UnmarshalText([]byte(tt.str))
124 if err == nil {
125 t.Errorf("(*OID).UnmarshalText(%v) = (%v, %v); want = (OID{}, %v)", tt.str, oid3, err, errInvalidOID)
126 }
127 }
128 }
129
130 func TestOIDEqual(t *testing.T) {
131 var cases = []struct {
132 oid OID
133 oid2 OID
134 eq bool
135 }{
136 {oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: mustNewOIDFromInts(t, []uint64{1, 2, 3}), eq: true},
137 {oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: mustNewOIDFromInts(t, []uint64{1, 2, 4}), eq: false},
138 {oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: mustNewOIDFromInts(t, []uint64{1, 2, 3, 4}), eq: false},
139 {oid: mustNewOIDFromInts(t, []uint64{2, 33, 22}), oid2: mustNewOIDFromInts(t, []uint64{2, 33, 23}), eq: false},
140 {oid: OID{}, oid2: OID{}, eq: true},
141 {oid: OID{}, oid2: mustNewOIDFromInts(t, []uint64{2, 33, 23}), eq: false},
142 }
143
144 for _, tt := range cases {
145 if eq := tt.oid.Equal(tt.oid2); eq != tt.eq {
146 t.Errorf("(%v).Equal(%v) = %v, want %v", tt.oid, tt.oid2, eq, tt.eq)
147 }
148 }
149 }
150
151 var (
152 _ encoding.BinaryMarshaler = OID{}
153 _ encoding.BinaryUnmarshaler = new(OID)
154 _ encoding.TextMarshaler = OID{}
155 _ encoding.TextUnmarshaler = new(OID)
156 )
157
158 func TestOIDMarshal(t *testing.T) {
159 cases := []struct {
160 in string
161 out OID
162 err error
163 }{
164 {in: "", err: errInvalidOID},
165 {in: "0", err: errInvalidOID},
166 {in: "1", err: errInvalidOID},
167 {in: ".1", err: errInvalidOID},
168 {in: ".1.", err: errInvalidOID},
169 {in: "1.", err: errInvalidOID},
170 {in: "1..", err: errInvalidOID},
171 {in: "1.2.", err: errInvalidOID},
172 {in: "1.2.333.", err: errInvalidOID},
173 {in: "1.2.333..", err: errInvalidOID},
174 {in: "1.2..", err: errInvalidOID},
175 {in: "+1.2", err: errInvalidOID},
176 {in: "-1.2", err: errInvalidOID},
177 {in: "1.-2", err: errInvalidOID},
178 {in: "1.2.+333", err: errInvalidOID},
179 }
180
181 for _, v := range oidTests {
182 oid, ok := newOIDFromDER(v.raw)
183 if !ok {
184 continue
185 }
186 cases = append(cases, struct {
187 in string
188 out OID
189 err error
190 }{
191 in: v.str,
192 out: oid,
193 err: nil,
194 })
195 }
196
197 for _, tt := range cases {
198 o, err := ParseOID(tt.in)
199 if err != tt.err {
200 t.Errorf("ParseOID(%q) = %v; want = %v", tt.in, err, tt.err)
201 continue
202 }
203
204 var o2 OID
205 err = o2.UnmarshalText([]byte(tt.in))
206 if err != tt.err {
207 t.Errorf("(*OID).UnmarshalText(%q) = %v; want = %v", tt.in, err, tt.err)
208 continue
209 }
210
211 if err != nil {
212 continue
213 }
214
215 if !o.Equal(tt.out) {
216 t.Errorf("(*OID).UnmarshalText(%q) = %v; want = %v", tt.in, o, tt.out)
217 continue
218 }
219
220 if !o2.Equal(tt.out) {
221 t.Errorf("ParseOID(%q) = %v; want = %v", tt.in, o2, tt.out)
222 continue
223 }
224
225 marshalled, err := o.MarshalText()
226 if string(marshalled) != tt.in || err != nil {
227 t.Errorf("(%#v).MarshalText() = (%v, %v); want = (%v, nil)", o, string(marshalled), err, tt.in)
228 continue
229 }
230
231 textAppend := make([]byte, 4)
232 textAppend, err = o.AppendText(textAppend)
233 textAppend = textAppend[4:]
234 if string(textAppend) != tt.in || err != nil {
235 t.Errorf("(%#v).AppendText() = (%v, %v); want = (%v, nil)", o, string(textAppend), err, tt.in)
236 continue
237 }
238
239 binary, err := o.MarshalBinary()
240 if err != nil {
241 t.Errorf("(%#v).MarshalBinary() = %v; want = nil", o, err)
242 }
243
244 var o3 OID
245 if err := o3.UnmarshalBinary(binary); err != nil {
246 t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = nil", binary, err)
247 }
248
249 if !o3.Equal(tt.out) {
250 t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = %v", binary, o3, tt.out)
251 continue
252 }
253
254 binaryAppend := make([]byte, 4)
255 binaryAppend, err = o.AppendBinary(binaryAppend)
256 binaryAppend = binaryAppend[4:]
257 if err != nil {
258 t.Errorf("(%#v).AppendBinary() = %v; want = nil", o, err)
259 }
260
261 var o4 OID
262 if err := o4.UnmarshalBinary(binaryAppend); err != nil {
263 t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = nil", binaryAppend, err)
264 }
265
266 if !o4.Equal(tt.out) {
267 t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = %v", binaryAppend, o4, tt.out)
268 continue
269 }
270 }
271 }
272
273 func TestOIDEqualASN1OID(t *testing.T) {
274 maxInt32PlusOne := int64(math.MaxInt32) + 1
275 var cases = []struct {
276 oid OID
277 oid2 asn1.ObjectIdentifier
278 eq bool
279 }{
280 {oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: asn1.ObjectIdentifier{1, 2, 3}, eq: true},
281 {oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: asn1.ObjectIdentifier{1, 2, 4}, eq: false},
282 {oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: asn1.ObjectIdentifier{1, 2, 3, 4}, eq: false},
283 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 22}), oid2: asn1.ObjectIdentifier{1, 33, 23}, eq: false},
284 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 23}), oid2: asn1.ObjectIdentifier{1, 33, 22}, eq: false},
285 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 127}), oid2: asn1.ObjectIdentifier{1, 33, 127}, eq: true},
286 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 128}), oid2: asn1.ObjectIdentifier{1, 33, 127}, eq: false},
287 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 128}), oid2: asn1.ObjectIdentifier{1, 33, 128}, eq: true},
288 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 129}), oid2: asn1.ObjectIdentifier{1, 33, 129}, eq: true},
289 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 128}), oid2: asn1.ObjectIdentifier{1, 33, 129}, eq: false},
290 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 129}), oid2: asn1.ObjectIdentifier{1, 33, 128}, eq: false},
291 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 255}), oid2: asn1.ObjectIdentifier{1, 33, 255}, eq: true},
292 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 256}), oid2: asn1.ObjectIdentifier{1, 33, 256}, eq: true},
293 {oid: mustNewOIDFromInts(t, []uint64{2, 33, 257}), oid2: asn1.ObjectIdentifier{2, 33, 256}, eq: false},
294 {oid: mustNewOIDFromInts(t, []uint64{2, 33, 256}), oid2: asn1.ObjectIdentifier{2, 33, 257}, eq: false},
295
296 {oid: mustNewOIDFromInts(t, []uint64{1, 33}), oid2: asn1.ObjectIdentifier{1, 33, math.MaxInt32}, eq: false},
297 {oid: mustNewOIDFromInts(t, []uint64{1, 33, math.MaxInt32}), oid2: asn1.ObjectIdentifier{1, 33}, eq: false},
298 {oid: mustNewOIDFromInts(t, []uint64{1, 33, math.MaxInt32}), oid2: asn1.ObjectIdentifier{1, 33, math.MaxInt32}, eq: true},
299 {
300 oid: mustNewOIDFromInts(t, []uint64{1, 33, math.MaxInt32 + 1}),
301 oid2: asn1.ObjectIdentifier{1, 33 , int(maxInt32PlusOne)},
302 eq: false,
303 },
304
305 {oid: mustNewOIDFromInts(t, []uint64{1, 33, 256}), oid2: asn1.ObjectIdentifier{}, eq: false},
306 {oid: OID{}, oid2: asn1.ObjectIdentifier{1, 33, 256}, eq: false},
307 {oid: OID{}, oid2: asn1.ObjectIdentifier{}, eq: false},
308 }
309
310 for _, tt := range cases {
311 if eq := tt.oid.EqualASN1OID(tt.oid2); eq != tt.eq {
312 t.Errorf("(%v).EqualASN1OID(%v) = %v, want %v", tt.oid, tt.oid2, eq, tt.eq)
313 }
314 }
315 }
316
317 func TestOIDUnmarshalBinary(t *testing.T) {
318 for _, tt := range oidTests {
319 var o OID
320 err := o.UnmarshalBinary(tt.raw)
321
322 expectErr := errInvalidOID
323 if tt.valid {
324 expectErr = nil
325 }
326
327 if err != expectErr {
328 t.Errorf("(o *OID).UnmarshalBinary(%v) = %v; want = %v; (o = %v)", tt.raw, err, expectErr, o)
329 }
330 }
331 }
332
333 func BenchmarkOIDMarshalUnmarshalText(b *testing.B) {
334 oid := mustNewOIDFromInts(b, []uint64{1, 2, 3, 9999, 1024})
335 for range b.N {
336 text, err := oid.MarshalText()
337 if err != nil {
338 b.Fatal(err)
339 }
340 var o OID
341 if err := o.UnmarshalText(text); err != nil {
342 b.Fatal(err)
343 }
344 }
345 }
346
347 func mustNewOIDFromInts(t testing.TB, ints []uint64) OID {
348 t.Helper()
349 oid, err := OIDFromInts(ints)
350 if err != nil {
351 t.Fatalf("OIDFromInts(%v) unexpected error: %v", ints, err)
352 }
353 return oid
354 }
355
View as plain text