1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.asn1new.primitives;
18
19 import java.io.Serializable;
20
21 import org.apache.asn1.codec.DecoderException;
22
23
24 /***
25 * This class implement an OID (Object Identifier).
26 *
27 * An OID is encoded as a list of bytes representing integers.
28 *
29 * An OID has a numeric representation where number are separated with dots :
30 * SPNEGO Oid = 1.3.6.1.5.5.2
31 *
32 * Translating from a byte list to a dot separated list of number follows the rules :
33 * - the first number is in [0..2]
34 * - the second number is in [0..39] if the first number is 0 or 1
35 * - the first byte has a value equal to : number 1 * 40 + number two
36 * - the upper bit of a byte is set if the next byte is a part of the number
37 *
38 * For instance, the SPNEGO Oid (1.3.6.1.5.5.2) will be encoded :
39 * 1.3 -> 0x2B (1*40 + 3 = 43 = 0x2B)
40 * .6 -> 0x06
41 * .1 -> 0x01
42 * .5 -> 0x05
43 * .5 -> 0x05
44 * .2 -> 0x02
45 *
46 * The Kerberos V5 Oid (1.2.840.48018.1.2.2) will be encoded :
47 * 1.2 -> 0x2A (1*40 + 2 = 42 = 0x2A)
48 * 840 -> 0x86 0x48 (840 = 6 * 128 + 72 = (0x06 | 0x80) 0x48 = 0x86 0x48
49 * 48018 -> 0x82 0xF7 0x12 (2 * 128 * 128 + 119 * 128 + 18 = (0x02 | 0x80) (0x77 | 0x80) 0x12
50 *
51 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52 */
53 public class OID implements Serializable
54 {
55 private static final long serialVersionUID = 1L;
56
57
58
59 /*** The OID as a array of int */
60 private int[] oidValues;
61
62
63
64 /***
65 * Creates a new OID object.
66 */
67 public OID()
68 {
69
70
71
72 }
73
74 /***
75 * Create a new OID object from a byte array
76 * @param oid
77 */
78 public OID( byte[] oid ) throws DecoderException
79 {
80 setOID(oid);
81 }
82
83 /***
84 * Create a new OID object from a String
85 * @param oid The String which is supposed to be an OID
86 */
87 public OID( String oid ) throws DecoderException
88 {
89 setOID( oid );
90 }
91
92
93 /***
94 * Set the OID. It will be translated from a byte array to an internal representation.
95 * @param oid The bytes containing the OID
96 */
97 public void setOID( byte[] oid ) throws DecoderException
98 {
99
100 if ( oid == null )
101 {
102 throw new DecoderException( "Null OID" );
103 }
104
105 if ( oid.length < 1 )
106 {
107 throw new DecoderException( "Invalid OID : " + oid );
108 }
109
110
111 int nbValues = 1;
112
113 int pos = 0;
114
115 while ( pos < oid.length )
116 {
117
118 if ( oid[pos] >= 0 )
119 {
120 nbValues++;
121 }
122
123 pos++;
124 }
125
126 oidValues = new int[nbValues];
127
128 nbValues = 0;
129 pos = 0;
130
131 int accumulator = 0;
132
133
134 if ( ( oid[0] < 0 ) || ( oid[0] >= 80 ) )
135 {
136 oidValues[nbValues++] = 2;
137
138 while ( pos < oid.length )
139 {
140
141 if ( oid[pos] >= 0 )
142 {
143 oidValues[nbValues++] = ( ( accumulator << 7 ) + oid[pos] ) - 80;
144 accumulator = 0;
145 pos++;
146 break;
147 }
148 else
149 {
150 accumulator = ( accumulator << 7 ) + ( oid[pos] & 0x007F );
151 }
152
153 pos++;
154 }
155 }
156 else if ( oid[0] < 40 )
157 {
158 oidValues[nbValues++] = 0;
159 oidValues[nbValues++] = oid[pos++];
160 }
161 else
162 {
163 oidValues[nbValues++] = 1;
164 oidValues[nbValues++] = oid[pos++] - 40;
165 }
166
167 while ( pos < oid.length )
168 {
169
170 if ( oid[pos] >= 0 )
171 {
172 oidValues[nbValues++] = ( accumulator << 7 ) + oid[pos];
173 accumulator = 0;
174 }
175 else
176 {
177 accumulator = ( accumulator << 7 ) + ( oid[pos] & 0x007F );
178 }
179
180 pos++;
181 }
182 }
183
184 /***
185 * Set the OID. It will be translated from a String to an internal representation.
186 * The syntax will be controled in respect with this rule :
187 * OID = ( [ '0' | '1' ] '.' [ 0 .. 39 ] | '2' '.' int) ( '.' int )*
188 * @param oid The String containing the OID
189 */
190 public void setOID( String oid ) throws DecoderException
191 {
192
193 if ( ( oid == null ) || ( oid.length() == 0 ) )
194 {
195 throw new DecoderException( "Null OID" );
196 }
197
198 int nbInts = 1;
199 byte[] bytes = oid.getBytes();
200 boolean dotSeen = false;
201
202
203 for ( int i = 0; i < bytes.length; i++ )
204 {
205
206 if ( bytes[i] == '.' )
207 {
208
209 if ( dotSeen )
210 {
211
212
213 throw new DecoderException( "Invalid OID : " + oid );
214 }
215
216 nbInts++;
217 dotSeen = true;
218 }
219 else
220 {
221 dotSeen = false;
222 }
223 }
224
225
226 if ( nbInts < 2 )
227 {
228 throw new DecoderException( "Invalid OID : " + oid );
229 }
230
231 oidValues = new int[nbInts];
232
233 int pos = 0;
234 int intPos = 0;
235
236
237
238 boolean ituOrIso = false;
239
240
241 switch ( bytes[pos] )
242 {
243
244 case '0' :
245 case '1' :
246 ituOrIso = true;
247
248
249 case '2' :
250 oidValues[intPos++] = bytes[pos++] - '0';
251 break;
252
253 default :
254 throw new DecoderException( "Invalid OID : " + oid );
255 }
256
257
258 if ( bytes[pos++] != '.' )
259 {
260 throw new DecoderException( "Invalid OID : " + oid );
261 }
262
263 dotSeen = true;
264
265 int value = 0;
266
267 for ( int i = pos; i < bytes.length; i++ )
268 {
269
270 if ( bytes[i] == '.' )
271 {
272
273 if ( dotSeen )
274 {
275
276
277 throw new DecoderException( "Invalid OID : " + oid );
278 }
279
280 if (ituOrIso && value > 39)
281 {
282 throw new DecoderException( "Invalid OID : " + oid );
283 }
284 else
285 {
286 ituOrIso = false;
287 }
288
289 nbInts++;
290 dotSeen = true;
291 oidValues[intPos++] = value;
292 value = 0;
293 }
294 else if ( ( bytes[i] >= 0x30 ) && ( bytes[i] <= 0x39 ) )
295 {
296 dotSeen = false;
297 value = ( ( value * 10 ) + bytes[i] ) - '0';
298
299 }
300 else
301 {
302
303
304 throw new DecoderException( "Invalid OID : " + oid );
305 }
306 }
307
308 oidValues[intPos++] = value;
309 }
310
311 /***
312 * Get an array of int from the OID
313 * @return An array of int representing the OID
314 */
315 public int[] getOIDValues()
316 {
317 return oidValues;
318 }
319
320 /***
321 * Get the number of bytes necessary to store the OID
322 * @return An int representing the length of the OID
323 */
324 public int getOIDLength()
325 {
326 int value = oidValues[0] * 40 + oidValues[1];
327 int nbBytes = 0;
328
329 if (value < 128)
330 {
331 nbBytes = 1;
332 }
333 else if (value < 16384)
334 {
335 nbBytes = 2;
336 }
337 else if (value < 2097152)
338 {
339 nbBytes = 3;
340 }
341 else if (value < 268435456)
342 {
343 nbBytes = 4;
344 }
345 else
346 {
347 nbBytes = 5;
348 }
349
350 for (int i = 2; i < oidValues.length; i++ )
351 {
352 value = oidValues[i];
353
354 if (value < 128)
355 {
356 nbBytes += 1;
357 }
358 else if (value < 16384)
359 {
360 nbBytes += 2;
361 }
362 else if (value < 2097152)
363 {
364 nbBytes += 3;
365 }
366 else if (value < 268435456)
367 {
368 nbBytes += 4;
369 }
370 else
371 {
372 nbBytes += 5;
373 }
374 }
375
376 return nbBytes;
377 }
378
379 /***
380 * Get an array of bytes from the OID
381 * @return An array of int representing the OID
382 */
383 public byte[] getOID()
384 {
385 int value = oidValues[0] * 40 + oidValues[1];
386 int firstValues = value;
387
388 byte[] bytes = new byte[getOIDLength()];
389 int pos = 0;
390
391 if (oidValues[0] < 2)
392 {
393 bytes[pos++] = (byte)(oidValues[0] * 40 + oidValues[1]);
394 }
395 else
396 {
397 if (firstValues < 128)
398 {
399 bytes[pos++] = (byte)(firstValues);
400 }
401 else if (firstValues < 16384)
402 {
403 bytes[pos++] = (byte)( ( firstValues >> 7 ) | 0x0080 );
404 bytes[pos++] = (byte)( firstValues & 0x007F);
405 }
406 else if (value < 2097152)
407 {
408 bytes[pos++] = (byte)( ( firstValues >> 14 ) | 0x0080);
409 bytes[pos++] = (byte)( ( ( firstValues >> 7 ) & 0x007F) | 0x0080);
410 bytes[pos++] = (byte)( firstValues & 0x007F);
411 }
412 else if (value < 268435456)
413 {
414 bytes[pos++] = (byte)( ( firstValues >> 21 ) | 0x0080);
415 bytes[pos++] = (byte)( ( ( firstValues >> 14 ) & 0x007F) | 0x0080);
416 bytes[pos++] = (byte)( ( ( firstValues >> 7 ) & 0x007F) | 0x0080);
417 bytes[pos++] = (byte)( firstValues & 0x007F);
418 }
419 else
420 {
421 bytes[pos++] = (byte)( ( firstValues >> 28 ) | 0x0080);
422 bytes[pos++] = (byte)( ( ( firstValues >> 21 ) & 0x007F) | 0x0080);
423 bytes[pos++] = (byte)( ( ( firstValues >> 14 ) & 0x007F) | 0x0080);
424 bytes[pos++] = (byte)( ( ( firstValues >> 7 ) & 0x007F) | 0x0080);
425 bytes[pos++] = (byte)( firstValues & 0x007F);
426 }
427 }
428
429 for (int i = 2; i < oidValues.length; i++ )
430 {
431 value = oidValues[i];
432
433 if (value < 128)
434 {
435 bytes[pos++] = (byte)(value);
436 }
437 else if (value < 16384)
438 {
439 bytes[pos++] = (byte)( ( value >> 7 ) | 0x0080 );
440 bytes[pos++] = (byte)( value & 0x007F);
441 }
442 else if (value < 2097152)
443 {
444 bytes[pos++] = (byte)( ( value >> 14 ) | 0x0080);
445 bytes[pos++] = (byte)( ( ( value >> 7 ) & 0x007F) | 0x0080);
446 bytes[pos++] = (byte)( value & 0x007F);
447 }
448 else if (value < 268435456)
449 {
450 bytes[pos++] = (byte)( ( value >> 21 ) | 0x0080);
451 bytes[pos++] = (byte)( ( ( value >> 14 ) & 0x007F) | 0x0080);
452 bytes[pos++] = (byte)( ( ( value >> 7 ) & 0x007F) | 0x0080);
453 bytes[pos++] = (byte)( value & 0x007F);
454 }
455 else
456 {
457 bytes[pos++] = (byte)( ( value >> 28 ) | 0x0080);
458 bytes[pos++] = (byte)( ( ( value >> 21 ) & 0x007F) | 0x0080);
459 bytes[pos++] = (byte)( ( ( value >> 14 ) & 0x007F) | 0x0080);
460 bytes[pos++] = (byte)( ( ( value >> 7 ) & 0x007F) | 0x0080);
461 bytes[pos++] = (byte)( value & 0x007F);
462 }
463 }
464
465 return bytes;
466 }
467
468 /***
469 * Get the OID as a String
470 * @return A String representing the OID
471 */
472 public String toString()
473 {
474
475 StringBuffer sb = new StringBuffer();
476
477 if (oidValues != null)
478 {
479 sb.append( oidValues[0] );
480
481 for ( int i = 1; i < oidValues.length; i++ )
482 {
483 sb.append( '.' ).append( oidValues[i] );
484 }
485 }
486
487 return sb.toString();
488 }
489 }