1package org.bouncycastle.asn1; 2 3import java.io.ByteArrayOutputStream; 4import java.io.IOException; 5import java.io.OutputStream; 6import java.math.BigInteger; 7 8public class DERObjectIdentifier 9 extends DERObject 10{ 11 String identifier; 12 13 /** 14 * return an OID from the passed in object 15 * 16 * @exception IllegalArgumentException if the object cannot be converted. 17 */ 18 public static DERObjectIdentifier getInstance( 19 Object obj) 20 { 21 if (obj == null || obj instanceof DERObjectIdentifier) 22 { 23 return (DERObjectIdentifier)obj; 24 } 25 26 if (obj instanceof ASN1OctetString) 27 { 28 return new DERObjectIdentifier(((ASN1OctetString)obj).getOctets()); 29 } 30 31 if (obj instanceof ASN1TaggedObject) 32 { 33 return getInstance(((ASN1TaggedObject)obj).getObject()); 34 } 35 36 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 37 } 38 39 /** 40 * return an Object Identifier from a tagged object. 41 * 42 * @param obj the tagged object holding the object we want 43 * @param explicit true if the object is meant to be explicitly 44 * tagged false otherwise. 45 * @exception IllegalArgumentException if the tagged object cannot 46 * be converted. 47 */ 48 public static DERObjectIdentifier getInstance( 49 ASN1TaggedObject obj, 50 boolean explicit) 51 { 52 return getInstance(obj.getObject()); 53 } 54 55 56 DERObjectIdentifier( 57 byte[] bytes) 58 { 59 StringBuffer objId = new StringBuffer(); 60 long value = 0; 61 BigInteger bigValue = null; 62 boolean first = true; 63 64 for (int i = 0; i != bytes.length; i++) 65 { 66 int b = bytes[i] & 0xff; 67 68 if (value < 0x80000000000000L) 69 { 70 value = value * 128 + (b & 0x7f); 71 if ((b & 0x80) == 0) // end of number reached 72 { 73 if (first) 74 { 75 switch ((int)value / 40) 76 { 77 case 0: 78 objId.append('0'); 79 break; 80 case 1: 81 objId.append('1'); 82 value -= 40; 83 break; 84 default: 85 objId.append('2'); 86 value -= 80; 87 } 88 first = false; 89 } 90 91 objId.append('.'); 92 objId.append(value); 93 value = 0; 94 } 95 } 96 else 97 { 98 if (bigValue == null) 99 { 100 bigValue = BigInteger.valueOf(value); 101 } 102 bigValue = bigValue.shiftLeft(7); 103 bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); 104 if ((b & 0x80) == 0) 105 { 106 objId.append('.'); 107 objId.append(bigValue); 108 bigValue = null; 109 value = 0; 110 } 111 } 112 } 113 114 // BEGIN android-changed 115 /* 116 * Intern the identifier so there aren't hundreds of duplicates 117 * (in practice). 118 */ 119 this.identifier = objId.toString().intern(); 120 // END android-changed 121 } 122 123 public DERObjectIdentifier( 124 String identifier) 125 { 126 if (!isValidIdentifier(identifier)) 127 { 128 throw new IllegalArgumentException("string " + identifier + " not an OID"); 129 } 130 131 // BEGIN android-changed 132 /* 133 * Intern the identifier so there aren't hundreds of duplicates 134 * (in practice). 135 */ 136 this.identifier = identifier.intern(); 137 // END android-changed 138 } 139 140 public String getId() 141 { 142 return identifier; 143 } 144 145 private void writeField( 146 OutputStream out, 147 long fieldValue) 148 throws IOException 149 { 150 if (fieldValue >= (1L << 7)) 151 { 152 if (fieldValue >= (1L << 14)) 153 { 154 if (fieldValue >= (1L << 21)) 155 { 156 if (fieldValue >= (1L << 28)) 157 { 158 if (fieldValue >= (1L << 35)) 159 { 160 if (fieldValue >= (1L << 42)) 161 { 162 if (fieldValue >= (1L << 49)) 163 { 164 if (fieldValue >= (1L << 56)) 165 { 166 out.write((int)(fieldValue >> 56) | 0x80); 167 } 168 out.write((int)(fieldValue >> 49) | 0x80); 169 } 170 out.write((int)(fieldValue >> 42) | 0x80); 171 } 172 out.write((int)(fieldValue >> 35) | 0x80); 173 } 174 out.write((int)(fieldValue >> 28) | 0x80); 175 } 176 out.write((int)(fieldValue >> 21) | 0x80); 177 } 178 out.write((int)(fieldValue >> 14) | 0x80); 179 } 180 out.write((int)(fieldValue >> 7) | 0x80); 181 } 182 out.write((int)fieldValue & 0x7f); 183 } 184 185 private void writeField( 186 OutputStream out, 187 BigInteger fieldValue) 188 throws IOException 189 { 190 int byteCount = (fieldValue.bitLength()+6)/7; 191 if (byteCount == 0) 192 { 193 out.write(0); 194 } 195 else 196 { 197 BigInteger tmpValue = fieldValue; 198 byte[] tmp = new byte[byteCount]; 199 for (int i = byteCount-1; i >= 0; i--) 200 { 201 tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80); 202 tmpValue = tmpValue.shiftRight(7); 203 } 204 tmp[byteCount-1] &= 0x7f; 205 out.write(tmp); 206 } 207 208 } 209 210 void encode( 211 DEROutputStream out) 212 throws IOException 213 { 214 OIDTokenizer tok = new OIDTokenizer(identifier); 215 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 216 DEROutputStream dOut = new DEROutputStream(bOut); 217 218 writeField(bOut, 219 Integer.parseInt(tok.nextToken()) * 40 220 + Integer.parseInt(tok.nextToken())); 221 222 while (tok.hasMoreTokens()) 223 { 224 String token = tok.nextToken(); 225 if (token.length() < 18) 226 { 227 writeField(bOut, Long.parseLong(token)); 228 } 229 else 230 { 231 writeField(bOut, new BigInteger(token)); 232 } 233 } 234 235 dOut.close(); 236 237 byte[] bytes = bOut.toByteArray(); 238 239 out.writeEncoded(OBJECT_IDENTIFIER, bytes); 240 } 241 242 public int hashCode() 243 { 244 return identifier.hashCode(); 245 } 246 247 public boolean equals( 248 Object o) 249 { 250 if ((o == null) || !(o instanceof DERObjectIdentifier)) 251 { 252 return false; 253 } 254 255 return identifier.equals(((DERObjectIdentifier)o).identifier); 256 } 257 258 public String toString() 259 { 260 return getId(); 261 } 262 263 private static boolean isValidIdentifier( 264 String identifier) 265 { 266 boolean periodAllowed = false; 267 for (int i = identifier.length() - 1; i >= 0; i--) 268 { 269 char ch = identifier.charAt(i); 270 271 if ('0' <= ch && ch <= '9') 272 { 273 periodAllowed = true; 274 continue; 275 } 276 277 if (ch == '.') 278 { 279 if (!periodAllowed) 280 { 281 return false; 282 } 283 284 periodAllowed = false; 285 continue; 286 } 287 288 return false; 289 } 290 291 return periodAllowed; 292 } 293} 294