History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/x509/IPAddressName.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/x509/IPAddressName.java+489−0
@@ -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+}