1 |
775 |
jeremybenn |
/* Oid.java -- Object identifier class.
|
2 |
|
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
3 |
|
|
|
4 |
|
|
This file is part of GNU Classpath.
|
5 |
|
|
|
6 |
|
|
GNU Classpath is free software; you can redistribute it and/or modify
|
7 |
|
|
it under the terms of the GNU General Public License as published by
|
8 |
|
|
the Free Software Foundation; either version 2, or (at your option)
|
9 |
|
|
any later version.
|
10 |
|
|
|
11 |
|
|
GNU Classpath is distributed in the hope that it will be useful, but
|
12 |
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
|
|
General Public License for more details.
|
15 |
|
|
|
16 |
|
|
You should have received a copy of the GNU General Public License
|
17 |
|
|
along with GNU Classpath; see the file COPYING. If not, write to the
|
18 |
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 |
|
|
02110-1301 USA.
|
20 |
|
|
|
21 |
|
|
Linking this library statically or dynamically with other modules is
|
22 |
|
|
making a combined work based on this library. Thus, the terms and
|
23 |
|
|
conditions of the GNU General Public License cover the whole
|
24 |
|
|
combination.
|
25 |
|
|
|
26 |
|
|
As a special exception, the copyright holders of this library give you
|
27 |
|
|
permission to link this library with independent modules to produce an
|
28 |
|
|
executable, regardless of the license terms of these independent
|
29 |
|
|
modules, and to copy and distribute the resulting executable under
|
30 |
|
|
terms of your choice, provided that you also meet, for each linked
|
31 |
|
|
independent module, the terms and conditions of the license of that
|
32 |
|
|
module. An independent module is a module which is not derived from
|
33 |
|
|
or based on this library. If you modify this library, you may extend
|
34 |
|
|
this exception to your version of the library, but you are not
|
35 |
|
|
obligated to do so. If you do not wish to do so, delete this
|
36 |
|
|
exception statement from your version.
|
37 |
|
|
|
38 |
|
|
The documentation comments of this class are derived from the text
|
39 |
|
|
of RFC 2853: Generic Security Service API Version 2: Java Bindings.
|
40 |
|
|
That document is covered under the following license notice:
|
41 |
|
|
|
42 |
|
|
Copyright (C) The Internet Society (2000). All Rights Reserved.
|
43 |
|
|
|
44 |
|
|
This document and translations of it may be copied and furnished to
|
45 |
|
|
others, and derivative works that comment on or otherwise explain it
|
46 |
|
|
or assist in its implementation may be prepared, copied, published and
|
47 |
|
|
distributed, in whole or in part, without restriction of any kind,
|
48 |
|
|
provided that the above copyright notice and this paragraph are
|
49 |
|
|
included on all such copies and derivative works. However, this
|
50 |
|
|
document itself may not be modified in any way, such as by removing
|
51 |
|
|
the copyright notice or references to the Internet Society or other
|
52 |
|
|
Internet organizations, except as needed for the purpose of developing
|
53 |
|
|
Internet standards in which case the procedures for copyrights defined
|
54 |
|
|
in the Internet Standards process must be followed, or as required to
|
55 |
|
|
translate it into languages other than English.
|
56 |
|
|
|
57 |
|
|
The limited permissions granted above are perpetual and will not be
|
58 |
|
|
revoked by the Internet Society or its successors or assigns.
|
59 |
|
|
|
60 |
|
|
This document and the information contained herein is provided on an
|
61 |
|
|
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
62 |
|
|
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT
|
63 |
|
|
NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN
|
64 |
|
|
WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
65 |
|
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */
|
66 |
|
|
|
67 |
|
|
|
68 |
|
|
package org.ietf.jgss;
|
69 |
|
|
|
70 |
|
|
import gnu.java.lang.CPStringBuilder;
|
71 |
|
|
|
72 |
|
|
import java.io.ByteArrayInputStream;
|
73 |
|
|
import java.io.ByteArrayOutputStream;
|
74 |
|
|
import java.io.DataInputStream;
|
75 |
|
|
import java.io.InputStream;
|
76 |
|
|
import java.io.IOException;
|
77 |
|
|
import java.io.OutputStream;
|
78 |
|
|
|
79 |
|
|
import java.math.BigInteger;
|
80 |
|
|
|
81 |
|
|
import java.util.Arrays;
|
82 |
|
|
import java.util.StringTokenizer;
|
83 |
|
|
|
84 |
|
|
/**
|
85 |
|
|
* <p>This class represents Universal Object Identifiers (Oids) and their
|
86 |
|
|
* associated operations.</p>
|
87 |
|
|
*
|
88 |
|
|
* <p>Oids are hierarchically globally-interpretable identifiers used
|
89 |
|
|
* within the GSS-API framework to identify mechanisms and name formats.</p>
|
90 |
|
|
*
|
91 |
|
|
* <p>The structure and encoding of Oids is defined in ISOIEC-8824 and
|
92 |
|
|
* ISOIEC-8825. For example the Oid representation of Kerberos V5
|
93 |
|
|
* mechanism is "1.2.840.113554.1.2.2".</p>
|
94 |
|
|
*
|
95 |
|
|
* <p>The {@link GSSName} name class contains <code>public static Oid</code>
|
96 |
|
|
* objects representing the standard name types defined in GSS-API.</p>
|
97 |
|
|
*/
|
98 |
|
|
public class Oid
|
99 |
|
|
{
|
100 |
|
|
|
101 |
|
|
// Constants and fields.
|
102 |
|
|
// -------------------------------------------------------------------------
|
103 |
|
|
|
104 |
|
|
private static final int OBJECT_IDENTIFIER = 0x06;
|
105 |
|
|
private static final int RELATIVE_OID = 0x0d;
|
106 |
|
|
|
107 |
|
|
private final int[] components;
|
108 |
|
|
private byte[] derOid;
|
109 |
|
|
private String strOid;
|
110 |
|
|
private boolean relative;
|
111 |
|
|
|
112 |
|
|
// Constructors.
|
113 |
|
|
// -------------------------------------------------------------------------
|
114 |
|
|
|
115 |
|
|
/**
|
116 |
|
|
* Creates an Oid object from a string representation of its integer
|
117 |
|
|
* components (e.g. "1.2.840.113554.1.2.2").
|
118 |
|
|
*
|
119 |
|
|
* @param strOid The string representation for the oid.
|
120 |
|
|
* @throws GSSException If the argument is badly formed.
|
121 |
|
|
*/
|
122 |
|
|
public Oid(String strOid) throws GSSException
|
123 |
|
|
{
|
124 |
|
|
if (strOid == null)
|
125 |
|
|
throw new NullPointerException();
|
126 |
|
|
this.strOid = strOid;
|
127 |
|
|
try
|
128 |
|
|
{
|
129 |
|
|
StringTokenizer tok = new StringTokenizer(strOid, ".");
|
130 |
|
|
components = new int[tok.countTokens()];
|
131 |
|
|
int i = 0;
|
132 |
|
|
while (tok.hasMoreTokens() && i < components.length)
|
133 |
|
|
{
|
134 |
|
|
components[i++] = Integer.parseInt(tok.nextToken());
|
135 |
|
|
}
|
136 |
|
|
}
|
137 |
|
|
catch (Exception x)
|
138 |
|
|
{
|
139 |
|
|
throw new GSSException(GSSException.FAILURE);
|
140 |
|
|
}
|
141 |
|
|
relative = false;
|
142 |
|
|
}
|
143 |
|
|
|
144 |
|
|
/**
|
145 |
|
|
* Creates an Oid object from its DER encoding. This refers to the full
|
146 |
|
|
* encoding including tag and length. The structure and encoding of
|
147 |
|
|
* Oids is defined in ISOIEC-8824 and ISOIEC-8825. This method is
|
148 |
|
|
* identical in functionality to its byte array counterpart.
|
149 |
|
|
*
|
150 |
|
|
* @param derOid Stream containing the DER encoded oid.
|
151 |
|
|
* @throws GSSException If the DER stream is badly formed, or if the
|
152 |
|
|
* input stream throws an exception.
|
153 |
|
|
*/
|
154 |
|
|
public Oid(InputStream derOid) throws GSSException
|
155 |
|
|
{
|
156 |
|
|
DataInputStream in = new DataInputStream(derOid);
|
157 |
|
|
try
|
158 |
|
|
{
|
159 |
|
|
int tag = in.read() & 0x1F;
|
160 |
|
|
if (tag != OBJECT_IDENTIFIER && tag != RELATIVE_OID)
|
161 |
|
|
throw new IOException();
|
162 |
|
|
int len = in.read();
|
163 |
|
|
if ((len & ~0x7F) != 0)
|
164 |
|
|
{
|
165 |
|
|
byte[] buf = new byte[len & 0x7F];
|
166 |
|
|
in.readFully(buf);
|
167 |
|
|
len = new BigInteger(1, buf).intValue();
|
168 |
|
|
}
|
169 |
|
|
if (len < 0)
|
170 |
|
|
throw new IOException();
|
171 |
|
|
byte[] enc = new byte[len];
|
172 |
|
|
in.readFully(enc);
|
173 |
|
|
int[] comp = new int[len + 1];
|
174 |
|
|
int count = 0;
|
175 |
|
|
int i = 0;
|
176 |
|
|
relative = tag == RELATIVE_OID;
|
177 |
|
|
if (!relative && i < len)
|
178 |
|
|
{
|
179 |
|
|
int j = (enc[i] & 0xFF);
|
180 |
|
|
comp[count++] = j / 40;
|
181 |
|
|
comp[count++] = j % 40;
|
182 |
|
|
i++;
|
183 |
|
|
}
|
184 |
|
|
while (i < len)
|
185 |
|
|
{
|
186 |
|
|
int j = 0;
|
187 |
|
|
do
|
188 |
|
|
{
|
189 |
|
|
j = enc[i++] & 0xFF;
|
190 |
|
|
comp[count] <<= 7;
|
191 |
|
|
comp[count] |= j & 0x7F;
|
192 |
|
|
if (i >= len && (j & 0x80) != 0)
|
193 |
|
|
throw new IOException();
|
194 |
|
|
}
|
195 |
|
|
while ((j & 0x80) != 0);
|
196 |
|
|
count++;
|
197 |
|
|
}
|
198 |
|
|
if (count == len)
|
199 |
|
|
this.components = comp;
|
200 |
|
|
else
|
201 |
|
|
{
|
202 |
|
|
this.components = new int[count];
|
203 |
|
|
System.arraycopy(comp, 0, components, 0, count);
|
204 |
|
|
}
|
205 |
|
|
}
|
206 |
|
|
catch (IOException ioe)
|
207 |
|
|
{
|
208 |
|
|
throw new GSSException(GSSException.FAILURE);
|
209 |
|
|
}
|
210 |
|
|
}
|
211 |
|
|
|
212 |
|
|
/**
|
213 |
|
|
* Creates an Oid object from its DER encoding. This refers to the full
|
214 |
|
|
* encoding including tag and length. The structure and encoding of
|
215 |
|
|
* Oids is defined in ISOIEC-8824 and ISOIEC-8825. This method is
|
216 |
|
|
* identical in functionality to its streaming counterpart.
|
217 |
|
|
*
|
218 |
|
|
* @param derOid Byte array storing a DER encoded oid.
|
219 |
|
|
* @throws GSSException If the DER bytes are badly formed.
|
220 |
|
|
*/
|
221 |
|
|
public Oid(byte[] derOid) throws GSSException
|
222 |
|
|
{
|
223 |
|
|
this(new ByteArrayInputStream(derOid));
|
224 |
|
|
this.derOid = (byte[]) derOid.clone();
|
225 |
|
|
}
|
226 |
|
|
|
227 |
|
|
Oid(int[] components)
|
228 |
|
|
{
|
229 |
|
|
this.components = components;
|
230 |
|
|
relative = false;
|
231 |
|
|
}
|
232 |
|
|
|
233 |
|
|
// Instance methods.
|
234 |
|
|
// -------------------------------------------------------------------------
|
235 |
|
|
|
236 |
|
|
/**
|
237 |
|
|
* Returns a string representation of the oid's integer components in
|
238 |
|
|
* dot separated notation (e.g. "1.2.840.113554.1.2.2").
|
239 |
|
|
*
|
240 |
|
|
* @return The string representation of this oid.
|
241 |
|
|
*/
|
242 |
|
|
public String toString()
|
243 |
|
|
{
|
244 |
|
|
if (strOid == null)
|
245 |
|
|
{
|
246 |
|
|
CPStringBuilder buf = new CPStringBuilder();
|
247 |
|
|
for (int i = 0; i < components.length; i++)
|
248 |
|
|
{
|
249 |
|
|
buf.append(components[i]);
|
250 |
|
|
if (i < components.length - 1)
|
251 |
|
|
buf.append('.');
|
252 |
|
|
}
|
253 |
|
|
strOid = buf.toString();
|
254 |
|
|
}
|
255 |
|
|
return strOid;
|
256 |
|
|
}
|
257 |
|
|
|
258 |
|
|
/**
|
259 |
|
|
* Returns the full ASN.1 DER encoding for this oid object, which
|
260 |
|
|
* includes the tag and length.
|
261 |
|
|
*
|
262 |
|
|
* @return The ASN.1 DER encoding for this oid.
|
263 |
|
|
* @throws GSSException If encoding fails.
|
264 |
|
|
*/
|
265 |
|
|
public byte[] getDER() throws GSSException
|
266 |
|
|
{
|
267 |
|
|
if (derOid == null)
|
268 |
|
|
{
|
269 |
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream(256);
|
270 |
|
|
try
|
271 |
|
|
{
|
272 |
|
|
int i = 0;
|
273 |
|
|
if (!relative)
|
274 |
|
|
{
|
275 |
|
|
int b = components[i++] * 40 + (components.length > 1
|
276 |
|
|
? components[i++] : 0);
|
277 |
|
|
encodeSubId(out, b);
|
278 |
|
|
}
|
279 |
|
|
for ( ; i < components.length; i++)
|
280 |
|
|
encodeSubId(out, components[i]);
|
281 |
|
|
byte[] oid = out.toByteArray();
|
282 |
|
|
out.reset();
|
283 |
|
|
if (relative)
|
284 |
|
|
out.write(RELATIVE_OID);
|
285 |
|
|
else
|
286 |
|
|
out.write(OBJECT_IDENTIFIER);
|
287 |
|
|
if (oid.length < 128)
|
288 |
|
|
out.write(oid.length);
|
289 |
|
|
else if (oid.length < 256)
|
290 |
|
|
{
|
291 |
|
|
out.write(0x81);
|
292 |
|
|
out.write(oid.length);
|
293 |
|
|
}
|
294 |
|
|
else if (oid.length < 65536)
|
295 |
|
|
{
|
296 |
|
|
out.write(0x82);
|
297 |
|
|
out.write((oid.length >>> 8) & 0xFF);
|
298 |
|
|
out.write(oid.length & 0xFF);
|
299 |
|
|
}
|
300 |
|
|
else if (oid.length < 16777216)
|
301 |
|
|
{
|
302 |
|
|
out.write(0x83);
|
303 |
|
|
out.write((oid.length >>> 16) & 0xFF);
|
304 |
|
|
out.write((oid.length >>> 8) & 0xFF);
|
305 |
|
|
out.write(oid.length & 0xFF);
|
306 |
|
|
}
|
307 |
|
|
else
|
308 |
|
|
{
|
309 |
|
|
out.write(0x84);
|
310 |
|
|
out.write((oid.length >>> 24) & 0xFF);
|
311 |
|
|
out.write((oid.length >>> 16) & 0xFF);
|
312 |
|
|
out.write((oid.length >>> 8) & 0xFF);
|
313 |
|
|
out.write(oid.length & 0xFF);
|
314 |
|
|
}
|
315 |
|
|
out.write(oid);
|
316 |
|
|
}
|
317 |
|
|
catch (IOException ioe)
|
318 |
|
|
{
|
319 |
|
|
throw new GSSException(GSSException.FAILURE);
|
320 |
|
|
}
|
321 |
|
|
derOid = out.toByteArray();
|
322 |
|
|
}
|
323 |
|
|
return (byte[]) derOid.clone();
|
324 |
|
|
}
|
325 |
|
|
|
326 |
|
|
/**
|
327 |
|
|
* A utility method to test if an Oid object is contained within the
|
328 |
|
|
* supplied Oid object array.
|
329 |
|
|
*
|
330 |
|
|
* @param oids An array of oids to search.
|
331 |
|
|
* @return True if this oid is contained in the given array.
|
332 |
|
|
*/
|
333 |
|
|
public boolean containedIn(Oid[] oids)
|
334 |
|
|
{
|
335 |
|
|
for (int i = 0; i < oids.length; i++)
|
336 |
|
|
{
|
337 |
|
|
if (equals(oids[i]))
|
338 |
|
|
return true;
|
339 |
|
|
}
|
340 |
|
|
return false;
|
341 |
|
|
}
|
342 |
|
|
|
343 |
|
|
public boolean equals(Object o)
|
344 |
|
|
{
|
345 |
|
|
if (!(o instanceof Oid))
|
346 |
|
|
return false;
|
347 |
|
|
Oid that = (Oid) o;
|
348 |
|
|
return Arrays.equals(components, that.components);
|
349 |
|
|
}
|
350 |
|
|
|
351 |
|
|
public int hashCode()
|
352 |
|
|
{
|
353 |
|
|
int code = 0;
|
354 |
|
|
for (int i = 0; i < components.length; i++)
|
355 |
|
|
code += components[i];
|
356 |
|
|
return code;
|
357 |
|
|
}
|
358 |
|
|
|
359 |
|
|
// Own methods.
|
360 |
|
|
// -------------------------------------------------------------------------
|
361 |
|
|
|
362 |
|
|
private static void encodeSubId(OutputStream out, int id) throws IOException
|
363 |
|
|
{
|
364 |
|
|
if (id < 128)
|
365 |
|
|
{
|
366 |
|
|
out.write(id);
|
367 |
|
|
}
|
368 |
|
|
else if (id < 16384)
|
369 |
|
|
{
|
370 |
|
|
out.write((id >>> 7) | 0x80);
|
371 |
|
|
out.write(id & 0x7F);
|
372 |
|
|
}
|
373 |
|
|
else if (id < 2097152)
|
374 |
|
|
{
|
375 |
|
|
out.write((id >>> 14) | 0x80);
|
376 |
|
|
out.write(((id >>> 7) | 0x80) & 0xFF);
|
377 |
|
|
out.write(id & 0x7F);
|
378 |
|
|
}
|
379 |
|
|
else if (id < 268435456)
|
380 |
|
|
{
|
381 |
|
|
out.write( (id >>> 21) | 0x80);
|
382 |
|
|
out.write(((id >>> 14) | 0x80) & 0xFF);
|
383 |
|
|
out.write(((id >>> 7) | 0x80) & 0xFF);
|
384 |
|
|
out.write(id & 0x7F);
|
385 |
|
|
}
|
386 |
|
|
}
|
387 |
|
|
}
|