386 lines
12 KiB
Java
386 lines
12 KiB
Java
|
/* Oid.java -- Object identifier class.
|
||
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
||
|
|
||
|
This file is part of GNU Classpath.
|
||
|
|
||
|
GNU Classpath is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 2, or (at your option)
|
||
|
any later version.
|
||
|
|
||
|
GNU Classpath is distributed in the hope that it will be useful, but
|
||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with GNU Classpath; see the file COPYING. If not, write to the
|
||
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||
|
02110-1301 USA.
|
||
|
|
||
|
Linking this library statically or dynamically with other modules is
|
||
|
making a combined work based on this library. Thus, the terms and
|
||
|
conditions of the GNU General Public License cover the whole
|
||
|
combination.
|
||
|
|
||
|
As a special exception, the copyright holders of this library give you
|
||
|
permission to link this library with independent modules to produce an
|
||
|
executable, regardless of the license terms of these independent
|
||
|
modules, and to copy and distribute the resulting executable under
|
||
|
terms of your choice, provided that you also meet, for each linked
|
||
|
independent module, the terms and conditions of the license of that
|
||
|
module. An independent module is a module which is not derived from
|
||
|
or based on this library. If you modify this library, you may extend
|
||
|
this exception to your version of the library, but you are not
|
||
|
obligated to do so. If you do not wish to do so, delete this
|
||
|
exception statement from your version.
|
||
|
|
||
|
The documentation comments of this class are derived from the text
|
||
|
of RFC 2853: Generic Security Service API Version 2: Java Bindings.
|
||
|
That document is covered under the following license notice:
|
||
|
|
||
|
Copyright (C) The Internet Society (2000). All Rights Reserved.
|
||
|
|
||
|
This document and translations of it may be copied and furnished to
|
||
|
others, and derivative works that comment on or otherwise explain it
|
||
|
or assist in its implementation may be prepared, copied, published and
|
||
|
distributed, in whole or in part, without restriction of any kind,
|
||
|
provided that the above copyright notice and this paragraph are
|
||
|
included on all such copies and derivative works. However, this
|
||
|
document itself may not be modified in any way, such as by removing
|
||
|
the copyright notice or references to the Internet Society or other
|
||
|
Internet organizations, except as needed for the purpose of developing
|
||
|
Internet standards in which case the procedures for copyrights defined
|
||
|
in the Internet Standards process must be followed, or as required to
|
||
|
translate it into languages other than English.
|
||
|
|
||
|
The limited permissions granted above are perpetual and will not be
|
||
|
revoked by the Internet Society or its successors or assigns.
|
||
|
|
||
|
This document and the information contained herein is provided on an
|
||
|
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||
|
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT
|
||
|
NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN
|
||
|
WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||
|
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */
|
||
|
|
||
|
|
||
|
package org.ietf.jgss;
|
||
|
|
||
|
import java.io.ByteArrayInputStream;
|
||
|
import java.io.ByteArrayOutputStream;
|
||
|
import java.io.DataInputStream;
|
||
|
import java.io.InputStream;
|
||
|
import java.io.IOException;
|
||
|
import java.io.OutputStream;
|
||
|
|
||
|
import java.math.BigInteger;
|
||
|
|
||
|
import java.util.Arrays;
|
||
|
import java.util.StringTokenizer;
|
||
|
|
||
|
/**
|
||
|
* <p>This class represents Universal Object Identifiers (Oids) and their
|
||
|
* associated operations.</p>
|
||
|
*
|
||
|
* <p>Oids are hierarchically globally-interpretable identifiers used
|
||
|
* within the GSS-API framework to identify mechanisms and name formats.</p>
|
||
|
*
|
||
|
* <p>The structure and encoding of Oids is defined in ISOIEC-8824 and
|
||
|
* ISOIEC-8825. For example the Oid representation of Kerberos V5
|
||
|
* mechanism is "1.2.840.113554.1.2.2".</p>
|
||
|
*
|
||
|
* <p>The {@link GSSName} name class contains <code>public static Oid</code>
|
||
|
* objects representing the standard name types defined in GSS-API.</p>
|
||
|
*/
|
||
|
public class Oid
|
||
|
{
|
||
|
|
||
|
// Constants and fields.
|
||
|
// -------------------------------------------------------------------------
|
||
|
|
||
|
private static final int OBJECT_IDENTIFIER = 0x06;
|
||
|
private static final int RELATIVE_OID = 0x0d;
|
||
|
|
||
|
private final int[] components;
|
||
|
private byte[] derOid;
|
||
|
private String strOid;
|
||
|
private boolean relative;
|
||
|
|
||
|
// Constructors.
|
||
|
// -------------------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Creates an Oid object from a string representation of its integer
|
||
|
* components (e.g. "1.2.840.113554.1.2.2").
|
||
|
*
|
||
|
* @param strOid The string representation for the oid.
|
||
|
* @throws GSSException If the argument is badly formed.
|
||
|
*/
|
||
|
public Oid(String strOid) throws GSSException
|
||
|
{
|
||
|
if (strOid == null)
|
||
|
throw new NullPointerException();
|
||
|
this.strOid = strOid;
|
||
|
try
|
||
|
{
|
||
|
StringTokenizer tok = new StringTokenizer(strOid, ".");
|
||
|
components = new int[tok.countTokens()];
|
||
|
int i = 0;
|
||
|
while (tok.hasMoreTokens() && i < components.length)
|
||
|
{
|
||
|
components[i++] = Integer.parseInt(tok.nextToken());
|
||
|
}
|
||
|
}
|
||
|
catch (Exception x)
|
||
|
{
|
||
|
throw new GSSException(GSSException.FAILURE);
|
||
|
}
|
||
|
relative = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates an Oid object from its DER encoding. This refers to the full
|
||
|
* encoding including tag and length. The structure and encoding of
|
||
|
* Oids is defined in ISOIEC-8824 and ISOIEC-8825. This method is
|
||
|
* identical in functionality to its byte array counterpart.
|
||
|
*
|
||
|
* @param derOid Stream containing the DER encoded oid.
|
||
|
* @throws GSSException If the DER stream is badly formed, or if the
|
||
|
* input stream throws an exception.
|
||
|
*/
|
||
|
public Oid(InputStream derOid) throws GSSException
|
||
|
{
|
||
|
DataInputStream in = new DataInputStream(derOid);
|
||
|
try
|
||
|
{
|
||
|
int tag = in.read() & 0x1F;
|
||
|
if (tag != OBJECT_IDENTIFIER && tag != RELATIVE_OID)
|
||
|
throw new IOException();
|
||
|
int len = in.read();
|
||
|
if ((len & ~0x7F) != 0)
|
||
|
{
|
||
|
byte[] buf = new byte[len & 0x7F];
|
||
|
in.readFully(buf);
|
||
|
len = new BigInteger(1, buf).intValue();
|
||
|
}
|
||
|
if (len < 0)
|
||
|
throw new IOException();
|
||
|
byte[] enc = new byte[len];
|
||
|
in.readFully(enc);
|
||
|
int[] comp = new int[len + 1];
|
||
|
int count = 0;
|
||
|
int i = 0;
|
||
|
relative = tag == RELATIVE_OID;
|
||
|
if (!relative && i < len)
|
||
|
{
|
||
|
int j = (enc[i] & 0xFF);
|
||
|
comp[count++] = j / 40;
|
||
|
comp[count++] = j % 40;
|
||
|
i++;
|
||
|
}
|
||
|
while (i < len)
|
||
|
{
|
||
|
int j = 0;
|
||
|
do
|
||
|
{
|
||
|
j = enc[i++] & 0xFF;
|
||
|
comp[count] <<= 7;
|
||
|
comp[count] |= j & 0x7F;
|
||
|
if (i >= len && (j & 0x80) != 0)
|
||
|
throw new IOException();
|
||
|
}
|
||
|
while ((j & 0x80) != 0);
|
||
|
count++;
|
||
|
}
|
||
|
if (count == len)
|
||
|
this.components = comp;
|
||
|
else
|
||
|
{
|
||
|
this.components = new int[count];
|
||
|
System.arraycopy(comp, 0, components, 0, count);
|
||
|
}
|
||
|
}
|
||
|
catch (IOException ioe)
|
||
|
{
|
||
|
throw new GSSException(GSSException.FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates an Oid object from its DER encoding. This refers to the full
|
||
|
* encoding including tag and length. The structure and encoding of
|
||
|
* Oids is defined in ISOIEC-8824 and ISOIEC-8825. This method is
|
||
|
* identical in functionality to its streaming counterpart.
|
||
|
*
|
||
|
* @param derOid Byte array storing a DER encoded oid.
|
||
|
* @throws GSSException If the DER bytes are badly formed.
|
||
|
*/
|
||
|
public Oid(byte[] derOid) throws GSSException
|
||
|
{
|
||
|
this(new ByteArrayInputStream(derOid));
|
||
|
this.derOid = (byte[]) derOid.clone();
|
||
|
}
|
||
|
|
||
|
Oid(int[] components)
|
||
|
{
|
||
|
this.components = components;
|
||
|
relative = false;
|
||
|
}
|
||
|
|
||
|
// Instance methods.
|
||
|
// -------------------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Returns a string representation of the oid's integer components in
|
||
|
* dot separated notation (e.g. "1.2.840.113554.1.2.2").
|
||
|
*
|
||
|
* @return The string representation of this oid.
|
||
|
*/
|
||
|
public String toString()
|
||
|
{
|
||
|
if (strOid == null)
|
||
|
{
|
||
|
StringBuffer buf = new StringBuffer();
|
||
|
for (int i = 0; i < components.length; i++)
|
||
|
{
|
||
|
buf.append(components[i]);
|
||
|
if (i < components.length - 1)
|
||
|
buf.append('.');
|
||
|
}
|
||
|
strOid = buf.toString();
|
||
|
}
|
||
|
return strOid;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the full ASN.1 DER encoding for this oid object, which
|
||
|
* includes the tag and length.
|
||
|
*
|
||
|
* @return The ASN.1 DER encoding for this oid.
|
||
|
* @throws GSSException If encoding fails.
|
||
|
*/
|
||
|
public byte[] getDER() throws GSSException
|
||
|
{
|
||
|
if (derOid == null)
|
||
|
{
|
||
|
ByteArrayOutputStream out = new ByteArrayOutputStream(256);
|
||
|
try
|
||
|
{
|
||
|
int i = 0;
|
||
|
if (!relative)
|
||
|
{
|
||
|
int b = components[i++] * 40 + (components.length > 1
|
||
|
? components[i++] : 0);
|
||
|
encodeSubId(out, b);
|
||
|
}
|
||
|
for ( ; i < components.length; i++)
|
||
|
encodeSubId(out, components[i]);
|
||
|
byte[] oid = out.toByteArray();
|
||
|
out.reset();
|
||
|
if (relative)
|
||
|
out.write(RELATIVE_OID);
|
||
|
else
|
||
|
out.write(OBJECT_IDENTIFIER);
|
||
|
if (oid.length < 128)
|
||
|
out.write(oid.length);
|
||
|
else if (oid.length < 256)
|
||
|
{
|
||
|
out.write(0x81);
|
||
|
out.write(oid.length);
|
||
|
}
|
||
|
else if (oid.length < 65536)
|
||
|
{
|
||
|
out.write(0x82);
|
||
|
out.write((oid.length >>> 8) & 0xFF);
|
||
|
out.write(oid.length & 0xFF);
|
||
|
}
|
||
|
else if (oid.length < 16777216)
|
||
|
{
|
||
|
out.write(0x83);
|
||
|
out.write((oid.length >>> 16) & 0xFF);
|
||
|
out.write((oid.length >>> 8) & 0xFF);
|
||
|
out.write(oid.length & 0xFF);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
out.write(0x84);
|
||
|
out.write((oid.length >>> 24) & 0xFF);
|
||
|
out.write((oid.length >>> 16) & 0xFF);
|
||
|
out.write((oid.length >>> 8) & 0xFF);
|
||
|
out.write(oid.length & 0xFF);
|
||
|
}
|
||
|
out.write(oid);
|
||
|
}
|
||
|
catch (IOException ioe)
|
||
|
{
|
||
|
throw new GSSException(GSSException.FAILURE);
|
||
|
}
|
||
|
derOid = out.toByteArray();
|
||
|
}
|
||
|
return (byte[]) derOid.clone();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A utility method to test if an Oid object is contained within the
|
||
|
* supplied Oid object array.
|
||
|
*
|
||
|
* @param oids An array of oids to search.
|
||
|
* @return True if this oid is contained in the given array.
|
||
|
*/
|
||
|
public boolean containedIn(Oid[] oids)
|
||
|
{
|
||
|
for (int i = 0; i < oids.length; i++)
|
||
|
{
|
||
|
if (equals(oids[i]))
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public boolean equals(Object o)
|
||
|
{
|
||
|
if (!(o instanceof Oid))
|
||
|
return false;
|
||
|
Oid that = (Oid) o;
|
||
|
return Arrays.equals(components, that.components);
|
||
|
}
|
||
|
|
||
|
public int hashCode()
|
||
|
{
|
||
|
int code = 0;
|
||
|
for (int i = 0; i < components.length; i++)
|
||
|
code += components[i];
|
||
|
return code;
|
||
|
}
|
||
|
|
||
|
// Own methods.
|
||
|
// -------------------------------------------------------------------------
|
||
|
|
||
|
private static void encodeSubId(OutputStream out, int id) throws IOException
|
||
|
{
|
||
|
if (id < 128)
|
||
|
{
|
||
|
out.write(id);
|
||
|
}
|
||
|
else if (id < 16384)
|
||
|
{
|
||
|
out.write((id >>> 7) | 0x80);
|
||
|
out.write(id & 0x7F);
|
||
|
}
|
||
|
else if (id < 2097152)
|
||
|
{
|
||
|
out.write((id >>> 14) | 0x80);
|
||
|
out.write(((id >>> 7) | 0x80) & 0xFF);
|
||
|
out.write(id & 0x7F);
|
||
|
}
|
||
|
else if (id < 268435456)
|
||
|
{
|
||
|
out.write( (id >>> 21) | 0x80);
|
||
|
out.write(((id >>> 14) | 0x80) & 0xFF);
|
||
|
out.write(((id >>> 7) | 0x80) & 0xFF);
|
||
|
out.write(id & 0x7F);
|
||
|
}
|
||
|
}
|
||
|
}
|