Source file src/crypto/x509/oid_test.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     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 /*convert to int, so that it compiles on 32bit*/, 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