001: package org.bouncycastle.asn1;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.io.IOException;
005: import java.io.OutputStream;
006: import java.math.BigInteger;
007:
008: public class DERObjectIdentifier extends ASN1Object {
009: String identifier;
010:
011: /**
012: * return an OID from the passed in object
013: *
014: * @exception IllegalArgumentException if the object cannot be converted.
015: */
016: public static DERObjectIdentifier getInstance(Object obj) {
017: if (obj == null || obj instanceof DERObjectIdentifier) {
018: return (DERObjectIdentifier) obj;
019: }
020:
021: if (obj instanceof ASN1OctetString) {
022: return new DERObjectIdentifier(((ASN1OctetString) obj)
023: .getOctets());
024: }
025:
026: if (obj instanceof ASN1TaggedObject) {
027: return getInstance(((ASN1TaggedObject) obj).getObject());
028: }
029:
030: throw new IllegalArgumentException(
031: "illegal object in getInstance: "
032: + obj.getClass().getName());
033: }
034:
035: /**
036: * return an Object Identifier from a tagged object.
037: *
038: * @param obj the tagged object holding the object we want
039: * @param explicit true if the object is meant to be explicitly
040: * tagged false otherwise.
041: * @exception IllegalArgumentException if the tagged object cannot
042: * be converted.
043: */
044: public static DERObjectIdentifier getInstance(ASN1TaggedObject obj,
045: boolean explicit) {
046: return getInstance(obj.getObject());
047: }
048:
049: DERObjectIdentifier(byte[] bytes) {
050: StringBuffer objId = new StringBuffer();
051: long value = 0;
052: BigInteger bigValue = null;
053: boolean first = true;
054:
055: for (int i = 0; i != bytes.length; i++) {
056: int b = bytes[i] & 0xff;
057:
058: if (value < 0x80000000000000L) {
059: value = value * 128 + (b & 0x7f);
060: if ((b & 0x80) == 0) // end of number reached
061: {
062: if (first) {
063: switch ((int) value / 40) {
064: case 0:
065: objId.append('0');
066: break;
067: case 1:
068: objId.append('1');
069: value -= 40;
070: break;
071: default:
072: objId.append('2');
073: value -= 80;
074: }
075: first = false;
076: }
077:
078: objId.append('.');
079: objId.append(value);
080: value = 0;
081: }
082: } else {
083: if (bigValue == null) {
084: bigValue = BigInteger.valueOf(value);
085: }
086: bigValue = bigValue.shiftLeft(7);
087: bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
088: if ((b & 0x80) == 0) {
089: objId.append('.');
090: objId.append(bigValue);
091: bigValue = null;
092: value = 0;
093: }
094: }
095: }
096:
097: this .identifier = objId.toString();
098: }
099:
100: public DERObjectIdentifier(String identifier) {
101: if (!isValidIdentifier(identifier)) {
102: throw new IllegalArgumentException("string " + identifier
103: + " not an OID");
104: }
105:
106: this .identifier = identifier;
107: }
108:
109: public String getId() {
110: return identifier;
111: }
112:
113: private void writeField(OutputStream out, long fieldValue)
114: throws IOException {
115: if (fieldValue >= (1L << 7)) {
116: if (fieldValue >= (1L << 14)) {
117: if (fieldValue >= (1L << 21)) {
118: if (fieldValue >= (1L << 28)) {
119: if (fieldValue >= (1L << 35)) {
120: if (fieldValue >= (1L << 42)) {
121: if (fieldValue >= (1L << 49)) {
122: if (fieldValue >= (1L << 56)) {
123: out
124: .write((int) (fieldValue >> 56) | 0x80);
125: }
126: out
127: .write((int) (fieldValue >> 49) | 0x80);
128: }
129: out
130: .write((int) (fieldValue >> 42) | 0x80);
131: }
132: out.write((int) (fieldValue >> 35) | 0x80);
133: }
134: out.write((int) (fieldValue >> 28) | 0x80);
135: }
136: out.write((int) (fieldValue >> 21) | 0x80);
137: }
138: out.write((int) (fieldValue >> 14) | 0x80);
139: }
140: out.write((int) (fieldValue >> 7) | 0x80);
141: }
142: out.write((int) fieldValue & 0x7f);
143: }
144:
145: private void writeField(OutputStream out, BigInteger fieldValue)
146: throws IOException {
147: int byteCount = (fieldValue.bitLength() + 6) / 7;
148: if (byteCount == 0) {
149: out.write(0);
150: } else {
151: BigInteger tmpValue = fieldValue;
152: byte[] tmp = new byte[byteCount];
153: for (int i = byteCount - 1; i >= 0; i--) {
154: tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80);
155: tmpValue = tmpValue.shiftRight(7);
156: }
157: tmp[byteCount - 1] &= 0x7f;
158: out.write(tmp);
159: }
160:
161: }
162:
163: void encode(DEROutputStream out) throws IOException {
164: OIDTokenizer tok = new OIDTokenizer(identifier);
165: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
166: DEROutputStream dOut = new DEROutputStream(bOut);
167:
168: writeField(bOut, Integer.parseInt(tok.nextToken()) * 40
169: + Integer.parseInt(tok.nextToken()));
170:
171: while (tok.hasMoreTokens()) {
172: String token = tok.nextToken();
173: if (token.length() < 18) {
174: writeField(bOut, Long.parseLong(token));
175: } else {
176: writeField(bOut, new BigInteger(token));
177: }
178: }
179:
180: dOut.close();
181:
182: byte[] bytes = bOut.toByteArray();
183:
184: out.writeEncoded(OBJECT_IDENTIFIER, bytes);
185: }
186:
187: public int hashCode() {
188: return identifier.hashCode();
189: }
190:
191: boolean asn1Equals(DERObject o) {
192: if (!(o instanceof DERObjectIdentifier)) {
193: return false;
194: }
195:
196: return identifier.equals(((DERObjectIdentifier) o).identifier);
197: }
198:
199: public String toString() {
200: return getId();
201: }
202:
203: private static boolean isValidIdentifier(String identifier) {
204: if (identifier.length() < 3 || identifier.charAt(1) != '.') {
205: return false;
206: }
207:
208: char first = identifier.charAt(0);
209: if (first < '0' || first > '2') {
210: return false;
211: }
212:
213: boolean periodAllowed = false;
214: for (int i = identifier.length() - 1; i >= 2; i--) {
215: char ch = identifier.charAt(i);
216:
217: if ('0' <= ch && ch <= '9') {
218: periodAllowed = true;
219: continue;
220: }
221:
222: if (ch == '.') {
223: if (!periodAllowed) {
224: return false;
225: }
226:
227: periodAllowed = false;
228: continue;
229: }
230:
231: return false;
232: }
233:
234: return periodAllowed;
235: }
236: }
|