github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/crypto/x509/oid.go (about) 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 }