...

Source file src/crypto/x509/oid.go

Documentation: crypto/x509

     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  	"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  // An OID represents an ASN.1 OBJECT IDENTIFIER.
    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  		// ITU-T X.690, section 8.19.2:
    35  		// The subidentifier shall be encoded in the fewest possible octets,
    36  		// that is, the leading octet of the subidentifier shall not have the value 0x80.
    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  // OIDFromInts creates a new OID using ints, each integer is a separate component.
    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  // Equal returns true when oid and other represents the same Object Identifier.
    87  func (oid OID) Equal(other OID) bool {
    88  	// There is only one possible DER encoding of
    89  	// each unique Object Identifier.
    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  		// 5 * 7 bits per byte == 35 bits of data
    98  		// Thus the representation is either non-minimal or too large for an int32
    99  		if shifted == 5 {
   100  			failed = true
   101  			return
   102  		}
   103  		ret64 <<= 7
   104  		b := bytes[offset]
   105  		// integers should be minimally encoded, so the leading octet should
   106  		// never be 0x80
   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  			// Ensure that the returned value fits in an int on all platforms
   116  			if ret64 > math.MaxInt32 {
   117  				failed = true
   118  			}
   119  			return
   120  		}
   121  	}
   122  	failed = true
   123  	return
   124  }
   125  
   126  // EqualASN1OID returns whether an OID equals an asn1.ObjectIdentifier. If
   127  // asn1.ObjectIdentifier cannot represent the OID specified by oid, because
   128  // a component of OID requires more than 31 bits, it returns false.
   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  		// This should never happen, since we've already parsed the OID,
   136  		// but just in case.
   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  			// Again, shouldn't happen, since we've already parsed
   156  			// the OID, but better safe than sorry.
   157  			return false
   158  		}
   159  		if v != other[i] {
   160  			return false
   161  		}
   162  	}
   163  
   164  	return i == len(other)
   165  }
   166  
   167  // Strings returns the string representation of the Object Identifier.
   168  func (oid OID) String() string {
   169  	var b strings.Builder
   170  	b.Grow(32)
   171  	const (
   172  		valSize         = 64 // size in bits of val.
   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 // amount of usable bits of val for OIDs.
   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