1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /** 19 * @author Stepan M. Mishura 20 * @version $Revision$ 21 */ 22 23 package org.apache.harmony.security.asn1; 24 25 import java.util.Arrays; 26 27 /** 28 * Instance of this class represents ObjectIdentifier (OID). 29 * 30 * According to X.690: 31 * OID is represented as a sequence of subidentifier. 32 * Each subidentifier is represented as non negative integer value. 33 * There are at least 2 subidentifiers in the sequence. 34 * 35 * Valid values for first subidentifier are 0, 1 and 2. 36 * If the first subidentifier has 0 or 1 value the second 37 * subidentifier must be less then 40. 38 * 39 * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a> 40 */ 41 42 public final class ObjectIdentifier { 43 44 // OID as array of integers 45 private final int[] oid; 46 47 // OID as string 48 private String soid; 49 50 /** 51 * Creates ObjectIdentifier(OID) from array of integers. 52 * 53 * @param oid - array of integers 54 * @throws IllegalArgumentException - if oid is invalid or null 55 */ 56 public ObjectIdentifier(int[] oid) { 57 validate(oid); 58 this.oid = oid; 59 } 60 61 /** 62 * Creates ObjectIdentifier(OID) from string representation. 63 * 64 * @param strOid - oid string 65 * @throws IllegalArgumentException - if oid string is invalid or null 66 */ 67 public ObjectIdentifier(String strOid) { 68 this.oid = toIntArray(strOid); 69 this.soid = strOid; 70 } 71 72 /** 73 * Returns array of integers. 74 * 75 * @return array of integers 76 */ 77 public int[] getOid() { 78 return oid; 79 } 80 81 /** 82 * Compares object with OID for equality. 83 * 84 * @return true if object is ObjectIdentifier and it has the same 85 * representation as array of integers, otherwise false 86 */ 87 public boolean equals(Object o) { 88 if (this == o) { 89 return true; 90 } 91 if (o == null || this.getClass() != o.getClass()) { 92 return false; 93 } 94 return Arrays.equals(oid, ((ObjectIdentifier) o).oid); 95 } 96 97 /** 98 * @see java.lang.Object#toString() 99 */ 100 public String toString() { 101 if (soid == null) { 102 soid = toString(oid); 103 } 104 return soid; 105 } 106 107 /** 108 * @see java.lang.Object#hashCode() 109 */ 110 public int hashCode() { 111 // FIXME change me to Arrays.hashCode(int[]) 112 int intHash = 0; 113 for (int i = 0; i < oid.length && i < 4; i++) { 114 intHash += oid[i] << (8 * i); //TODO what about to find better one? 115 } 116 return intHash & 0x7FFFFFFF; // only positive 117 } 118 119 /** 120 * Validates ObjectIdentifier (OID). 121 * 122 * @param oid - oid as array of integers 123 * @throws IllegalArgumentException - if oid is invalid or null 124 */ 125 public static void validate(int[] oid) { 126 127 if (oid == null) { 128 throw new IllegalArgumentException("oid == null"); 129 } 130 131 if (oid.length < 2) { 132 throw new IllegalArgumentException("OID MUST have at least 2 subidentifiers"); 133 } 134 135 if (oid[0] > 2) { 136 throw new IllegalArgumentException("Valid values for first subidentifier are 0, 1 and 2"); 137 } else if (oid[0] != 2 && oid[1] > 39) { 138 throw new IllegalArgumentException("If the first subidentifier has 0 or 1 value the second subidentifier value MUST be less than 40"); 139 } 140 141 for (int i = 0; i < oid.length; i++) { 142 if (oid[i] < 0) { 143 throw new IllegalArgumentException("Subidentifier MUST have positive value"); 144 } 145 } 146 } 147 148 // FIXME: implement me 149 // /** 150 // * Validates ObjectIdentifier (OID). 151 // * 152 // * @param oid - oid as string 153 // * @throws IllegalArgumentException - if oid string is invalid or null 154 // */ 155 // public static void validate(String oid) { 156 // 157 // if (oid == null) { 158 // throw new NullPointerException(); 159 // } 160 // 161 // int length = oid.length(); 162 // if (length < 3 || oid.charAt(1) != '.') { 163 // throw new IllegalArgumentException("Invalid oid string"); 164 // } 165 // 166 // int pos = 2; 167 // int subidentifier = 0; 168 // switch (oid.charAt(0)) { 169 // case '0': 170 // case '1': 171 // for (char c = oid.charAt(pos);;) { 172 // if (c < '0' || c > '9') { 173 // throw new IllegalArgumentException("Invalid oid string"); 174 // } else { 175 // subidentifier = subidentifier * 10 + c - '0'; 176 // } 177 // 178 // pos++; 179 // if (pos == length) { 180 // break; 181 // } 182 // 183 // c = oid.charAt(pos); 184 // if (c == '.') { 185 // pos++; 186 // if (pos == length) { 187 // throw new IllegalArgumentException("Invalid oid string"); 188 // } 189 // break; 190 // } 191 // } 192 // 193 // if (subidentifier > 39) { 194 // throw new IllegalArgumentException( 195 // "If the first subidentifier has 0 or 1 value the second " 196 // + "subidentifier value MUST be less then 40."); 197 // } 198 // break; 199 // case '2': 200 // break; 201 // default: 202 // throw new IllegalArgumentException( 203 // "Valid values for first subidentifier are 0, 1 and 2"); 204 // } 205 // 206 // if (pos == length) { 207 // return; 208 // } 209 // 210 // for (char c = oid.charAt(pos);;) { 211 // if (c < '0' || c > '9') { 212 // throw new IllegalArgumentException("Invalid oid string"); 213 // } 214 // 215 // pos++; 216 // if (pos == length) { 217 // return; 218 // } 219 // 220 // c = oid.charAt(pos); 221 // if (c == '.') { 222 // pos++; 223 // if (pos == length) { 224 // throw new IllegalArgumentException("Invalid oid string"); 225 // } 226 // } 227 // } 228 // } 229 230 /** 231 * Returns string representation of OID. 232 * 233 * Note: it is supposed that passed array of integers 234 * contains valid OID value, so no checks are performed. 235 * 236 * @param oid - oid as array of integers 237 * @return oid string representation 238 */ 239 public static String toString(int[] oid) { 240 StringBuilder sb = new StringBuilder(3 * oid.length); 241 242 for (int i = 0; i < oid.length - 1; ++i) { 243 sb.append(oid[i]); 244 sb.append('.'); 245 } 246 sb.append(oid[oid.length - 1]); 247 return sb.toString(); 248 } 249 250 // BEGIN android-changed 251 /** 252 * Gets ObjectIdentifier (OID) from string representation. 253 * 254 * String representation is defined by the following syntax: 255 * OID = subidentifier 1*("." subidentifier) 256 * subidentifier = 1*(digit) 257 * 258 * @param oidString - string representation of OID 259 * @return - oid as array of integers 260 * @throws IllegalArgumentException - if oid string is invalid or null 261 */ 262 public static int[] toIntArray(String str) { 263 return toIntArray(str, true); 264 } 265 266 /** 267 * Returns whether the given string is a valid ObjectIdentifier 268 * (OID) representation. 269 * 270 * String representation is defined as for {@link #toIntArray}. 271 * 272 * @param oidString - string representation of OID 273 * @return true if oidString has valid syntax or false if not 274 */ 275 public static boolean isOID(String str) { 276 return toIntArray(str, false) != null; 277 } 278 279 /** 280 * Gets ObjectIdentifier (OID) from string representation. 281 * 282 * String representation is defined by the following syntax: 283 * OID = subidentifier 1*("." subidentifier) 284 * subidentifier = 1*(digit) 285 * 286 * @param oidString - string representation of OID 287 * @return - oid as array of integers or null if the oid string is 288 * invalid or null and shouldThrow is false 289 * @throws IllegalArgumentException - if oid string is invalid or null and 290 * shouldThrow is true 291 */ 292 private static int[] toIntArray(String str, boolean shouldThrow) { 293 if (str == null) { 294 if (! shouldThrow) { 295 return null; 296 } 297 throw new IllegalArgumentException(); 298 } 299 300 int length = str.length(); 301 if (length == 0) { 302 if (! shouldThrow) { 303 return null; 304 } 305 throw new IllegalArgumentException("Incorrect syntax"); 306 } 307 308 int count = 1; // number of subidentifiers 309 boolean wasDot = true; // indicates whether char before was dot or not. 310 char c; // current char 311 for (int i = 0; i < length; i++) { 312 c = str.charAt(i); 313 if (c == '.') { 314 if (wasDot) { 315 if (! shouldThrow) { 316 return null; 317 } 318 throw new IllegalArgumentException("Incorrect syntax"); 319 } 320 wasDot = true; 321 count++; 322 } else if (c >= '0' && c <= '9') { 323 wasDot = false; 324 } else { 325 if (! shouldThrow) { 326 return null; 327 } 328 throw new IllegalArgumentException("Incorrect syntax"); 329 } 330 } 331 332 if (wasDot) { 333 // the last char is dot 334 if (! shouldThrow) { 335 return null; 336 } 337 throw new IllegalArgumentException("Incorrect syntax"); 338 } 339 340 if (count < 2) { 341 if (! shouldThrow) { 342 return null; 343 } 344 throw new IllegalArgumentException("Incorrect syntax"); 345 } 346 347 int[] oid = new int[count]; 348 for (int i = 0, j = 0; i < length; i++) { 349 c = str.charAt(i); 350 if (c == '.') { 351 j++; 352 } else { 353 oid[j] = oid[j] * 10 + c - 48; // '0' = 48 354 } 355 } 356 357 if (oid[0] > 2) { 358 if (! shouldThrow) { 359 return null; 360 } 361 throw new IllegalArgumentException("Incorrect syntax"); 362 } else if (oid[0] != 2 && oid[1] > 39) { 363 if (! shouldThrow) { 364 return null; 365 } 366 throw new IllegalArgumentException("Incorrect syntax"); 367 } 368 369 return oid; 370 } 371 // END android-changed 372 } 373