Skip to content
Snippets Groups Projects
oid_test.go 11.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • // Copyright 2023 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package x509
    
    import (
    
    var oidTests = []struct {
    	raw   []byte
    	valid bool
    	str   string
    	ints  []uint64
    }{
    	{[]byte{}, false, "", nil},
    	{[]byte{0x80, 0x01}, false, "", nil},
    	{[]byte{0x01, 0x80, 0x01}, false, "", nil},
    
    	{[]byte{1, 2, 3}, true, "0.1.2.3", []uint64{0, 1, 2, 3}},
    	{[]byte{41, 2, 3}, true, "1.1.2.3", []uint64{1, 1, 2, 3}},
    	{[]byte{86, 2, 3}, true, "2.6.2.3", []uint64{2, 6, 2, 3}},
    
    	{[]byte{41, 255, 255, 255, 127}, true, "1.1.268435455", []uint64{1, 1, 268435455}},
    	{[]byte{41, 0x87, 255, 255, 255, 127}, true, "1.1.2147483647", []uint64{1, 1, 2147483647}},
    	{[]byte{41, 255, 255, 255, 255, 127}, true, "1.1.34359738367", []uint64{1, 1, 34359738367}},
    	{[]byte{42, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "1.2.9223372036854775807", []uint64{1, 2, 9223372036854775807}},
    	{[]byte{43, 0x81, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "1.3.18446744073709551615", []uint64{1, 3, 18446744073709551615}},
    	{[]byte{44, 0x83, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "1.4.36893488147419103231", nil},
    	{[]byte{85, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.5.1180591620717411303423", nil},
    	{[]byte{85, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.5.19342813113834066795298815", nil},
    
    	{[]byte{255, 255, 255, 127}, true, "2.268435375", []uint64{2, 268435375}},
    	{[]byte{0x87, 255, 255, 255, 127}, true, "2.2147483567", []uint64{2, 2147483567}},
    	{[]byte{255, 127}, true, "2.16303", []uint64{2, 16303}},
    	{[]byte{255, 255, 255, 255, 127}, true, "2.34359738287", []uint64{2, 34359738287}},
    	{[]byte{255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.9223372036854775727", []uint64{2, 9223372036854775727}},
    	{[]byte{0x81, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.18446744073709551535", []uint64{2, 18446744073709551535}},
    	{[]byte{0x83, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.36893488147419103151", nil},
    	{[]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.1180591620717411303343", nil},
    	{[]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, true, "2.19342813113834066795298735", nil},
    
    	{[]byte{41, 0x80 | 66, 0x80 | 44, 0x80 | 11, 33}, true, "1.1.139134369", []uint64{1, 1, 139134369}},
    	{[]byte{0x80 | 66, 0x80 | 44, 0x80 | 11, 33}, true, "2.139134289", []uint64{2, 139134289}},
    }
    
    func TestOID(t *testing.T) {
    	for _, v := range oidTests {
    
    		oid, ok := newOIDFromDER(v.raw)
    		if ok != v.valid {
    
    			t.Errorf("newOIDFromDER(%v) = (%v, %v); want = (OID, %v)", v.raw, oid, ok, v.valid)
    
    			continue
    		}
    
    		if !ok {
    			continue
    		}
    
    		if str := oid.String(); str != v.str {
    
    			t.Errorf("(%#v).String() = %v, want; %v", oid, str, v.str)
    
    		}
    
    		var asn1OID asn1.ObjectIdentifier
    		for _, v := range v.ints {
    			if v > math.MaxInt32 {
    				asn1OID = nil
    				break
    			}
    			asn1OID = append(asn1OID, int(v))
    		}
    
    		o, ok := oid.toASN1OID()
    		if shouldOk := asn1OID != nil; shouldOk != ok {
    
    			t.Errorf("(%#v).toASN1OID() = (%v, %v); want = (%v, %v)", oid, o, ok, asn1OID, shouldOk)
    
    		if asn1OID != nil && !o.Equal(asn1OID) {
    			t.Errorf("(%#v).toASN1OID() = (%v, true); want = (%v, true)", oid, o, asn1OID)
    
    		}
    
    		if v.ints != nil {
    			oid2, err := OIDFromInts(v.ints)
    			if err != nil {
    
    				t.Errorf("OIDFromInts(%v) = (%v, %v); want = (%v, nil)", v.ints, oid2, err, oid)
    
    				t.Errorf("OIDFromInts(%v) = (%v, nil); want = (%v, nil)", v.ints, oid2, oid)
    
    func TestInvalidOID(t *testing.T) {
    	cases := []struct {
    		str  string
    		ints []uint64
    	}{
    		{str: "", ints: []uint64{}},
    		{str: "1", ints: []uint64{1}},
    		{str: "3", ints: []uint64{3}},
    		{str: "3.100.200", ints: []uint64{3, 100, 200}},
    		{str: "1.81", ints: []uint64{1, 81}},
    		{str: "1.81.200", ints: []uint64{1, 81, 200}},
    	}
    
    	for _, tt := range cases {
    		oid, err := OIDFromInts(tt.ints)
    		if err == nil {
    			t.Errorf("OIDFromInts(%v) = (%v, %v); want = (OID{}, %v)", tt.ints, oid, err, errInvalidOID)
    		}
    
    		oid2, err := ParseOID(tt.str)
    		if err == nil {
    			t.Errorf("ParseOID(%v) = (%v, %v); want = (OID{}, %v)", tt.str, oid2, err, errInvalidOID)
    		}
    
    		var oid3 OID
    		err = oid3.UnmarshalText([]byte(tt.str))
    		if err == nil {
    			t.Errorf("(*OID).UnmarshalText(%v) = (%v, %v); want = (OID{}, %v)", tt.str, oid3, err, errInvalidOID)
    		}
    	}
    }
    
    
    func TestOIDEqual(t *testing.T) {
    	var cases = []struct {
    		oid  OID
    		oid2 OID
    		eq   bool
    	}{
    		{oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: mustNewOIDFromInts(t, []uint64{1, 2, 3}), eq: true},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: mustNewOIDFromInts(t, []uint64{1, 2, 4}), eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: mustNewOIDFromInts(t, []uint64{1, 2, 3, 4}), eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{2, 33, 22}), oid2: mustNewOIDFromInts(t, []uint64{2, 33, 23}), eq: false},
    		{oid: OID{}, oid2: OID{}, eq: true},
    		{oid: OID{}, oid2: mustNewOIDFromInts(t, []uint64{2, 33, 23}), eq: false},
    	}
    
    	for _, tt := range cases {
    		if eq := tt.oid.Equal(tt.oid2); eq != tt.eq {
    			t.Errorf("(%v).Equal(%v) = %v, want %v", tt.oid, tt.oid2, eq, tt.eq)
    		}
    	}
    }
    
    
    var (
    	_ encoding.BinaryMarshaler   = OID{}
    	_ encoding.BinaryUnmarshaler = new(OID)
    	_ encoding.TextMarshaler     = OID{}
    	_ encoding.TextUnmarshaler   = new(OID)
    )
    
    func TestOIDMarshal(t *testing.T) {
    	cases := []struct {
    		in  string
    		out OID
    		err error
    	}{
    		{in: "", err: errInvalidOID},
    		{in: "0", err: errInvalidOID},
    		{in: "1", err: errInvalidOID},
    		{in: ".1", err: errInvalidOID},
    		{in: ".1.", err: errInvalidOID},
    		{in: "1.", err: errInvalidOID},
    		{in: "1..", err: errInvalidOID},
    		{in: "1.2.", err: errInvalidOID},
    		{in: "1.2.333.", err: errInvalidOID},
    		{in: "1.2.333..", err: errInvalidOID},
    		{in: "1.2..", err: errInvalidOID},
    		{in: "+1.2", err: errInvalidOID},
    		{in: "-1.2", err: errInvalidOID},
    		{in: "1.-2", err: errInvalidOID},
    		{in: "1.2.+333", err: errInvalidOID},
    	}
    
    	for _, v := range oidTests {
    		oid, ok := newOIDFromDER(v.raw)
    		if !ok {
    			continue
    		}
    		cases = append(cases, struct {
    			in  string
    			out OID
    			err error
    		}{
    			in:  v.str,
    			out: oid,
    			err: nil,
    		})
    	}
    
    	for _, tt := range cases {
    		o, err := ParseOID(tt.in)
    		if err != tt.err {
    			t.Errorf("ParseOID(%q) = %v; want = %v", tt.in, err, tt.err)
    			continue
    		}
    
    		var o2 OID
    		err = o2.UnmarshalText([]byte(tt.in))
    		if err != tt.err {
    			t.Errorf("(*OID).UnmarshalText(%q) = %v; want = %v", tt.in, err, tt.err)
    			continue
    		}
    
    		if err != nil {
    			continue
    		}
    
    		if !o.Equal(tt.out) {
    			t.Errorf("(*OID).UnmarshalText(%q) = %v; want = %v", tt.in, o, tt.out)
    			continue
    		}
    
    		if !o2.Equal(tt.out) {
    			t.Errorf("ParseOID(%q) = %v; want = %v", tt.in, o2, tt.out)
    			continue
    		}
    
    		marshalled, err := o.MarshalText()
    		if string(marshalled) != tt.in || err != nil {
    			t.Errorf("(%#v).MarshalText() = (%v, %v); want = (%v, nil)", o, string(marshalled), err, tt.in)
    			continue
    		}
    
    
    		textAppend := make([]byte, 4)
    		textAppend, err = o.AppendText(textAppend)
    		textAppend = textAppend[4:]
    		if string(textAppend) != tt.in || err != nil {
    			t.Errorf("(%#v).AppendText() = (%v, %v); want = (%v, nil)", o, string(textAppend), err, tt.in)
    			continue
    		}
    
    
    		binary, err := o.MarshalBinary()
    		if err != nil {
    			t.Errorf("(%#v).MarshalBinary() = %v; want = nil", o, err)
    		}
    
    		var o3 OID
    		if err := o3.UnmarshalBinary(binary); err != nil {
    			t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = nil", binary, err)
    		}
    
    		if !o3.Equal(tt.out) {
    			t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = %v", binary, o3, tt.out)
    			continue
    		}
    
    
    		binaryAppend := make([]byte, 4)
    		binaryAppend, err = o.AppendBinary(binaryAppend)
    		binaryAppend = binaryAppend[4:]
    		if err != nil {
    			t.Errorf("(%#v).AppendBinary() = %v; want = nil", o, err)
    		}
    
    		var o4 OID
    		if err := o4.UnmarshalBinary(binaryAppend); err != nil {
    			t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = nil", binaryAppend, err)
    		}
    
    		if !o4.Equal(tt.out) {
    			t.Errorf("(*OID).UnmarshalBinary(%v) = %v; want = %v", binaryAppend, o4, tt.out)
    			continue
    		}
    
    func TestOIDEqualASN1OID(t *testing.T) {
    	maxInt32PlusOne := int64(math.MaxInt32) + 1
    	var cases = []struct {
    		oid  OID
    		oid2 asn1.ObjectIdentifier
    		eq   bool
    	}{
    		{oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: asn1.ObjectIdentifier{1, 2, 3}, eq: true},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: asn1.ObjectIdentifier{1, 2, 4}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 2, 3}), oid2: asn1.ObjectIdentifier{1, 2, 3, 4}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 22}), oid2: asn1.ObjectIdentifier{1, 33, 23}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 23}), oid2: asn1.ObjectIdentifier{1, 33, 22}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 127}), oid2: asn1.ObjectIdentifier{1, 33, 127}, eq: true},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 128}), oid2: asn1.ObjectIdentifier{1, 33, 127}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 128}), oid2: asn1.ObjectIdentifier{1, 33, 128}, eq: true},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 129}), oid2: asn1.ObjectIdentifier{1, 33, 129}, eq: true},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 128}), oid2: asn1.ObjectIdentifier{1, 33, 129}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 129}), oid2: asn1.ObjectIdentifier{1, 33, 128}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 255}), oid2: asn1.ObjectIdentifier{1, 33, 255}, eq: true},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 256}), oid2: asn1.ObjectIdentifier{1, 33, 256}, eq: true},
    		{oid: mustNewOIDFromInts(t, []uint64{2, 33, 257}), oid2: asn1.ObjectIdentifier{2, 33, 256}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{2, 33, 256}), oid2: asn1.ObjectIdentifier{2, 33, 257}, eq: false},
    
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33}), oid2: asn1.ObjectIdentifier{1, 33, math.MaxInt32}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, math.MaxInt32}), oid2: asn1.ObjectIdentifier{1, 33}, eq: false},
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, math.MaxInt32}), oid2: asn1.ObjectIdentifier{1, 33, math.MaxInt32}, eq: true},
    		{
    			oid:  mustNewOIDFromInts(t, []uint64{1, 33, math.MaxInt32 + 1}),
    			oid2: asn1.ObjectIdentifier{1, 33 /*convert to int, so that it compiles on 32bit*/, int(maxInt32PlusOne)},
    			eq:   false,
    		},
    
    		{oid: mustNewOIDFromInts(t, []uint64{1, 33, 256}), oid2: asn1.ObjectIdentifier{}, eq: false},
    		{oid: OID{}, oid2: asn1.ObjectIdentifier{1, 33, 256}, eq: false},
    		{oid: OID{}, oid2: asn1.ObjectIdentifier{}, eq: false},
    	}
    
    	for _, tt := range cases {
    		if eq := tt.oid.EqualASN1OID(tt.oid2); eq != tt.eq {
    			t.Errorf("(%v).EqualASN1OID(%v) = %v, want %v", tt.oid, tt.oid2, eq, tt.eq)
    		}
    	}
    }
    
    
    func TestOIDUnmarshalBinary(t *testing.T) {
    	for _, tt := range oidTests {
    		var o OID
    		err := o.UnmarshalBinary(tt.raw)
    
    		expectErr := errInvalidOID
    		if tt.valid {
    			expectErr = nil
    		}
    
    		if err != expectErr {
    			t.Errorf("(o *OID).UnmarshalBinary(%v) = %v; want = %v; (o = %v)", tt.raw, err, expectErr, o)
    		}
    	}
    }
    
    func BenchmarkOIDMarshalUnmarshalText(b *testing.B) {
    	oid := mustNewOIDFromInts(b, []uint64{1, 2, 3, 9999, 1024})
    	for range b.N {
    		text, err := oid.MarshalText()
    		if err != nil {
    			b.Fatal(err)
    		}
    		var o OID
    		if err := o.UnmarshalText(text); err != nil {
    			b.Fatal(err)
    		}
    	}
    }
    
    func mustNewOIDFromInts(t testing.TB, ints []uint64) OID {
    
    	oid, err := OIDFromInts(ints)
    	if err != nil {
    		t.Fatalf("OIDFromInts(%v) unexpected error: %v", ints, err)
    	}
    	return oid
    }