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