Showing the changes to java/pkg/sun/security/x509/IPAddressName.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,489 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 5 | * This code is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 only, as | ||
| 7 | * published by the Free Software Foundation. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | |||
| 26 | package sun.security.x509; | ||
| 27 | |||
| 28 | import java.io.IOException; | ||
| 29 | import java.lang.Integer; | ||
| 30 | import java.net.InetAddress; | ||
| 31 | import java.util.Arrays; | ||
| 32 | import sun.misc.HexDumpEncoder; | ||
| 33 | import sun.security.util.BitArray; | ||
| 34 | import sun.security.util.DerOutputStream; | ||
| 35 | import sun.security.util.DerValue; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * This class implements the IPAddressName as required by the GeneralNames | ||
| 39 | * ASN.1 object. Both IPv4 and IPv6 addresses are supported using the | ||
| 40 | * formats specified in IETF PKIX RFC2459. | ||
| 41 | * <p> | ||
| 42 | * [RFC2459 4.2.1.7 Subject Alternative Name] | ||
| 43 | * When the subjectAltName extension contains a iPAddress, the address | ||
| 44 | * MUST be stored in the octet string in "network byte order," as | ||
| 45 | * specified in RFC 791. The least significant bit (LSB) of | ||
| 46 | * each octet is the LSB of the corresponding byte in the network | ||
| 47 | * address. For IP Version 4, as specified in RFC 791, the octet string | ||
| 48 | * MUST contain exactly four octets. For IP Version 6, as specified in | ||
| 49 | * RFC 1883, the octet string MUST contain exactly sixteen octets. | ||
| 50 | * <p> | ||
| 51 | * [RFC2459 4.2.1.11 Name Constraints] | ||
| 52 | * The syntax of iPAddress MUST be as described in section 4.2.1.7 with | ||
| 53 | * the following additions specifically for Name Constraints. For IPv4 | ||
| 54 | * addresses, the ipAddress field of generalName MUST contain eight (8) | ||
| 55 | * octets, encoded in the style of RFC 1519 (CIDR) to represent an | ||
| 56 | * address range.[RFC 1519] For IPv6 addresses, the ipAddress field | ||
| 57 | * MUST contain 32 octets similarly encoded. For example, a name | ||
| 58 | * constraint for "class C" subnet 10.9.8.0 shall be represented as the | ||
| 59 | * octets 0A 09 08 00 FF FF FF 00, representing the CIDR notation | ||
| 60 | * 10.9.8.0/255.255.255.0. | ||
| 61 | * <p> | ||
| 62 | * @see GeneralName | ||
| 63 | * @see GeneralNameInterface | ||
| 64 | * @see GeneralNames | ||
| 65 | * | ||
| 66 | * | ||
| 67 | * @author Amit Kapoor | ||
| 68 | * @author Hemma Prafullchandra | ||
| 69 | */ | ||
| 70 | public class IPAddressName implements GeneralNameInterface { | ||
| 71 | private byte[] address; | ||
| 72 | private boolean isIPv4; | ||
| 73 | private String name; | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Create the IPAddressName object from the passed encoded Der value. | ||
| 77 | * | ||
| 78 | * @params derValue the encoded DER IPAddressName. | ||
| 79 | * @exception IOException on error. | ||
| 80 | */ | ||
| 81 | public IPAddressName(DerValue derValue) throws IOException { | ||
| 82 | this(derValue.getOctetString()); | ||
| 83 | } | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Create the IPAddressName object with the specified octets. | ||
| 87 | * | ||
| 88 | * @params address the IP address | ||
| 89 | * @throws IOException if address is not a valid IPv4 or IPv6 address | ||
| 90 | */ | ||
| 91 | public IPAddressName(byte[] address) throws IOException { | ||
| 92 | /* | ||
| 93 | * A valid address must consist of 4 bytes of address and | ||
| 94 | * optional 4 bytes of 4 bytes of mask, or 16 bytes of address | ||
| 95 | * and optional 16 bytes of mask. | ||
| 96 | */ | ||
| 97 | if (address.length == 4 || address.length == 8) { | ||
| 98 | isIPv4 = true; | ||
| 99 | } else if (address.length == 16 || address.length == 32) { | ||
| 100 | isIPv4 = false; | ||
| 101 | } else { | ||
| 102 | throw new IOException("Invalid IPAddressName"); | ||
| 103 | } | ||
| 104 | this.address = address; | ||
| 105 | } | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Create an IPAddressName from a String. | ||
| 109 | * [IETF RFC1338 Supernetting & IETF RFC1519 Classless Inter-Domain | ||
| 110 | * Routing (CIDR)] For IPv4 addresses, the forms are | ||
| 111 | * "b1.b2.b3.b4" or "b1.b2.b3.b4/m1.m2.m3.m4", where b1 - b4 are decimal | ||
| 112 | * byte values 0-255 and m1 - m4 are decimal mask values | ||
| 113 | * 0 - 255. | ||
| 114 | * <p> | ||
| 115 | * [IETF RFC2373 IP Version 6 Addressing Architecture] | ||
| 116 | * For IPv6 addresses, the forms are "a1:a2:...:a8" or "a1:a2:...:a8/n", | ||
| 117 | * where a1-a8 are hexadecimal values representing the eight 16-bit pieces | ||
| 118 | * of the address. If /n is used, n is a decimal number indicating how many | ||
| 119 | * of the leftmost contiguous bits of the address comprise the prefix for | ||
| 120 | * this subnet. Internally, a mask value is created using the prefix length. | ||
| 121 | * <p> | ||
| 122 | * @param name String form of IPAddressName | ||
| 123 | * @throws IOException if name can not be converted to a valid IPv4 or IPv6 | ||
| 124 | * address | ||
| 125 | */ | ||
| 126 | public IPAddressName(String name) throws IOException { | ||
| 127 | |||
| 128 | if (name == null || name.length() == 0) { | ||
| 129 | throw new IOException("IPAddress cannot be null or empty"); | ||
| 130 | } | ||
| 131 | if (name.charAt(name.length() - 1) == '/') { | ||
| 132 | throw new IOException("Invalid IPAddress: " + name); | ||
| 133 | } | ||
| 134 | |||
| 135 | if (name.indexOf(':') >= 0) { | ||
| 136 | // name is IPv6: uses colons as value separators | ||
| 137 | // Parse name into byte-value address components and optional | ||
| 138 | // prefix | ||
| 139 | parseIPv6(name); | ||
| 140 | isIPv4 = false; | ||
| 141 | } else if (name.indexOf('.') >= 0) { | ||
| 142 | //name is IPv4: uses dots as value separators | ||
| 143 | parseIPv4(name); | ||
| 144 | isIPv4 = true; | ||
| 145 | } else { | ||
| 146 | throw new IOException("Invalid IPAddress: " + name); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | /** | ||
| 151 | * Parse an IPv4 address. | ||
| 152 | * | ||
| 153 | * @param name IPv4 address with optional mask values | ||
| 154 | * @throws IOException on error | ||
| 155 | */ | ||
| 156 | private void parseIPv4(String name) throws IOException { | ||
| 157 | |||
| 158 | // Parse name into byte-value address components | ||
| 159 | int slashNdx = name.indexOf('/'); | ||
| 160 | if (slashNdx == -1) { | ||
| 161 | address = InetAddress.getByName(name).getAddress(); | ||
| 162 | } else { | ||
| 163 | address = new byte[8]; | ||
| 164 | |||
| 165 | // parse mask | ||
| 166 | byte[] mask = InetAddress.getByName | ||
| 167 | (name.substring(slashNdx+1)).getAddress(); | ||
| 168 | |||
| 169 | // parse base address | ||
| 170 | byte[] host = InetAddress.getByName | ||
| 171 | (name.substring(0, slashNdx)).getAddress(); | ||
| 172 | |||
| 173 | System.arraycopy(host, 0, address, 0, 4); | ||
| 174 | System.arraycopy(mask, 0, address, 4, 4); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | /** | ||
| 179 | * Parse an IPv6 address. | ||
| 180 | * | ||
| 181 | * @param name String IPv6 address with optional /<prefix length> | ||
| 182 | * If /<prefix length> is present, address[] array will | ||
| 183 | * be 32 bytes long, otherwise 16. | ||
| 184 | * @throws IOException on error | ||
| 185 | */ | ||
| 186 | private final static int MASKSIZE = 16; | ||
| 187 | private void parseIPv6(String name) throws IOException { | ||
| 188 | |||
| 189 | int slashNdx = name.indexOf('/'); | ||
| 190 | if (slashNdx == -1) { | ||
| 191 | address = InetAddress.getByName(name).getAddress(); | ||
| 192 | } else { | ||
| 193 | address = new byte[32]; | ||
| 194 | byte[] base = InetAddress.getByName | ||
| 195 | (name.substring(0, slashNdx)).getAddress(); | ||
| 196 | System.arraycopy(base, 0, address, 0, 16); | ||
| 197 | |||
| 198 | // append a mask corresponding to the num of prefix bits specified | ||
| 199 | int prefixLen = Integer.parseInt(name.substring(slashNdx+1)); | ||
| 200 | if (prefixLen > 128) | ||
| 201 | throw new IOException("IPv6Address prefix is longer than 128"); | ||
| 202 | |||
| 203 | // create new bit array initialized to zeros | ||
| 204 | BitArray bitArray = new BitArray(MASKSIZE * 8); | ||
| 205 | |||
| 206 | // set all most significant bits up to prefix length | ||
| 207 | for (int i = 0; i < prefixLen; i++) | ||
| 208 | bitArray.set(i, true); | ||
| 209 | byte[] maskArray = bitArray.toByteArray(); | ||
| 210 | |||
| 211 | // copy mask bytes into mask portion of address | ||
| 212 | for (int i = 0; i < MASKSIZE; i++) | ||
| 213 | address[MASKSIZE+i] = maskArray[i]; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | /** | ||
| 218 | * Return the type of the GeneralName. | ||
| 219 | */ | ||
| 220 | public int getType() { | ||
| 221 | return NAME_IP; | ||
| 222 | } | ||
| 223 | |||
| 224 | /** | ||
| 225 | * Encode the IPAddress name into the DerOutputStream. | ||
| 226 | * | ||
| 227 | * @params out the DER stream to encode the IPAddressName to. | ||
| 228 | * @exception IOException on encoding errors. | ||
| 229 | */ | ||
| 230 | public void encode(DerOutputStream out) throws IOException { | ||
| 231 | out.putOctetString(address); | ||
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * Return a printable string of IPaddress | ||
| 236 | */ | ||
| 237 | public String toString() { | ||
| 238 | try { | ||
| 239 | return "IPAddress: " + getName(); | ||
| 240 | } catch (IOException ioe) { | ||
| 241 | // dump out hex rep for debugging purposes | ||
| 242 | HexDumpEncoder enc = new HexDumpEncoder(); | ||
| 243 | return "IPAddress: " + enc.encodeBuffer(address); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * Return a standard String representation of IPAddress. | ||
| 249 | * See IPAddressName(String) for the formats used for IPv4 | ||
| 250 | * and IPv6 addresses. | ||
| 251 | * | ||
| 252 | * @throws IOException if the IPAddress cannot be converted to a String | ||
| 253 | */ | ||
| 254 | public String getName() throws IOException { | ||
| 255 | if (name != null) | ||
| 256 | return name; | ||
| 257 | |||
| 258 | if (isIPv4) { | ||
| 259 | //IPv4 address or subdomain | ||
| 260 | byte[] host = new byte[4]; | ||
| 261 | System.arraycopy(address, 0, host, 0, 4); | ||
| 262 | name = InetAddress.getByAddress(host).getHostAddress(); | ||
| 263 | if (address.length == 8) { | ||
| 264 | byte[] mask = new byte[4]; | ||
| 265 | System.arraycopy(address, 4, mask, 0, 4); | ||
| 266 | name = name + "/" + | ||
| 267 | InetAddress.getByAddress(mask).getHostAddress(); | ||
| 268 | } | ||
| 269 | } else { | ||
| 270 | //IPv6 address or subdomain | ||
| 271 | byte[] host = new byte[16]; | ||
| 272 | System.arraycopy(address, 0, host, 0, 16); | ||
| 273 | name = InetAddress.getByAddress(host).getHostAddress(); | ||
| 274 | if (address.length == 32) { | ||
| 275 | // IPv6 subdomain: display prefix length | ||
| 276 | |||
| 277 | // copy subdomain into new array and convert to BitArray | ||
| 278 | byte[] maskBytes = new byte[16]; | ||
| 279 | for (int i=16; i < 32; i++) | ||
| 280 | maskBytes[i-16] = address[i]; | ||
| 281 | BitArray ba = new BitArray(16*8, maskBytes); | ||
| 282 | // Find first zero bit | ||
| 283 | int i=0; | ||
| 284 | for (; i < 16*8; i++) { | ||
| 285 | if (!ba.get(i)) | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | name = name + "/" + i; | ||
| 289 | // Verify remaining bits 0 | ||
| 290 | for (; i < 16*8; i++) { | ||
| 291 | if (ba.get(i)) { | ||
| 292 | throw new IOException("Invalid IPv6 subdomain - set " + | ||
| 293 | "bit " + i + " not contiguous"); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | } | ||
| 297 | } | ||
| 298 | return name; | ||
| 299 | } | ||
| 300 | |||
| 301 | /** | ||
| 302 | * Returns this IPAddress name as a byte array. | ||
| 303 | */ | ||
| 304 | public byte[] getBytes() { | ||
| 305 | return address.clone(); | ||
| 306 | } | ||
| 307 | |||
| 308 | /** | ||
| 309 | * Compares this name with another, for equality. | ||
| 310 | * | ||
| 311 | * @return true iff the names are identical. | ||
| 312 | */ | ||
| 313 | public boolean equals(Object obj) { | ||
| 314 | if (this == obj) | ||
| 315 | return true; | ||
| 316 | |||
| 317 | if (!(obj instanceof IPAddressName)) | ||
| 318 | return false; | ||
| 319 | |||
| 320 | byte[] other = ((IPAddressName)obj).getBytes(); | ||
| 321 | |||
| 322 | if (other.length != address.length) | ||
| 323 | return false; | ||
| 324 | |||
| 325 | if (address.length == 8 || address.length == 32) { | ||
| 326 | // Two subnet addresses | ||
| 327 | // Mask each and compare masked values | ||
| 328 | int maskLen = address.length/2; | ||
| 329 | byte[] maskedThis = new byte[maskLen]; | ||
| 330 | byte[] maskedOther = new byte[maskLen]; | ||
| 331 | for (int i=0; i < maskLen; i++) { | ||
| 332 | maskedThis[i] = (byte)(address[i] & address[i+maskLen]); | ||
| 333 | maskedOther[i] = (byte)(other[i] & other[i+maskLen]); | ||
| 334 | if (maskedThis[i] != maskedOther[i]) { | ||
| 335 | return false; | ||
| 336 | } | ||
| 337 | } | ||
| 338 | // Now compare masks | ||
| 339 | for (int i=maskLen; i < address.length; i++) | ||
| 340 | if (address[i] != other[i]) | ||
| 341 | return false; | ||
| 342 | return true; | ||
| 343 | } else { | ||
| 344 | // Two IPv4 host addresses or two IPv6 host addresses | ||
| 345 | // Compare bytes | ||
| 346 | return Arrays.equals(other, address); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | /** | ||
| 351 | * Returns the hash code value for this object. | ||
| 352 | * | ||
| 353 | * @return a hash code value for this object. | ||
| 354 | */ | ||
| 355 | public int hashCode() { | ||
| 356 | int retval = 0; | ||
| 357 | |||
| 358 | for (int i=0; i<address.length; i++) | ||
| 359 | retval += address[i] * i; | ||
| 360 | |||
| 361 | return retval; | ||
| 362 | } | ||
| 363 | |||
| 364 | /** | ||
| 365 | * Return type of constraint inputName places on this name:<ul> | ||
| 366 | * <li>NAME_DIFF_TYPE = -1: input name is different type from name | ||
| 367 | * (i.e. does not constrain). | ||
| 368 | * <li>NAME_MATCH = 0: input name matches name. | ||
| 369 | * <li>NAME_NARROWS = 1: input name narrows name (is lower in the naming | ||
| 370 | * subtree) | ||
| 371 | * <li>NAME_WIDENS = 2: input name widens name (is higher in the naming | ||
| 372 | * subtree) | ||
| 373 | * <li>NAME_SAME_TYPE = 3: input name does not match or narrow name, but | ||
| 374 | * is same type. | ||
| 375 | * </ul>. These results are used in checking NameConstraints during | ||
| 376 | * certification path verification. | ||
| 377 | * <p> | ||
| 378 | * [RFC2459] The syntax of iPAddress MUST be as described in section | ||
| 379 | * 4.2.1.7 with the following additions specifically for Name Constraints. | ||
| 380 | * For IPv4 addresses, the ipAddress field of generalName MUST contain | ||
| 381 | * eight (8) octets, encoded in the style of RFC 1519 (CIDR) to represent an | ||
| 382 | * address range.[RFC 1519] For IPv6 addresses, the ipAddress field | ||
| 383 | * MUST contain 32 octets similarly encoded. For example, a name | ||
| 384 | * constraint for "class C" subnet 10.9.8.0 shall be represented as the | ||
| 385 | * octets 0A 09 08 00 FF FF FF 00, representing the CIDR notation | ||
| 386 | * 10.9.8.0/255.255.255.0. | ||
| 387 | * <p> | ||
| 388 | * @param inputName to be checked for being constrained | ||
| 389 | * @returns constraint type above | ||
| 390 | * @throws UnsupportedOperationException if name is not exact match, but | ||
| 391 | * narrowing and widening are not supported for this name type. | ||
| 392 | */ | ||
| 393 | public int constrains(GeneralNameInterface inputName) | ||
| 394 | throws UnsupportedOperationException { | ||
| 395 | int constraintType; | ||
| 396 | if (inputName == null) | ||
| 397 | constraintType = NAME_DIFF_TYPE; | ||
| 398 | else if (inputName.getType() != NAME_IP) | ||
| 399 | constraintType = NAME_DIFF_TYPE; | ||
| 400 | else if (((IPAddressName)inputName).equals(this)) | ||
| 401 | constraintType = NAME_MATCH; | ||
| 402 | else { | ||
| 403 | byte[] otherAddress = ((IPAddressName)inputName).getBytes(); | ||
| 404 | if (otherAddress.length == 4 && address.length == 4) | ||
| 405 | // Two host addresses | ||
| 406 | constraintType = NAME_SAME_TYPE; | ||
| 407 | else if ((otherAddress.length == 8 && address.length == 8) || | ||
| 408 | (otherAddress.length == 32 && address.length == 32)) { | ||
| 409 | // Two subnet addresses | ||
| 410 | // See if one address fully encloses the other address | ||
| 411 | boolean otherSubsetOfThis = true; | ||
| 412 | boolean thisSubsetOfOther = true; | ||
| 413 | boolean thisEmpty = false; | ||
| 414 | boolean otherEmpty = false; | ||
| 415 | int maskOffset = address.length/2; | ||
| 416 | for (int i=0; i < maskOffset; i++) { | ||
| 417 | if ((byte)(address[i] & address[i+maskOffset]) != address[i]) | ||
| 418 | thisEmpty=true; | ||
| 419 | if ((byte)(otherAddress[i] & otherAddress[i+maskOffset]) != otherAddress[i]) | ||
| 420 | otherEmpty=true; | ||
| 421 | if (!(((byte)(address[i+maskOffset] & otherAddress[i+maskOffset]) == address[i+maskOffset]) && | ||
| 422 | ((byte)(address[i] & address[i+maskOffset]) == (byte)(otherAddress[i] & address[i+maskOffset])))) { | ||
| 423 | otherSubsetOfThis = false; | ||
| 424 | } | ||
| 425 | if (!(((byte)(otherAddress[i+maskOffset] & address[i+maskOffset]) == otherAddress[i+maskOffset]) && | ||
| 426 | ((byte)(otherAddress[i] & otherAddress[i+maskOffset]) == (byte)(address[i] & otherAddress[i+maskOffset])))) { | ||
| 427 | thisSubsetOfOther = false; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | if (thisEmpty || otherEmpty) { | ||
| 431 | if (thisEmpty && otherEmpty) | ||
| 432 | constraintType = NAME_MATCH; | ||
| 433 | else if (thisEmpty) | ||
| 434 | constraintType = NAME_WIDENS; | ||
| 435 | else | ||
| 436 | constraintType = NAME_NARROWS; | ||
| 437 | } else if (otherSubsetOfThis) | ||
| 438 | constraintType = NAME_NARROWS; | ||
| 439 | else if (thisSubsetOfOther) | ||
| 440 | constraintType = NAME_WIDENS; | ||
| 441 | else | ||
| 442 | constraintType = NAME_SAME_TYPE; | ||
| 443 | } else if (otherAddress.length == 8 || otherAddress.length == 32) { | ||
| 444 | //Other is a subnet, this is a host address | ||
| 445 | int i = 0; | ||
| 446 | int maskOffset = otherAddress.length/2; | ||
| 447 | for (; i < maskOffset; i++) { | ||
| 448 | // Mask this address by other address mask and compare to other address | ||
| 449 | // If all match, then this address is in other address subnet | ||
| 450 | if ((address[i] & otherAddress[i+maskOffset]) != otherAddress[i]) | ||
| 451 | break; | ||
| 452 | } | ||
| 453 | if (i == maskOffset) | ||
| 454 | constraintType = NAME_WIDENS; | ||
| 455 | else | ||
| 456 | constraintType = NAME_SAME_TYPE; | ||
| 457 | } else if (address.length == 8 || address.length == 32) { | ||
| 458 | //This is a subnet, other is a host address | ||
| 459 | int i = 0; | ||
| 460 | int maskOffset = address.length/2; | ||
| 461 | for (; i < maskOffset; i++) { | ||
| 462 | // Mask other address by this address mask and compare to this address | ||
| 463 | if ((otherAddress[i] & address[i+maskOffset]) != address[i]) | ||
| 464 | break; | ||
| 465 | } | ||
| 466 | if (i == maskOffset) | ||
| 467 | constraintType = NAME_NARROWS; | ||
| 468 | else | ||
| 469 | constraintType = NAME_SAME_TYPE; | ||
| 470 | } else { | ||
| 471 | constraintType = NAME_SAME_TYPE; | ||
| 472 | } | ||
| 473 | } | ||
| 474 | return constraintType; | ||
| 475 | } | ||
| 476 | |||
| 477 | /** | ||
| 478 | * Return subtree depth of this name for purposes of determining | ||
| 479 | * NameConstraints minimum and maximum bounds and for calculating | ||
| 480 | * path lengths in name subtrees. | ||
| 481 | * | ||
| 482 | * @returns distance of name from root | ||
| 483 | * @throws UnsupportedOperationException if not supported for this name type | ||
| 484 | */ | ||
| 485 | public int subtreeDepth() throws UnsupportedOperationException { | ||
| 486 | throw new UnsupportedOperationException | ||
| 487 | ("subtreeDepth() not defined for IPAddressName"); | ||
| 488 | } | ||
| 489 | } | ||