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 public final class ObjectIdentifier { 42 43 /** OID as array of integers */ 44 private final int[] oid; 45 46 /** OID as string */ 47 private String soid; 48 49 /** 50 * Creates ObjectIdentifier(OID) from array of integers. 51 * 52 * @param oid array of integers 53 * @throws IllegalArgumentException if oid is invalid or null 54 */ 55 public ObjectIdentifier(int[] oid) { 56 validate(oid); 57 this.oid = oid; 58 } 59 60 /** 61 * Creates ObjectIdentifier(OID) from string representation. 62 * 63 * @param strOid oid string 64 * @throws IllegalArgumentException if oid string is invalid or null 65 */ 66 public ObjectIdentifier(String strOid) { 67 this.oid = toIntArray(strOid); 68 this.soid = strOid; 69 } 70 71 @Override public boolean equals(Object o) { 72 if (this == o) { 73 return true; 74 } 75 if (o == null || this.getClass() != o.getClass()) { 76 return false; 77 } 78 return Arrays.equals(oid, ((ObjectIdentifier) o).oid); 79 } 80 81 @Override public String toString() { 82 if (soid == null) { 83 soid = toString(oid); 84 } 85 return soid; 86 } 87 88 @Override public int hashCode() { 89 // FIXME change me to Arrays.hashCode(int[]) 90 int intHash = 0; 91 for (int i = 0; i < oid.length && i < 4; i++) { 92 intHash += oid[i] << (8 * i); //TODO what about to find better one? 93 } 94 return intHash & 0x7FFFFFFF; // only positive 95 } 96 97 /** 98 * Validates ObjectIdentifier (OID). 99 * 100 * @param oid oid as array of integers 101 * @throws IllegalArgumentException if oid is invalid or null 102 */ 103 public static void validate(int[] oid) { 104 if (oid == null) { 105 throw new IllegalArgumentException("oid == null"); 106 } 107 108 if (oid.length < 2) { 109 throw new IllegalArgumentException("OID MUST have at least 2 subidentifiers"); 110 } 111 112 if (oid[0] > 2) { 113 throw new IllegalArgumentException( 114 "Valid values for first subidentifier are 0, 1 and 2"); 115 } else if (oid[0] != 2 && oid[1] > 39) { 116 throw new IllegalArgumentException("If the first subidentifier has 0 or 1 value the " 117 + "second subidentifier value MUST be less than 40"); 118 } 119 120 for (int anOid : oid) { 121 if (anOid < 0) { 122 throw new IllegalArgumentException("Subidentifier MUST have positive value"); 123 } 124 } 125 } 126 127 /** 128 * Returns string representation of OID. 129 * 130 * Note: it is supposed that passed array of integers 131 * contains valid OID value, so no checks are performed. 132 * 133 * @param oid oid as array of integers 134 * @return oid string representation 135 */ 136 public static String toString(int[] oid) { 137 StringBuilder sb = new StringBuilder(3 * oid.length); 138 139 for (int i = 0; i < oid.length - 1; ++i) { 140 sb.append(oid[i]); 141 sb.append('.'); 142 } 143 sb.append(oid[oid.length - 1]); 144 return sb.toString(); 145 } 146 147 /** 148 * Gets ObjectIdentifier (OID) from string representation. 149 * 150 * String representation is defined by the following syntax: 151 * OID = subidentifier 1*("." subidentifier) 152 * subidentifier = 1*(digit) 153 * 154 * @param str string representation of OID 155 * @return oid as array of integers 156 * @throws IllegalArgumentException if oid string is invalid or null 157 */ 158 public static int[] toIntArray(String str) { 159 return toIntArray(str, true); 160 } 161 162 /** 163 * Returns whether the given string is a valid ObjectIdentifier 164 * (OID) representation. 165 * 166 * String representation is defined as for {@link #toIntArray}. 167 * 168 * @param str string representation of OID 169 * @return true if oidString has valid syntax or false if not 170 */ 171 public static boolean isOID(String str) { 172 return toIntArray(str, false) != null; 173 } 174 175 /** 176 * Gets ObjectIdentifier (OID) from string representation. 177 * 178 * String representation is defined by the following syntax: 179 * OID = subidentifier 1*("." subidentifier) 180 * subidentifier = 1*(digit) 181 * 182 * @param str string representation of OID 183 * @return oid as array of integers or null if the oid string is 184 * invalid or null and shouldThrow is false 185 * @throws IllegalArgumentException if oid string is invalid or null and 186 * shouldThrow is true 187 */ 188 private static int[] toIntArray(String str, boolean shouldThrow) { 189 if (str == null) { 190 if (! shouldThrow) { 191 return null; 192 } 193 throw new IllegalArgumentException(); 194 } 195 196 int length = str.length(); 197 if (length == 0) { 198 if (! shouldThrow) { 199 return null; 200 } 201 throw new IllegalArgumentException("Incorrect syntax"); 202 } 203 204 int count = 1; // number of subidentifiers 205 boolean wasDot = true; // indicates whether char before was dot or not. 206 char c; // current char 207 for (int i = 0; i < length; i++) { 208 c = str.charAt(i); 209 if (c == '.') { 210 if (wasDot) { 211 if (! shouldThrow) { 212 return null; 213 } 214 throw new IllegalArgumentException("Incorrect syntax"); 215 } 216 wasDot = true; 217 count++; 218 } else if (c >= '0' && c <= '9') { 219 wasDot = false; 220 } else { 221 if (! shouldThrow) { 222 return null; 223 } 224 throw new IllegalArgumentException("Incorrect syntax"); 225 } 226 } 227 228 if (wasDot) { 229 // the last char is dot 230 if (! shouldThrow) { 231 return null; 232 } 233 throw new IllegalArgumentException("Incorrect syntax"); 234 } 235 236 if (count < 2) { 237 if (! shouldThrow) { 238 return null; 239 } 240 throw new IllegalArgumentException("Incorrect syntax"); 241 } 242 243 int[] oid = new int[count]; 244 for (int i = 0, j = 0; i < length; i++) { 245 c = str.charAt(i); 246 if (c == '.') { 247 j++; 248 } else { 249 oid[j] = oid[j] * 10 + c - 48; // '0' = 48 250 } 251 } 252 253 if (oid[0] > 2) { 254 if (! shouldThrow) { 255 return null; 256 } 257 throw new IllegalArgumentException("Incorrect syntax"); 258 } else if (oid[0] != 2 && oid[1] > 39) { 259 if (! shouldThrow) { 260 return null; 261 } 262 throw new IllegalArgumentException("Incorrect syntax"); 263 } 264 265 return oid; 266 } 267 } 268