IPAddressName.java revision 11882:a199b72a5b37
1251875Speter/*
2251875Speter * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
3251875Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4251875Speter *
5251875Speter * This code is free software; you can redistribute it and/or modify it
6251875Speter * under the terms of the GNU General Public License version 2 only, as
7251875Speter * published by the Free Software Foundation.  Oracle designates this
8251875Speter * particular file as subject to the "Classpath" exception as provided
9251875Speter * by Oracle in the LICENSE file that accompanied this code.
10251875Speter *
11251875Speter * This code is distributed in the hope that it will be useful, but WITHOUT
12251875Speter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13251875Speter * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14251875Speter * version 2 for more details (a copy is included in the LICENSE file that
15251875Speter * accompanied this code).
16251875Speter *
17251875Speter * You should have received a copy of the GNU General Public License version
18251875Speter * 2 along with this work; if not, write to the Free Software Foundation,
19251875Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20251875Speter *
21251875Speter * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22251875Speter * or visit www.oracle.com if you need additional information or have any
23251875Speter * questions.
24251875Speter */
25251875Speter
26251875Speterpackage sun.security.x509;
27251875Speter
28251875Speterimport java.io.IOException;
29251875Speterimport java.lang.Integer;
30251875Speterimport java.net.InetAddress;
31251875Speterimport java.util.Arrays;
32251875Speterimport sun.misc.HexDumpEncoder;
33251875Speterimport sun.security.util.BitArray;
34251875Speterimport sun.security.util.DerOutputStream;
35251875Speterimport sun.security.util.DerValue;
36251875Speter
37251875Speter/**
38251875Speter * This class implements the IPAddressName as required by the GeneralNames
39251875Speter * ASN.1 object.  Both IPv4 and IPv6 addresses are supported using the
40251875Speter * formats specified in IETF PKIX RFC2459.
41251875Speter * <p>
42251875Speter * [RFC2459 4.2.1.7 Subject Alternative Name]
43251875Speter * When the subjectAltName extension contains a iPAddress, the address
44251875Speter * MUST be stored in the octet string in "network byte order," as
45251875Speter * specified in RFC 791. The least significant bit (LSB) of
46251875Speter * each octet is the LSB of the corresponding byte in the network
47251875Speter * address. For IP Version 4, as specified in RFC 791, the octet string
48251875Speter * MUST contain exactly four octets.  For IP Version 6, as specified in
49251875Speter * RFC 1883, the octet string MUST contain exactly sixteen octets.
50251875Speter * <p>
51251875Speter * [RFC2459 4.2.1.11 Name Constraints]
52251875Speter * The syntax of iPAddress MUST be as described in section 4.2.1.7 with
53251875Speter * the following additions specifically for Name Constraints.  For IPv4
54251875Speter * addresses, the ipAddress field of generalName MUST contain eight (8)
55251875Speter * octets, encoded in the style of RFC 1519 (CIDR) to represent an
56251875Speter * address range.[RFC 1519]  For IPv6 addresses, the ipAddress field
57251875Speter * MUST contain 32 octets similarly encoded.  For example, a name
58251875Speter * constraint for "class C" subnet 10.9.8.0 shall be represented as the
59251875Speter * octets 0A 09 08 00 FF FF FF 00, representing the CIDR notation
60251875Speter * 10.9.8.0/255.255.255.0.
61251875Speter * <p>
62251875Speter * @see GeneralName
63251875Speter * @see GeneralNameInterface
64251875Speter * @see GeneralNames
65251875Speter *
66251875Speter *
67251875Speter * @author Amit Kapoor
68251875Speter * @author Hemma Prafullchandra
69251875Speter */
70251875Speterpublic class IPAddressName implements GeneralNameInterface {
71251875Speter    private byte[] address;
72251875Speter    private boolean isIPv4;
73251875Speter    private String name;
74251875Speter
75251875Speter    /**
76251875Speter     * Create the IPAddressName object from the passed encoded Der value.
77251875Speter     *
78251875Speter     * @param derValue the encoded DER IPAddressName.
79251875Speter     * @exception IOException on error.
80251875Speter     */
81251875Speter    public IPAddressName(DerValue derValue) throws IOException {
82251875Speter        this(derValue.getOctetString());
83251875Speter    }
84251875Speter
85251875Speter    /**
86251875Speter     * Create the IPAddressName object with the specified octets.
87251875Speter     *
88251875Speter     * @param address the IP address
89251875Speter     * @throws IOException if address is not a valid IPv4 or IPv6 address
90251875Speter     */
91251875Speter    public IPAddressName(byte[] address) throws IOException {
92251875Speter        /*
93251875Speter         * A valid address must consist of 4 bytes of address and
94251875Speter         * optional 4 bytes of 4 bytes of mask, or 16 bytes of address
95251875Speter         * and optional 16 bytes of mask.
96251875Speter         */
97251875Speter        if (address.length == 4 || address.length == 8) {
98251875Speter            isIPv4 = true;
99251875Speter        } else if (address.length == 16 || address.length == 32) {
100251875Speter            isIPv4 = false;
101251875Speter        } else {
102251875Speter            throw new IOException("Invalid IPAddressName");
103251875Speter        }
104251875Speter        this.address = address;
105251875Speter    }
106251875Speter
107251875Speter    /**
108251875Speter     * Create an IPAddressName from a String.
109251875Speter     * [IETF RFC1338 Supernetting {@literal &} IETF RFC1519 Classless Inter-Domain
110251875Speter     * Routing (CIDR)] For IPv4 addresses, the forms are
111251875Speter     * "b1.b2.b3.b4" or "b1.b2.b3.b4/m1.m2.m3.m4", where b1 - b4 are decimal
112251875Speter     * byte values 0-255 and m1 - m4 are decimal mask values
113251875Speter     * 0 - 255.
114251875Speter     * <p>
115251875Speter     * [IETF RFC2373 IP Version 6 Addressing Architecture]
116251875Speter     * For IPv6 addresses, the forms are "a1:a2:...:a8" or "a1:a2:...:a8/n",
117251875Speter     * where a1-a8 are hexadecimal values representing the eight 16-bit pieces
118251875Speter     * of the address. If /n is used, n is a decimal number indicating how many
119251875Speter     * of the leftmost contiguous bits of the address comprise the prefix for
120251875Speter     * this subnet. Internally, a mask value is created using the prefix length.
121251875Speter     *
122251875Speter     * @param name String form of IPAddressName
123251875Speter     * @throws IOException if name can not be converted to a valid IPv4 or IPv6
124251875Speter     *     address
125251875Speter     */
126251875Speter    public IPAddressName(String name) throws IOException {
127251875Speter
128251875Speter        if (name == null || name.length() == 0) {
129251875Speter            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     * @param 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     *
388     * @param inputName to be checked for being constrained
389     * @return 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     * @return 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}
490