@@ -24,6 +24,12 @@ type OID struct {
24
24
der []byte
25
25
}
26
26
27
+ // ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots.
28
+ func ParseOID (oid string ) (OID , error ) {
29
+ var o OID
30
+ return o , o .unmarshalOIDText (oid )
31
+ }
32
+
27
33
func newOIDFromDER (der []byte ) (OID , bool ) {
28
34
if len (der ) == 0 || der [len (der )- 1 ]& 0x80 != 0 {
29
35
return OID {}, false
@@ -83,6 +89,112 @@ func appendBase128Int(dst []byte, n uint64) []byte {
83
89
return dst
84
90
}
85
91
92
+ func base128BigIntLength (n * big.Int ) int {
93
+ if n .Cmp (big .NewInt (0 )) == 0 {
94
+ return 1
95
+ }
96
+ return (n .BitLen () + 6 ) / 7
97
+ }
98
+
99
+ func appendBase128BigInt (dst []byte , n * big.Int ) []byte {
100
+ if n .Cmp (big .NewInt (0 )) == 0 {
101
+ return append (dst , 0 )
102
+ }
103
+
104
+ for i := base128BigIntLength (n ) - 1 ; i >= 0 ; i -- {
105
+ o := byte (big .NewInt (0 ).Rsh (n , uint (i )* 7 ).Bits ()[0 ])
106
+ o &= 0x7f
107
+ if i != 0 {
108
+ o |= 0x80
109
+ }
110
+ dst = append (dst , o )
111
+ }
112
+ return dst
113
+ }
114
+
115
+ // MarshalText implements [encoding.TextMarshaler]
116
+ func (o OID ) MarshalText () ([]byte , error ) {
117
+ return []byte (o .String ()), nil
118
+ }
119
+
120
+ // UnmarshalText implements [encoding.TextUnmarshaler]
121
+ func (o * OID ) UnmarshalText (text []byte ) error {
122
+ return o .unmarshalOIDText (string (text ))
123
+ }
124
+
125
+ func (o * OID ) unmarshalOIDText (oid string ) error {
126
+ // (*big.Int).SetString allows +/- signs, but we don't want
127
+ // to allow them in the string representation of Object Identifier, so
128
+ // reject such encodings.
129
+ for _ , c := range oid {
130
+ isDigit := c >= '0' && c <= '9'
131
+ if ! isDigit && c != '.' {
132
+ return errInvalidOID
133
+ }
134
+ }
135
+
136
+ var (
137
+ firstNum string
138
+ secondNum string
139
+ )
140
+
141
+ var nextComponentExists bool
142
+ firstNum , oid , nextComponentExists = strings .Cut (oid , "." )
143
+ if ! nextComponentExists {
144
+ return errInvalidOID
145
+ }
146
+ secondNum , oid , nextComponentExists = strings .Cut (oid , "." )
147
+
148
+ var (
149
+ first = big .NewInt (0 )
150
+ second = big .NewInt (0 )
151
+ )
152
+
153
+ if _ , ok := first .SetString (firstNum , 10 ); ! ok {
154
+ return errInvalidOID
155
+ }
156
+ if _ , ok := second .SetString (secondNum , 10 ); ! ok {
157
+ return errInvalidOID
158
+ }
159
+
160
+ if first .Cmp (big .NewInt (2 )) > 0 || (first .Cmp (big .NewInt (2 )) < 0 && second .Cmp (big .NewInt (40 )) >= 0 ) {
161
+ return errInvalidOID
162
+ }
163
+
164
+ firstComponent := first .Mul (first , big .NewInt (40 ))
165
+ firstComponent .Add (firstComponent , second )
166
+
167
+ der := appendBase128BigInt (make ([]byte , 0 , 32 ), firstComponent )
168
+
169
+ for nextComponentExists {
170
+ var strNum string
171
+ strNum , oid , nextComponentExists = strings .Cut (oid , "." )
172
+ b , ok := big .NewInt (0 ).SetString (strNum , 10 )
173
+ if ! ok {
174
+ return errInvalidOID
175
+ }
176
+ der = appendBase128BigInt (der , b )
177
+ }
178
+
179
+ o .der = der
180
+ return nil
181
+ }
182
+
183
+ // MarshalBinary implements [encoding.BinaryMarshaler]
184
+ func (o OID ) MarshalBinary () ([]byte , error ) {
185
+ return bytes .Clone (o .der ), nil
186
+ }
187
+
188
+ // UnmarshalBinary implements [encoding.BinaryUnmarshaler]
189
+ func (o * OID ) UnmarshalBinary (b []byte ) error {
190
+ oid , ok := newOIDFromDER (bytes .Clone (b ))
191
+ if ! ok {
192
+ return errInvalidOID
193
+ }
194
+ * o = oid
195
+ return nil
196
+ }
197
+
86
198
// Equal returns true when oid and other represents the same Object Identifier.
87
199
func (oid OID ) Equal (other OID ) bool {
88
200
// There is only one possible DER encoding of
0 commit comments